Merge "Make ModifierShortcutManager multiuser aware." into main
diff --git a/services/core/java/com/android/server/policy/ModifierShortcutManager.java b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
index 9b64488..40b2ff9 100644
--- a/services/core/java/com/android/server/policy/ModifierShortcutManager.java
+++ b/services/core/java/com/android/server/policy/ModifierShortcutManager.java
@@ -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 @@
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 @@
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 @@
* 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 @@
// First try the exact keycode (with modifiers).
int shortcutChar = kcm.get(keyCode, metaState);
- if (shortcutChar != 0) {
+ if (shortcutChar == 0) {
+ return null;
+ }
+ shortcutIntent = shortcutMap.get(shortcutChar);
+
+ if (shortcutIntent == null) {
+ // Next try the primary character on that key.
+ shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
+ if (shortcutChar == 0) {
+ return null;
+ }
shortcutIntent = shortcutMap.get(shortcutChar);
}
- // Next try the primary character on that key.
if (shortcutIntent == null) {
- shortcutChar = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
- if (shortcutChar != 0) {
- shortcutIntent = shortcutMap.get(shortcutChar);
-
- if (shortcutIntent == null) {
- // Check for role based shortcut
- String role = isShiftOn ? mShiftRoleShortcuts.get(shortcutChar)
- : mRoleShortcuts.get(shortcutChar);
- if (role != null) {
- shortcutIntent = getRoleLaunchIntent(role);
- }
- }
+ // 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 @@
+ " className=" + className + " shortcutChar=" + shortcutChar);
continue;
}
- intent = resolveComponentNameIntent(packageName, className);
+ 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"
@@ -288,19 +331,37 @@
}
@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
- | PackageManager.MATCH_UNINSTALLED_PACKAGES;
+ 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 @@
if (intent != null) {
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
- mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+ 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 @@
if (shortcutIntent != null) {
shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
- mContext.startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
+ 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 @@
}
}
+ 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 @@
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 @@
}
return context.getString(resid);
};
-
}
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index df97313..7534bfe 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -76,6 +76,7 @@
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 @@
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 @@
if (statusBar != null) {
statusBar.setCurrentUser(newUserId);
}
+ if (modifierShortcutManagerMultiuser()) {
+ mModifierShortcutManager.setCurrentUser(UserHandle.of(newUserId));
+ }
}
@Override
diff --git a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
index 5533ff9..50041d0 100644
--- a/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/ModifierShortcutManagerTests.java
@@ -39,6 +39,7 @@
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 @@
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 @@
.canonicalToCurrentPackageNames(aryEq(new String[] { "com.test2" }));
- mModifierShortcutManager = new ModifierShortcutManager(mContext, mHandler);
+ mModifierShortcutManager = new ModifierShortcutManager(
+ mContext, mHandler, UserHandle.SYSTEM);
}
@Test