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

Commit 32e30398 authored by Pinyao Ting's avatar Pinyao Ting
Browse files

Shortcut integration with AppSearch (Part 3)

In order to move shortcuts from memory into AppSearch, any in-memory
mutation needs to be identified so that they can be applied directly
into AppSearch. This CL creates a proxy method that applies mutation on
the in-memory copy, which can later be changed to post the update into
AppSearch.

Bug: 151359749
Test: atest ShortcutManagerTest1 ShortcutManagerTest2 ShortcutManagerTest3 ShortcutManagerTest4 ShortcutManagerTest5 ShortcutManagerTest6 ShortcutManagerTest7 ShortcutManagerTest8 ShortcutManagerTest9 ShortcutManagerTest10 ShortcutManagerTest11
Change-Id: I59daa9cc589b587d022a1e070986e07ed6ab0a75
parent 47d1a022
Loading
Loading
Loading
Loading
+9 −6
Original line number Diff line number Diff line
@@ -280,7 +280,8 @@ public class ShortcutBitmapSaver {
                    IoUtils.closeQuietly(out);
                }

                shortcut.setBitmapPath(file.getAbsolutePath());
                final String path = file.getAbsolutePath();
                mService.postValue(shortcut, si -> si.setBitmapPath(path));

            } catch (IOException | RuntimeException e) {
                Slog.e(ShortcutService.TAG, "Unable to write bitmap to file", e);
@@ -295,12 +296,14 @@ public class ShortcutBitmapSaver {
                Slog.d(TAG, "Saved bitmap.");
            }
            if (shortcut != null) {
                if (shortcut.getBitmapPath() == null) {
                    removeIcon(shortcut);
                mService.postValue(shortcut, si -> {
                    if (si.getBitmapPath() == null) {
                        removeIcon(si);
                    }

                    // Whatever happened, remove this flag.
                shortcut.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
                    si.clearFlags(ShortcutInfo.FLAG_ICON_FILE_PENDING_SAVE);
                });
            }
        }
        return true;
+120 −61
Original line number Diff line number Diff line
@@ -223,12 +223,14 @@ class ShortcutPackage extends ShortcutPackageItem {
        // - Disable if needed.
        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
            ShortcutInfo si = mShortcuts.valueAt(i);
            si.clearFlags(ShortcutInfo.FLAG_SHADOW);
            mutateShortcut(si.getId(), si, shortcut -> {
                shortcut.clearFlags(ShortcutInfo.FLAG_SHADOW);

            si.setDisabledReason(restoreBlockReason);
                shortcut.setDisabledReason(restoreBlockReason);
                if (restoreBlockReason != ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
                si.addFlags(ShortcutInfo.FLAG_DISABLED);
                    shortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
                }
            });
        }
        // Because some launchers may not have been restored (e.g. allowBackup=false),
        // we need to re-calculate the pinned shortcuts.
@@ -460,9 +462,11 @@ class ShortcutPackage extends ShortcutPackageItem {
            if (si.isDynamic() && (!ignoreInvisible || si.isVisibleToPublisher())) {
                changed = true;

                si.setTimestamp(now);
                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
                si.setRank(0); // It may still be pinned, so clear the rank.
                mutateShortcut(si.getId(), si, shortcut -> {
                    shortcut.setTimestamp(now);
                    shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC);
                    shortcut.setRank(0); // It may still be pinned, so clear the rank.
                });
            }
        }
        if (changed) {
@@ -506,7 +510,7 @@ class ShortcutPackage extends ShortcutPackageItem {
    public ShortcutInfo deleteLongLivedWithId(@NonNull String shortcutId, boolean ignoreInvisible) {
        final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
        if (shortcut != null) {
            shortcut.clearFlags(ShortcutInfo.FLAG_CACHED_ALL);
            mutateShortcut(shortcutId, null, si -> si.clearFlags(ShortcutInfo.FLAG_CACHED_ALL));
        }
        return deleteOrDisableWithId(
                shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible,
@@ -527,7 +531,7 @@ class ShortcutPackage extends ShortcutPackageItem {
                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);
        mutateShortcut(shortcutId, null, disabled -> {
            if (disabled != null) {
                if (disabledMessage != null) {
                    disabled.setDisabledMessage(disabledMessage);
@@ -536,6 +540,7 @@ class ShortcutPackage extends ShortcutPackageItem {
                    mShortcutUser.mService.fixUpShortcutResourceNamesAndValues(disabled);
                }
            }
        });

        return deleted;
    }
@@ -557,21 +562,23 @@ class ShortcutPackage extends ShortcutPackageItem {
        }
        if (oldShortcut.isPinned() || oldShortcut.isCached()) {

            oldShortcut.setRank(0);
            oldShortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
            mutateShortcut(oldShortcut.getId(), oldShortcut, si -> {
                si.setRank(0);
                si.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_MANIFEST);
                if (disable) {
                oldShortcut.addFlags(ShortcutInfo.FLAG_DISABLED);
                    si.addFlags(ShortcutInfo.FLAG_DISABLED);
                    // Do not overwrite the disabled reason if one is alreay set.
                if (oldShortcut.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
                    oldShortcut.setDisabledReason(disabledReason);
                    if (si.getDisabledReason() == ShortcutInfo.DISABLED_REASON_NOT_DISABLED) {
                        si.setDisabledReason(disabledReason);
                    }
                }
            oldShortcut.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());
                si.setTimestamp(mShortcutUser.mService.injectCurrentTimeMillis());

                // See ShortcutRequestPinProcessor.directPinShortcut().
            if (mShortcutUser.mService.isDummyMainActivity(oldShortcut.getActivity())) {
                oldShortcut.setActivity(null);
                if (mShortcutUser.mService.isDummyMainActivity(si.getActivity())) {
                    si.setActivity(null);
                }
            });

            return null;
        } else {
@@ -581,12 +588,11 @@ class ShortcutPackage extends ShortcutPackageItem {
    }

    public void enableWithId(@NonNull String shortcutId) {
        final ShortcutInfo shortcut = mShortcuts.get(shortcutId);
        if (shortcut != null) {
            ensureNotImmutable(shortcut, /*ignoreInvisible=*/ true);
            shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
            shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
        }
        mutateShortcut(shortcutId, null, si -> {
            ensureNotImmutable(si, /*ignoreInvisible=*/ true);
            si.clearFlags(ShortcutInfo.FLAG_DISABLED);
            si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
        });
    }

    public void updateInvisibleShortcutForPinRequestWith(@NonNull ShortcutInfo shortcut) {
@@ -609,22 +615,25 @@ class ShortcutPackage extends ShortcutPackageItem {
     * <p>Then remove all shortcuts that are not dynamic and no longer pinned either.
     */
    public void refreshPinnedFlags() {
        // First, un-pin all shortcuts
        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
            mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
        // TODO: rewrite this function with proper query (i.e. fetch only pinned shortcuts and
        //  unpin if it's no longer pinned by any launcher and vice versa)
        final List<ShortcutInfo> shortcuts = new ArrayList<>(mShortcuts.values());
        final Map<String, ShortcutInfo> shortcutMap = new ArrayMap<>(shortcuts.size());
        for (ShortcutInfo si : shortcuts) {
            shortcutMap.put(si.getId(), si);
        }
        final Set<String> pinnedShortcuts = new ArraySet<>();

        // Then, for the pinned set for each launcher, set the pin flag one by one.
        // First, for the pinned set for each launcher, keep track of their id one by one.
        mShortcutUser.forAllLaunchers(launcherShortcuts -> {
            final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(
                    getPackageName(), getPackageUserId());

            if (pinned == null || pinned.size() == 0) {
                return;
            }
            for (int i = pinned.size() - 1; i >= 0; i--) {
                final String id = pinned.valueAt(i);
                final ShortcutInfo si = mShortcuts.get(id);
                final ShortcutInfo si = shortcutMap.get(id);
                if (si == null) {
                    // This happens if a launcher pinned shortcuts from this package, then backup&
                    // restored, but this package doesn't allow backing up.
@@ -632,9 +641,21 @@ class ShortcutPackage extends ShortcutPackageItem {
                    // That's fine, when the launcher is restored, we'll fix it.
                    continue;
                }
                si.addFlags(ShortcutInfo.FLAG_PINNED);
                pinnedShortcuts.add(si.getId());
            }
        });
        // Then, update the pinned state if necessary
        for (int i = shortcuts.size() - 1; i >= 0; i--) {
            final ShortcutInfo si = shortcuts.get(i);
            if (pinnedShortcuts.contains(si.getId()) && !si.isPinned()) {
                mutateShortcut(si.getId(), si,
                        shortcut -> shortcut.addFlags(ShortcutInfo.FLAG_PINNED));
            }
            if (!pinnedShortcuts.contains(si.getId()) && si.isPinned()) {
                mutateShortcut(si.getId(), si, shortcut ->
                        shortcut.clearFlags(ShortcutInfo.FLAG_PINNED));
            }
        }

        // Lastly, remove the ones that are no longer pinned, cached nor dynamic.
        removeOrphans();
@@ -1034,8 +1055,10 @@ class ShortcutPackage extends ShortcutPackageItem {
                continue;
            }
            Slog.i(TAG, String.format("Restoring shortcut: %s", si.getId()));
            si.clearFlags(ShortcutInfo.FLAG_DISABLED);
            si.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
            mutateShortcut(si.getId(), si, shortcut -> {
                shortcut.clearFlags(ShortcutInfo.FLAG_DISABLED);
                shortcut.setDisabledReason(ShortcutInfo.DISABLED_REASON_NOT_DISABLED);
            });
        }

        // For existing shortcuts, update timestamps if they have any resources.
@@ -1065,7 +1088,6 @@ class ShortcutPackage extends ShortcutPackageItem {
                }

                if (si.hasAnyResources()) {
                    if (!si.isOriginallyFromManifest()) {
                    if (publisherRes == null) {
                        publisherRes = getPackageResources();
                        if (publisherRes == null) {
@@ -1073,13 +1095,17 @@ class ShortcutPackage extends ShortcutPackageItem {
                        }
                    }

                        // TODO: update resource strings in AppSearch
                    final Resources res = publisherRes;
                    mutateShortcut(si.getId(), si, shortcut -> {
                        if (!shortcut.isOriginallyFromManifest()) {
                            shortcut.lookupAndFillInResourceIds(res);
                        }

                        // If this shortcut is not from a manifest, then update all resource IDs
                        // from resource names.  (We don't allow resource strings for
                        // non-manifest at the moment, but icons can still be resources.)
                        si.lookupAndFillInResourceIds(publisherRes);
                    }
                    si.setTimestamp(s.injectCurrentTimeMillis());
                        shortcut.setTimestamp(s.injectCurrentTimeMillis());
                    });
                }
            }
        }
@@ -1382,8 +1408,11 @@ class ShortcutPackage extends ShortcutPackageItem {
                    }
                }

                si.resolveResourceStrings(publisherRes);
                si.setTimestamp(s.injectCurrentTimeMillis());
                final Resources res = publisherRes;
                mutateShortcut(si.getId(), si, shortcut -> {
                    shortcut.resolveResourceStrings(res);
                    shortcut.setTimestamp(s.injectCurrentTimeMillis());
                });

                if (changedShortcuts == null) {
                    changedShortcuts = new ArrayList<>(1);
@@ -1400,7 +1429,7 @@ class ShortcutPackage extends ShortcutPackageItem {
    public void clearAllImplicitRanks() {
        for (int i = mShortcuts.size() - 1; i >= 0; i--) {
            final ShortcutInfo si = mShortcuts.valueAt(i);
            si.clearImplicitRankAndRankChangedFlag();
            mutateShortcut(si.getId(), si, ShortcutInfo::clearImplicitRankAndRankChangedFlag);
        }
    }

@@ -1445,8 +1474,10 @@ class ShortcutPackage extends ShortcutPackageItem {
            final ShortcutInfo si = mShortcuts.valueAt(i);
            if (si.isFloating()) {
                if (si.getRank() != 0) {
                    si.setTimestamp(now);
                    si.setRank(0);
                    mutateShortcut(si.getId(), si, shortcut -> {
                        shortcut.setTimestamp(now);
                        shortcut.setRank(0);
                    });
                }
            }
        }
@@ -1479,8 +1510,10 @@ class ShortcutPackage extends ShortcutPackageItem {
                }
                final int thisRank = rank++;
                if (si.getRank() != thisRank) {
                    si.setTimestamp(now);
                    si.setRank(thisRank);
                    mutateShortcut(si.getId(), si, shortcut -> {
                        shortcut.setTimestamp(now);
                        shortcut.setRank(thisRank);
                    });
                }
            }
        }
@@ -2172,6 +2205,32 @@ class ShortcutPackage extends ShortcutPackageItem {
        resetAppSearch(null);
    }

    void mutateShortcut(@NonNull final String id, @Nullable final ShortcutInfo shortcut,
            @NonNull final Consumer<ShortcutInfo> transform) {
        Objects.requireNonNull(id);
        Objects.requireNonNull(transform);
        synchronized (mLock) {
            if (shortcut != null) {
                transform.accept(shortcut);
            } else {
                transform.accept(findShortcutById(id));
            }
            // TODO: Load ShortcutInfo from AppSearch, apply transformation logic and save
        }
    }

    /**
     * Removes shortcuts from AppSearch.
     */
    void removeShortcuts() {
    }

    /**
     * Merge/replace shortcuts parsed from xml file.
     */
    void restoreParsedShortcuts(final boolean replace) {
    }

    private boolean verifyRanksSequential(List<ShortcutInfo> list) {
        boolean failed = false;

+52 −45
Original line number Diff line number Diff line
@@ -1179,6 +1179,14 @@ public class ShortcutService extends IShortcutService.Stub {
        }
    }

    void postValue(@NonNull final ShortcutInfo shortcutInfo,
            @NonNull final Consumer<ShortcutInfo> cb) {
        final String pkg = shortcutInfo.getPackage();
        final int userId = shortcutInfo.getUserId();
        final String id = shortcutInfo.getId();
        getPackageShortcutsLocked(pkg, userId).mutateShortcut(id, shortcutInfo, cb);
    }

    /** Return the last reset time. */
    @GuardedBy("mLock")
    long getLastResetTimeLocked() {
@@ -1566,7 +1574,6 @@ public class ShortcutService extends IShortcutService.Stub {
     * resource-based strings.
     */
    void fixUpShortcutResourceNamesAndValues(ShortcutInfo si) {
        // TODO: update resource names in AppSearch
        final Resources publisherRes = injectGetResourcesForApplicationAsUser(
                si.getPackage(), si.getUserId());
        if (publisherRes != null) {
@@ -1947,7 +1954,7 @@ public class ShortcutService extends IShortcutService.Stub {
        final boolean unlimited = injectHasUnlimitedShortcutsApiCallsPermission(
                injectBinderCallingPid(), injectBinderCallingUid());

        List<ShortcutInfo> changedShortcuts = null;
        final List<ShortcutInfo> changedShortcuts = new ArrayList<>(1);

        synchronized (mLock) {
            throwIfUserLockedL(userId);
@@ -1975,11 +1982,10 @@ public class ShortcutService extends IShortcutService.Stub {
                final ShortcutInfo source = newShortcuts.get(i);
                fixUpIncomingShortcutInfo(source, /* forUpdate= */ true);

                final ShortcutInfo target = ps.findShortcutById(source.getId());

                ps.mutateShortcut(source.getId(), null, target -> {
                    // Invisible shortcuts can't be updated.
                    if (target == null || !target.isVisibleToPublisher()) {
                    continue;
                        return;
                    }

                    if (target.isEnabled() != source.isEnabled()) {
@@ -2018,16 +2024,15 @@ public class ShortcutService extends IShortcutService.Stub {
                        fixUpShortcutResourceNamesAndValues(target);
                    }

                if (changedShortcuts == null) {
                    changedShortcuts = new ArrayList<>(1);
                }
                    changedShortcuts.add(target);
                });
            }

            // Lastly, adjust the ranks.
            ps.adjustRanks();
        }
        packageShortcutsChanged(packageName, userId, changedShortcuts, null);
        packageShortcutsChanged(packageName, userId,
                changedShortcuts.isEmpty() ? null : changedShortcuts, null);

        verifyStates();

@@ -3114,7 +3119,8 @@ public class ShortcutService extends IShortcutService.Stub {

                    if (doCache) {
                        if (si.isLongLived()) {
                            si.addFlags(cacheFlags);
                            sp.mutateShortcut(si.getId(), si,
                                    shortcut -> shortcut.addFlags(cacheFlags));
                            if (changedShortcuts == null) {
                                changedShortcuts = new ArrayList<>(1);
                            }
@@ -3125,7 +3131,8 @@ public class ShortcutService extends IShortcutService.Stub {
                        }
                    } else {
                        ShortcutInfo removed = null;
                        si.clearFlags(cacheFlags);
                        sp.mutateShortcut(si.getId(), si, shortcut ->
                                shortcut.clearFlags(cacheFlags));
                        if (!si.isDynamic() && !si.isCached()) {
                            removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true);
                        }
+10 −1
Original line number Diff line number Diff line
@@ -185,6 +185,9 @@ class ShortcutUser {
    public ShortcutPackage removePackage(@NonNull String packageName) {
        final ShortcutPackage removed = mPackages.remove(packageName);

        if (removed != null) {
            removed.removeShortcuts();
        }
        mService.cleanupBitmapsForPackage(mUserId, packageName);

        return removed;
@@ -330,7 +333,10 @@ class ShortcutUser {

        if (!shortcutPackage.rescanPackageIfNeeded(isNewApp, forceRescan)) {
            if (isNewApp) {
                mPackages.remove(packageName);
                final ShortcutPackage sp = mPackages.remove(packageName);
                if (sp != null) {
                    sp.removeShortcuts();
                }
            }
        }
    }
@@ -454,6 +460,7 @@ class ShortcutUser {
                        case ShortcutPackage.TAG_ROOT: {
                            final ShortcutPackage shortcuts = ShortcutPackage.loadFromXml(
                                    s, ret, parser, fromBackup);
                            shortcuts.restoreParsedShortcuts(false);

                            // Don't use addShortcut(), we don't need to save the icon.
                            ret.mPackages.put(shortcuts.getPackageName(), shortcuts);
@@ -488,6 +495,7 @@ class ShortcutUser {
                final ShortcutPackage sp = ShortcutPackage.loadFromFile(s, ret, f, fromBackup);
                if (sp != null) {
                    ret.mPackages.put(sp.getPackageName(), sp);
                    sp.restoreParsedShortcuts(false);
                }
            });

@@ -570,6 +578,7 @@ class ShortcutUser {
                Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored."
                        + " Existing non-manifeset shortcuts will be overwritten.");
            }
            sp.restoreParsedShortcuts(true);
            addPackage(sp);
            restoredPackages[0]++;
            restoredShortcuts[0] += sp.getShortcutCount();