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

Commit 864c1595 authored by Ben Murdoch's avatar Ben Murdoch Committed by Android (Google) Code Review
Browse files

Merge "Update bookmarks.xml shortcuts to specify a role to invoke." into main

parents 8b5560c9 59ad767c
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -33,7 +33,7 @@
-->
<bookmarks>
    <bookmark
        category="android.intent.category.APP_BROWSER"
        role="android.app.role.BROWSER"
        shortcut="b" />
    <bookmark
        category="android.intent.category.APP_CONTACTS"
@@ -51,7 +51,7 @@
        category="android.intent.category.APP_MUSIC"
        shortcut="p" />
    <bookmark
        category="android.intent.category.APP_MESSAGING"
        role="android.app.role.SMS"
        shortcut="s" />
    <bookmark
        category="android.intent.category.APP_CALCULATOR"
+3 −3
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@
       'c': Contacts
       'e': Email
       'g': GMail
       'l': Calendar
       'k': Calendar
       'm': Maps
       'p': Music
       's': SMS
@@ -33,7 +33,7 @@
-->
<bookmarks>
    <bookmark
        category="android.intent.category.APP_BROWSER"
        role="android.app.role.BROWSER"
        shortcut="b" />
    <bookmark
        category="android.intent.category.APP_CONTACTS"
@@ -51,7 +51,7 @@
        category="android.intent.category.APP_MUSIC"
        shortcut="p" />
    <bookmark
        category="android.intent.category.APP_MESSAGING"
        role="android.app.role.SMS"
        shortcut="s" />
    <bookmark
        category="android.intent.category.APP_CALCULATOR"
+26 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.role.RoleManager;
import android.content.Intent;
import android.hardware.input.KeyboardLayout;
import android.icu.util.ULocale;
@@ -37,6 +38,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.KeyboardConfiguredProto.KeyboardLayoutConfig;
import com.android.internal.os.KeyboardConfiguredProto.RepeatedKeyboardLayoutConfig;
import com.android.internal.util.FrameworkStatsLog;
import com.android.server.policy.ModifierShortcutManager;

import java.lang.annotation.Retention;
import java.util.ArrayList;
@@ -318,6 +320,13 @@ public final class KeyboardMetricsCollector {
                }
            }

            // The shortcut may be targeting a system role rather than using an intent selector,
            // so check for that.
            String role = intent.getStringExtra(ModifierShortcutManager.EXTRA_ROLE);
            if (!TextUtils.isEmpty(role)) {
                return getLogEventFromRole(role);
            }

            Set<String> intentCategories = intent.getCategories();
            if (intentCategories == null || intentCategories.isEmpty()
                    || !intentCategories.contains(Intent.CATEGORY_LAUNCHER)) {
@@ -363,6 +372,23 @@ public final class KeyboardMetricsCollector {
                    return null;
            }
        }

        /**
         * Find KeyboardLogEvent corresponding to the provide system role name.
         * Returns {@code null} if no matching event found.
         */
        @Nullable
        private static KeyboardLogEvent getLogEventFromRole(String role) {
            if (RoleManager.ROLE_BROWSER.equals(role)) {
                return LAUNCH_DEFAULT_BROWSER;
            } else if (RoleManager.ROLE_SMS.equals(role)) {
                return LAUNCH_DEFAULT_MESSAGING;
            } else {
                Log.w(TAG, "Keyboard shortcut to launch "
                        + role + " not supported for logging");
                return null;
            }
        }
    }

    /**
+92 −14
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.policy;

import android.annotation.SuppressLint;
import android.app.role.RoleManager;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -45,6 +46,8 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * Manages quick launch shortcuts by:
@@ -52,8 +55,8 @@ import java.io.IOException;
 * <li> Returning a shortcut-matching intent to clients
 * <li> Returning particular kind of application intent by special key.
 */
class ModifierShortcutManager {
    private static final String TAG = "WindowManager";
public class ModifierShortcutManager {
    private static final String TAG = "ModifierShortcutManager";

