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

Commit 082d0c47 authored by Mehdi Alizadeh's avatar Mehdi Alizadeh Committed by Android (Google) Code Review
Browse files

Merge "Adds unit tests for ShortcutChangeCallback APIs" into rvc-dev

parents 009c800f d0a7a90b
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -507,7 +507,8 @@ public class LauncherApps {
        /**
         * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
         * register this callback, have been added or updated.
         * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
         * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery,
         * Executor)
         *
         * <p>Only the applications that are allowed to access the shortcut information,
         * as defined in {@link #hasShortcutHostPermission()}, will receive it.
@@ -525,7 +526,8 @@ public class LauncherApps {
        /**
         * Indicates that one or more shortcuts, that match the {@link ShortcutQuery} used to
         * register this callback, have been removed.
         * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery)
         * @see LauncherApps#registerShortcutChangeCallback(ShortcutChangeCallback, ShortcutQuery,
         * Executor)
         *
         * <p>Only the applications that are allowed to access the shortcut information,
         * as defined in {@link #hasShortcutHostPermission()}, will receive it.
+29 −53
Original line number Diff line number Diff line
@@ -746,9 +746,8 @@ public class LauncherAppsService extends SystemService {
            }

            UserHandle user = UserHandle.of(injectCallingUserId());
            if (mContext.checkCallingOrSelfPermission(
                    android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
                    == PackageManager.PERMISSION_GRANTED) {
            if (injectHasInteractAcrossUsersFullPermission(injectBinderCallingPid(),
                    injectBinderCallingUid())) {
                user = null;
            }

@@ -1053,29 +1052,6 @@ public class LauncherAppsService extends SystemService {
        }

        public static class ShortcutChangeHandler implements LauncherApps.ShortcutChangeCallback {

            static class QueryInfo {
                final long mChangedSince;
                final String mPackage;
                final List<String> mShortcutIds;
                final List<LocusId> mLocusIds;
                final ComponentName mActivity;
                final int mQueryFlags;
                final UserHandle mCallbackUser;

                QueryInfo(long changedSince, String packageName, List<String> shortcutIds,
                        List<LocusId> locusIds, ComponentName activity, int flags,
                        UserHandle callbackUser) {
                    mChangedSince = changedSince;
                    mPackage = packageName;
                    mShortcutIds = shortcutIds;
                    mLocusIds = locusIds;
                    mActivity = activity;
                    mQueryFlags = flags;
                    mCallbackUser = callbackUser;
                }
            }

            private final UserManagerInternal mUserManagerInternal;

            ShortcutChangeHandler(UserManagerInternal userManager) {
@@ -1088,9 +1064,7 @@ public class LauncherAppsService extends SystemService {
            public synchronized void addShortcutChangeCallback(IShortcutChangeCallback callback,
                    ShortcutQueryWrapper query, UserHandle user) {
                mCallbacks.unregister(callback);
                mCallbacks.register(callback, new QueryInfo(query.getChangedSince(),
                        query.getPackage(), query.getShortcutIds(), query.getLocusIds(),
                        query.getActivity(), query.getQueryFlags(), user));
                mCallbacks.register(callback, new Pair<>(query, user));
            }

            public synchronized void removeShortcutChangeCallback(
@@ -1116,16 +1090,19 @@ public class LauncherAppsService extends SystemService {

                for (int i = 0; i < count; i++) {
                    final IShortcutChangeCallback callback = mCallbacks.getBroadcastItem(i);
                    final QueryInfo query = (QueryInfo) mCallbacks.getBroadcastCookie(i);
                    final Pair<ShortcutQueryWrapper, UserHandle> cookie =
                            (Pair<ShortcutQueryWrapper, UserHandle>)
                                    mCallbacks.getBroadcastCookie(i);

                    if (query.mCallbackUser != null && !hasUserAccess(query.mCallbackUser, user)) {
                    final UserHandle callbackUser = cookie.second;
                    if (callbackUser != null && !hasUserAccess(callbackUser, user)) {
                        // Callback owner does not have access to the shortcuts' user.
                        continue;
                    }

                    // Filter the list by query, if any matches exists, send via callback.
                    List<ShortcutInfo> matchedList =
                            filterShortcutsByQuery(packageName, shortcuts, query);
                    List<ShortcutInfo> matchedList = filterShortcutsByQuery(packageName, shortcuts,
                            cookie.first, shortcutsRemoved);
                    if (!CollectionUtils.isEmpty(matchedList)) {
                        try {
                            if (shortcutsRemoved) {
@@ -1143,21 +1120,25 @@ public class LauncherAppsService extends SystemService {
            }

            public static List<ShortcutInfo> filterShortcutsByQuery(String packageName,
                    List<ShortcutInfo> shortcuts, QueryInfo query) {
                if (query.mPackage != null && query.mPackage != packageName) {
                    List<ShortcutInfo> shortcuts, ShortcutQueryWrapper query,
                    boolean shortcutsRemoved) {
                final long changedSince = query.getChangedSince();
                final String queryPackage = query.getPackage();
                final List<String> shortcutIds = query.getShortcutIds();
                final List<LocusId> locusIds = query.getLocusIds();
                final ComponentName activity = query.getActivity();
                final int flags = query.getQueryFlags();

                if (queryPackage != null && !queryPackage.equals(packageName)) {
                    return null;
                }

                List<ShortcutInfo> matches = new ArrayList<>();

                final boolean matchDynamic =
                        (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0;
                final boolean matchPinned =
                        (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
                final boolean matchManifest =
                        (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
                final boolean matchCached =
                        (query.mQueryFlags & ShortcutQuery.FLAG_MATCH_CACHED) != 0;
                final boolean matchDynamic = (flags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0;
                final boolean matchPinned = (flags & ShortcutQuery.FLAG_MATCH_PINNED) != 0;
                final boolean matchManifest = (flags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0;
                final boolean matchCached = (flags & ShortcutQuery.FLAG_MATCH_CACHED) != 0;
                final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0)
                        | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0)
                        | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0)
@@ -1166,24 +1147,19 @@ public class LauncherAppsService extends SystemService {
                for (int i = 0; i < shortcuts.size(); i++) {
                    final ShortcutInfo si = shortcuts.get(i);

                    if (query.mActivity != null && !query.mActivity.equals(si.getActivity())) {
                    if (activity != null && !activity.equals(si.getActivity())) {
                        continue;
                    }

                    if (query.mChangedSince != 0
                            && query.mChangedSince > si.getLastChangedTimestamp()) {
                    if (changedSince != 0 && changedSince > si.getLastChangedTimestamp()) {
                        continue;
                    }

                    if (query.mShortcutIds != null && !query.mShortcutIds.contains(si.getId())) {
                    if (shortcutIds != null && !shortcutIds.contains(si.getId())) {
                        continue;
                    }

                    if (query.mLocusIds != null && !query.mLocusIds.contains(si.getLocusId())) {
                    if (locusIds != null && !locusIds.contains(si.getLocusId())) {
                        continue;
                    }

                    if ((shortcutFlags & si.getFlags()) != 0) {
                    if (shortcutsRemoved || (shortcutFlags & si.getFlags()) != 0) {
                        matches.add(si);
                    }
                }
+63 −37
Original line number Diff line number Diff line
@@ -256,7 +256,7 @@ class ShortcutPackage extends ShortcutPackageItem {
        if (shortcut != null) {
            mShortcutUser.mService.removeIconLocked(shortcut);
            shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED
                    | ShortcutInfo.FLAG_MANIFEST);
                    | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED);
        }
        return shortcut;
    }
@@ -281,8 +281,10 @@ class ShortcutPackage extends ShortcutPackageItem {
     * invisible.
     *
     * It checks the max number of dynamic shortcuts.
     *
     * @return True if it replaced an existing shortcut, False otherwise.
     */
    public void addOrReplaceDynamicShortcut(@NonNull ShortcutInfo newShortcut) {
    public boolean addOrReplaceDynamicShortcut(@NonNull ShortcutInfo newShortcut) {

        Preconditions.checkArgument(newShortcut.isEnabled(),
                "add/setDynamicShortcuts() cannot publish disabled shortcuts");
@@ -291,38 +293,59 @@ class ShortcutPackage extends ShortcutPackageItem {

        final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());

        final boolean replaced;

        final boolean wasPinned;
        final boolean wasCached;

        if (oldShortcut == null) {
            replaced = false;
            wasPinned = false;
            wasCached = false;
        } else {
            // It's an update case.
            // Make sure the target is updatable. (i.e. should be mutable.)
            oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false);
            replaced = true;

            wasPinned = oldShortcut.isPinned();
            wasCached = oldShortcut.isCached();
        }

        // If it was originally pinned, the new one should be pinned too.
        if (wasPinned) {
            newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
        }
        if (wasCached) {
            newShortcut.addFlags(ShortcutInfo.FLAG_CACHED);
        }

        forceReplaceShortcutInner(newShortcut);
        return replaced;
    }

    /**
     * Push a shortcut. If the max number of dynamic shortcuts is already reached, remove the
     * shortcut with the lowest rank before adding the new shortcut.
     *
     * Any shortcut that gets altered (removed or changed) as a result of this push operation will
     * be included and returned in changedShortcuts.
     *
     * @return True if a shortcut had to be removed to complete this operation, False otherwise.
     */
    public boolean pushDynamicShortcut(@NonNull ShortcutInfo newShortcut) {
    public boolean pushDynamicShortcut(@NonNull ShortcutInfo newShortcut,
            @NonNull List<ShortcutInfo> changedShortcuts) {
        Preconditions.checkArgument(newShortcut.isEnabled(),
                "pushDynamicShortcuts() cannot publish disabled shortcuts");

        newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);

        changedShortcuts.clear();
        final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
        boolean wasPinned = false;
        boolean wasCached = false;

        boolean deleted = false;

        if (oldShortcut == null) {
            final ShortcutService service = mShortcutUser.mService;
@@ -343,10 +366,11 @@ class ShortcutPackage extends ShortcutPackageItem {
                    // All shortcuts are manifest shortcuts and cannot be removed.
                    Slog.e(TAG, "Failed to remove manifest shortcut while pushing dynamic shortcut "
                            + newShortcut.getId());
                    return false;
                    return true;  // poppedShortcuts is empty which indicates a failure.
                }

                deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true);
                changedShortcuts.add(shortcut);
                deleted = deleteDynamicWithId(shortcut.getId(), /*ignoreInvisible=*/ true) != null;
            }
        } else {
            // It's an update case.
@@ -354,15 +378,19 @@ class ShortcutPackage extends ShortcutPackageItem {
            oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false);

            wasPinned = oldShortcut.isPinned();
            wasCached = oldShortcut.isCached();
        }

        // If it was originally pinned, the new one should be pinned too.
        // If it was originally pinned or cached, the new one should be pinned or cached too.
        if (wasPinned) {
            newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
        }
        if (wasCached) {
            newShortcut.addFlags(ShortcutInfo.FLAG_CACHED);
        }

        forceReplaceShortcutInner(newShortcut);
        return true;
        return deleted;
    }

    /**
@@ -371,8 +399,7 @@ class ShortcutPackage extends ShortcutPackageItem {
     * @return List of removed shortcuts.
     */
    private List<ShortcutInfo> removeOrphans() {
        ArrayList<String> removeList = null; // Lazily initialize.
        List<ShortcutInfo> removedShortcuts = null;
        List<ShortcutInfo> removeList = null;

        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
            final ShortcutInfo si = mShortcuts.valueAt(i);
@@ -381,18 +408,16 @@ class ShortcutPackage extends ShortcutPackageItem {

            if (removeList == null) {
                removeList = new ArrayList<>();
                removedShortcuts = new ArrayList<>();
            }
            removeList.add(si.getId());
            removedShortcuts.add(si);
            removeList.add(si);
        }
        if (removeList != null) {
            for (int i = removeList.size() - 1; i >= 0; i--) {
                forceDeleteShortcutInner(removeList.get(i));
                forceDeleteShortcutInner(removeList.get(i).getId());
            }
        }

        return removedShortcuts;
        return removeList;
    }

    /**
@@ -424,68 +449,69 @@ class ShortcutPackage extends ShortcutPackageItem {
     * Remove a dynamic shortcut by ID.  It'll be removed from the dynamic set, but if the shortcut
     * is pinned or cached, it'll remain as a pinned or cached shortcut, and is still enabled.
     *
     * @return true if it's removed, or false if it was not actually removed because it is either
     * @return The deleted shortcut, or null if it was not actually removed because it is either
     * pinned or cached.
     */
    public boolean deleteDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
        final ShortcutInfo removed = deleteOrDisableWithId(
    public ShortcutInfo deleteDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
        return deleteOrDisableWithId(
                shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible,
                ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
        return removed == null;
    }

    /**
     * Disable a dynamic shortcut by ID. It'll be removed from the dynamic set, but if the shortcut
     * is pinned, it'll remain as a pinned shortcut, but will be disabled.
     *
     * @return true if it's actually removed because it wasn't pinned, or false if it's still
     * pinned.
     * @return Shortcut if the disabled shortcut got removed because it wasn't pinned. Or null if
     * it's still pinned.
     */
    private boolean disableDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible,
    private ShortcutInfo disableDynamicWithId(@NonNull String shortcutId, boolean ignoreInvisible,
            int disabledReason) {
        final ShortcutInfo disabled = deleteOrDisableWithId(
                shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false, ignoreInvisible,
                disabledReason);
        return disabled == null;
        return deleteOrDisableWithId(shortcutId, /* disable =*/ true, /* overrideImmutable=*/ false,
                ignoreInvisible, disabledReason);
    }

    /**
     * Remove a long lived shortcut by ID. If the shortcut is pinned, it'll remain as a pinned
     * shortcut, and is still enabled.
     *
     * @return true if it's actually removed because it wasn't pinned, or false if it's still
     * pinned.
     * @return The deleted shortcut, or null if it was not actually removed because it's pinned.
     */
    public boolean deleteLongLivedWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
    public ShortcutInfo deleteLongLivedWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
        final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
        if (shortcut != null) {
            shortcut.clearFlags(ShortcutInfo.FLAG_CACHED);
        }
        final ShortcutInfo removed = deleteOrDisableWithId(
        return deleteOrDisableWithId(
                shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible,
                ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
        return removed == null;
    }

    /**
     * Disable a dynamic shortcut by ID.  It'll be removed from the dynamic set, but if the shortcut
     * is pinned, it'll remain as a pinned shortcut but will be disabled.
     *
     * @return Shortcut if the disabled shortcut got removed because it wasn't pinned. Or null if
     * it's still pinned.
     */
    public void disableWithId(@NonNull String shortcutId, String disabledMessage,
    public ShortcutInfo disableWithId(@NonNull String shortcutId, String disabledMessage,
            int disabledMessageResId, boolean overrideImmutable, boolean ignoreInvisible,
            int disabledReason) {
        final ShortcutInfo disabled = deleteOrDisableWithId(shortcutId, /* disable =*/ true,
        final ShortcutInfo deleted = deleteOrDisableWithId(shortcutId, /* disable =*/ true,
                overrideImmutable, ignoreInvisible, disabledReason);

        // If disabled id still exists, it is pinned and we need to update the disabled message.
        final ShortcutInfo disabled = mShortcuts.get(shortcutId);
        if (disabled != null) {
            if (disabledMessage != null) {
                disabled.setDisabledMessage(disabledMessage);
            } else if (disabledMessageResId != 0) {
                disabled.setDisabledMessageResId(disabledMessageResId);

                mShortcutUser.mService.fixUpShortcutResourceNamesAndValues(disabled);
            }
        }

        return deleted;
    }

    @Nullable
@@ -521,10 +547,10 @@ class ShortcutPackage extends ShortcutPackageItem {
                oldShortcut.setActivity(null);
            }

            return oldShortcut;
            return null;
        } else {
            forceDeleteShortcutInner(shortcutId);
            return null;
            return oldShortcut;
        }
    }

@@ -1005,7 +1031,7 @@ class ShortcutPackage extends ShortcutPackageItem {
                                "%s is no longer main activity. Disabling shorcut %s.",
                                getPackageName(), si.getId()));
                        if (disableDynamicWithId(si.getId(), /*ignoreInvisible*/ false,
                                ShortcutInfo.DISABLED_REASON_APP_CHANGED)) {
                                ShortcutInfo.DISABLED_REASON_APP_CHANGED) != null) {
                            continue; // Actually removed.
                        }
                        // Still pinned, so fall-through and possibly update the resources.
+3 −5
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
@@ -513,10 +513,6 @@ class ShortcutRequestPinProcessor {

            launcher.addPinnedShortcut(appPackageName, appUserId, shortcutId,
                    /*forPinRequest=*/ true);
            if (changedShortcuts == null) {
                changedShortcuts = new ArrayList<>(1);
            }
            changedShortcuts.add(original);

            if (current == null) {
                if (DEBUG) {
@@ -526,6 +522,8 @@ class ShortcutRequestPinProcessor {
            }

            ps.adjustRanks(); // Shouldn't be needed, but just in case.

            changedShortcuts = Collections.singletonList(ps.findShortcutById(shortcutId));
        }

        mService.verifyStates();
+193 −69

File changed.

Preview size limit exceeded, changes collapsed.

Loading