    private static final String TAG_BOOKMARKS = "bookmarks";
    private static final String TAG_BOOKMARK = "bookmark";
@@ -63,9 +66,13 @@ class ModifierShortcutManager {
    private static final String ATTRIBUTE_SHORTCUT = "shortcut";
    private static final String ATTRIBUTE_CATEGORY = "category";
    private static final String ATTRIBUTE_SHIFT = "shift";
    private static final String ATTRIBUTE_ROLE = "role";

    private final SparseArray<Intent> mIntentShortcuts = new SparseArray<>();
    private final SparseArray<Intent> mShiftShortcuts = new SparseArray<>();
    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 LongSparseArray<IShortcutService> mShortcutKeyServices = new LongSparseArray<>();

@@ -76,10 +83,12 @@ class ModifierShortcutManager {
     * usage page.  We don't support quite that many yet...
     */
    static SparseArray<String> sApplicationLaunchKeyCategories;
    static SparseArray<String> sApplicationLaunchKeyRoles;
    static {
        sApplicationLaunchKeyRoles = new SparseArray<String>();
        sApplicationLaunchKeyCategories = new SparseArray<String>();
        sApplicationLaunchKeyCategories.append(
                KeyEvent.KEYCODE_EXPLORER, Intent.CATEGORY_APP_BROWSER);
        sApplicationLaunchKeyRoles.append(
                KeyEvent.KEYCODE_EXPLORER, RoleManager.ROLE_BROWSER);
        sApplicationLaunchKeyCategories.append(
                KeyEvent.KEYCODE_ENVELOPE, Intent.CATEGORY_APP_EMAIL);
        sApplicationLaunchKeyCategories.append(
@@ -92,14 +101,25 @@ class ModifierShortcutManager {
                KeyEvent.KEYCODE_CALCULATOR, Intent.CATEGORY_APP_CALCULATOR);
    }

    public static final String EXTRA_ROLE =
            "com.android.server.policy.ModifierShortcutManager.EXTRA_ROLE";

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

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

@@ -141,14 +161,42 @@ class ModifierShortcutManager {
            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);
                    }
                }
            }
        }

        return shortcutIntent;
    }

    private Intent getRoleLaunchIntent(String role) {
        Intent intent = mRoleIntents.get(role);
        if (intent == null) {
            if (mRoleManager.isRoleAvailable(role)) {
                String rolePackage = mRoleManager.getDefaultApplication(role);
                if (rolePackage != null) {
                    intent = mPackageManager.getLaunchIntentForPackage(rolePackage);
                    intent.putExtra(EXTRA_ROLE, role);
                    mRoleIntents.put(role, intent);
                } else {
                    Log.w(TAG, "No default application for role " + role);
                }
            } else {
                Log.w(TAG, "Role " + role + " is not available.");
            }
        }
        return intent;
    }

    private void loadShortcuts() {
        PackageManager packageManager = mContext.getPackageManager();

        try {
            XmlResourceParser parser = mContext.getResources().getXml(
                    com.android.internal.R.xml.bookmarks);
@@ -170,29 +218,37 @@ class ModifierShortcutManager {
                String shortcutName = parser.getAttributeValue(null, ATTRIBUTE_SHORTCUT);
                String categoryName = parser.getAttributeValue(null, ATTRIBUTE_CATEGORY);
                String shiftName = parser.getAttributeValue(null, ATTRIBUTE_SHIFT);
                String roleName = parser.getAttributeValue(null, ATTRIBUTE_ROLE);

                if (TextUtils.isEmpty(shortcutName)) {
                    Log.w(TAG, "Unable to get shortcut for: " + packageName + "/" + className);
                    Log.w(TAG, "Shortcut required for bookmark with category=" + categoryName
                            + " packageName=" + packageName + " className=" + className
                            + " role=" + roleName + "shiftName=" + shiftName);
                    continue;
                }

                final int shortcutChar = shortcutName.charAt(0);
                final boolean isShiftShortcut = (shiftName != null && shiftName.equals("true"));

                final Intent intent;
                if (packageName != null && className != null) {
                    if (roleName != null || categoryName != null) {
                        Log.w(TAG, "Cannot specify role or category when package and class"
                                + " are present for bookmark packageName=" + packageName
                                + " className=" + className + " shortcutChar=" + shortcutChar);
                        continue;
                    }
                    ComponentName componentName = new ComponentName(packageName, className);
                    try {
                        packageManager.getActivityInfo(componentName,
                        mPackageManager.getActivityInfo(componentName,
                                PackageManager.MATCH_DIRECT_BOOT_AWARE
                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                                        | PackageManager.MATCH_UNINSTALLED_PACKAGES);
                    } catch (PackageManager.NameNotFoundException e) {
                        String[] packages = packageManager.canonicalToCurrentPackageNames(
                        String[] packages = mPackageManager.canonicalToCurrentPackageNames(
                                new String[] { packageName });
                        componentName = new ComponentName(packages[0], className);
                        try {
                            packageManager.getActivityInfo(componentName,
                            mPackageManager.getActivityInfo(componentName,
                                    PackageManager.MATCH_DIRECT_BOOT_AWARE
                                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE
                                            | PackageManager.MATCH_UNINSTALLED_PACKAGES);
@@ -207,10 +263,25 @@ class ModifierShortcutManager {
                    intent.addCategory(Intent.CATEGORY_LAUNCHER);
                    intent.setComponent(componentName);
                } else if (categoryName != null) {
                    if (roleName != null) {
                        Log.w(TAG, "Cannot specify role bookmark when category is present for"
                                + " bookmark shortcutChar=" + shortcutChar
                                + " category= " + categoryName);
                        continue;
                    }
                    intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, categoryName);
                } else if (roleName != null) {
                    // We can't resolve the role at the time of this file being parsed as the
                    // device hasn't finished booting, so we will look it up lazily.
                    if (isShiftShortcut) {
                        mShiftRoleShortcuts.put(shortcutChar, roleName);
                    } else {
                        mRoleShortcuts.put(shortcutChar, roleName);
                    }
                    continue;
                } else {
                    Log.w(TAG, "Unable to add bookmark for shortcut " + shortcutName
                            + ": missing package/class or category attributes");
                            + ": missing package/class, category or role attributes");
                    continue;
                }

@@ -298,10 +369,17 @@ class ModifierShortcutManager {
            // Invoke shortcuts using Meta.
            metaState &= ~KeyEvent.META_META_MASK;
        } else {
            Intent intent = null;
            // Handle application launch keys.
            String role = sApplicationLaunchKeyRoles.get(keyCode);
            String category = sApplicationLaunchKeyCategories.get(keyCode);
            if (category != null) {
                Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
            if (role != null) {
                intent = getRoleLaunchIntent(role);
            } else if (category != null) {
                intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, category);
            }

            if (intent != null) {
                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                try {
                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
@@ -309,7 +387,7 @@ class ModifierShortcutManager {
                    Slog.w(TAG, "Dropping application launch key because "
                            + "the activity to which it is registered was not found: "
                            + "keyCode=" + KeyEvent.keyCodeToString(keyCode) + ","
                            + " category=" + category);
                            + " category=" + category + " role=" + role);
                }
                logKeyboardShortcut(keyEvent, KeyboardLogEvent.getLogEventFromIntent(intent));
                return true;
+2 −0
Original line number Diff line number Diff line
@@ -49,6 +49,8 @@
    <uses-permission android:name="android.permission.MANAGE_MEDIA_PROJECTION"/>
    <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
    <uses-permission android:name="android.permission.MONITOR_INPUT"/>
    <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"/>
    <uses-permission android:name="android.permission.MANAGE_DEFAULT_APPLICATIONS"/>

    <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
    <application android:debuggable="true"
Loading