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

Commit 47092c27 authored by Pinyao Ting's avatar Pinyao Ting
Browse files

Shortcut integration with AppSearch (Part 10)

1. Persists enabled pinned shortcuts in xml.

Before the integration there are existing logic which persists shortcuts
in xml file, which makes it a good candidate for a cache layer on top of
AppSearch so that when launcher is loading the workspace, the later no
longer needs to wait for the former to finish initialization.

2. Postpone package rescan

When the device is rebooted for the very first time after the initial
restore, it would trigger a rescan on all the packages that was
installed on the device before the reboot. Since the device just
finished a restore, the number of new packages is large and
re-publishing manifest shortcuts from these packages could take a while.
In this CL we move the rescan to a background thread to prevent launcher
from being blocked when loading the workspace.

Bug: 151359749
Test: atest ShortcutManagerTest1 ShortcutManagerTest2
    ShortcutManagerTest3 ShortcutManagerTest4 ShortcutManagerTest5
    ShortcutManagerTest6 ShortcutManagerTest7 ShortcutManagerTest8
    ShortcutManagerTest9 ShortcutManagerTest10 ShortcutManagerTest11
    ShortcutManagerTest12
Test: atest CtsShortcutManagerTestCases
Change-Id: I612c8ad49f3408d80fbb6d64f948e95ae6641899
parent f1f376fc
Loading
Loading
Loading
Loading
+52 −18
Original line number Diff line number Diff line
@@ -160,7 +160,7 @@ class ShortcutPackage extends ShortcutPackageItem {
    /**
     * An temp in-memory copy of shortcuts for this package that was loaded from xml, keyed on IDs.
     */
    final ArraySet<ShortcutInfo> mShortcuts = new ArraySet<>();
    final ArrayMap<String, ShortcutInfo> mShortcuts = new ArrayMap<>();

    /**
     * All the share targets from the package
@@ -832,6 +832,26 @@ class ShortcutPackage extends ShortcutPackageItem {
        }
    }

    /**
     * Find all pinned shortcuts that match {@code query}.
     */
    public void findAllPinned(@NonNull List<ShortcutInfo> result,
            @Nullable Predicate<ShortcutInfo> query, int cloneFlag,
            @Nullable String callingLauncher, int launcherUserId, boolean getPinnedByAnyLauncher) {
        if (getPackageInfo().isShadow()) {
            // Restored and the app not installed yet, so don't return any.
            return;
        }
        final ShortcutService s = mShortcutUser.mService;

        // Set of pinned shortcuts by the calling launcher.
        final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
                : s.getLauncherShortcutsLocked(callingLauncher, getPackageUserId(), launcherUserId)
                        .getPinnedShortcutIds(getPackageName(), getPackageUserId());
        mShortcuts.values().forEach(si -> filter(result, query, cloneFlag, callingLauncher,
                pinnedByCallerSet, getPinnedByAnyLauncher, si));
    }

    private void filter(@NonNull final List<ShortcutInfo> result,
            @Nullable final Predicate<ShortcutInfo> query, final int cloneFlag,
            @Nullable final String callingLauncher,
@@ -1672,10 +1692,10 @@ class ShortcutPackage extends ShortcutPackageItem {
    @Override
    public void saveToXml(@NonNull TypedXmlSerializer out, boolean forBackup)
            throws IOException, XmlPullParserException {
        final int size = getShortcutCount();
        final int size = mShortcuts.size();
        final int shareTargetSize = mShareTargets.size();

        if (size == 0 && shareTargetSize == 0 && mApiCallCount == 0) {
        if (size == 0 && shareTargetSize == 0 && mApiCallCount == 0 && getShortcutCount() == 0) {
            return; // nothing to write.
        }

@@ -1695,15 +1715,8 @@ class ShortcutPackage extends ShortcutPackageItem {
        }
        getPackageInfo().saveToXml(mShortcutUser.mService, out, forBackup);

        if (forBackup) {
            // Shortcuts are persisted in AppSearch, xml is only needed for backup.
            forEachShortcut(AppSearchShortcutInfo.QUERY_IS_PINNED_AND_ENABLED, si -> {
                try {
                    saveShortcut(out, si, forBackup, getPackageInfo().isBackupAllowed());
                } catch (IOException | XmlPullParserException e) {
                    throw new RuntimeException(e);
                }
            });
        for (int j = 0; j < size; j++) {
            saveShortcut(out, mShortcuts.valueAt(j), forBackup, getPackageInfo().isBackupAllowed());
        }

        if (!forBackup) {
@@ -1916,7 +1929,7 @@ class ShortcutPackage extends ShortcutPackageItem {
                        final ShortcutInfo si = parseShortcut(parser, packageName,
                                shortcutUser.getUserId(), fromBackup);
                        // Don't use addShortcut(), we don't need to save the icon.
                        ret.mShortcuts.add(si);
                        ret.mShortcuts.put(si.getId(), si);
                        continue;
                    case TAG_SHARE_TARGET:
                        ret.mShareTargets.add(ShareTargetInfo.loadFromXml(parser));
@@ -2267,12 +2280,24 @@ class ShortcutPackage extends ShortcutPackageItem {
    }

    private void saveShortcut(@NonNull final Collection<ShortcutInfo> shortcuts) {
        Objects.requireNonNull(shortcuts);
        shortcuts.forEach(si -> {
            if (si.isPinned()) {
                mShortcuts.put(si.getId(), si);
            } else {
                mShortcuts.remove(si.getId());
            }
        });
        saveToAppSearch(shortcuts);
    }

    private void saveToAppSearch(@NonNull final Collection<ShortcutInfo> shortcuts) {
        Objects.requireNonNull(shortcuts);
        if (shortcuts.isEmpty()) {
            // No need to invoke AppSearch when there's nothing to save.
            return;
        }
        awaitInAppSearch("Saving shortcut", session -> {
        awaitInAppSearch("Saving shortcuts", session -> {
            final AndroidFuture<Boolean> future = new AndroidFuture<>();
            session.put(new PutDocumentsRequest.Builder()
                            .addGenericDocuments(
@@ -2314,6 +2339,7 @@ class ShortcutPackage extends ShortcutPackageItem {

    private void removeShortcut(@NonNull final String id) {
        Objects.requireNonNull(id);
        mShortcuts.remove(id);
        awaitInAppSearch("Removing shortcut with id=" + id, session -> {
            final AndroidFuture<Boolean> future = new AndroidFuture<>();
            session.remove(new RemoveByUriRequest.Builder(getPackageName()).addUris(id).build(),
@@ -2474,11 +2500,15 @@ class ShortcutPackage extends ShortcutPackageItem {
                        .detectAll()
                        .penaltyLog() // TODO: change this to penaltyDeath to fix the call-site
                        .build());
                if (!mIsInitilized || forceReset) {
                final boolean wasInitialized = mIsInitilized;
                if (!wasInitialized || forceReset) {
                    ConcurrentUtils.waitForFutureNoInterrupt(
                            setupSchema(session), "Setting up schema");
                }
                mIsInitilized = true;
                if (!wasInitialized) {
                    restoreParsedShortcuts(false);
                }
                return ConcurrentUtils.waitForFutureNoInterrupt(cb.apply(session), description);
            } catch (Exception e) {
                Slog.e(TAG, "Failed to initiate app search for shortcut package "
@@ -2526,13 +2556,17 @@ class ShortcutPackage extends ShortcutPackageItem {
    }

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

    private void restoreParsedShortcuts(final boolean replace) {
        if (replace) {
            removeShortcuts();
        }
        saveShortcut(mShortcuts);
        saveToAppSearch(mShortcuts.values());
    }

    private boolean verifyRanksSequential(List<ShortcutInfo> list) {
+11 −2
Original line number Diff line number Diff line
@@ -1306,7 +1306,7 @@ public class ShortcutService extends IShortcutService.Stub {
            mUsers.put(userId, userPackages);

            // Also when a user's data is first accessed, scan all packages.
            checkPackageChanges(userId);
            injectPostToHandler(() -> checkPackageChanges(userId));
        }
        return userPackages;
    }
@@ -3006,9 +3006,18 @@ public class ShortcutService extends IShortcutService.Stub {
                    ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER) != 0);
            queryFlags |= (getPinnedByAnyLauncher ? ShortcutQuery.FLAG_MATCH_PINNED : 0);

            final boolean matchPinnedOnly =
                    ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0)
                            && ((queryFlags & ShortcutQuery.FLAG_MATCH_CACHED) == 0)
                            && ((queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) == 0)
                            && ((queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) == 0);

            final Predicate<ShortcutInfo> filter = getFilterFromQuery(ids, locusIds, changedSince,
                    componentName, queryFlags, getPinnedByAnyLauncher);
            if (ids != null && !ids.isEmpty()) {
            if (matchPinnedOnly) {
                p.findAllPinned(ret, filter, cloneFlag, callingPackage, launcherUserId,
                        getPinnedByAnyLauncher);
            } else if (ids != null && !ids.isEmpty()) {
                p.findAllByIds(ret, ids, filter, cloneFlag, callingPackage, launcherUserId,
                        getPinnedByAnyLauncher);
            } else {
+1 −3
Original line number Diff line number Diff line
@@ -457,7 +457,6 @@ 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);
@@ -492,7 +491,6 @@ class ShortcutUser {
                final ShortcutPackage sp = ShortcutPackage.loadFromFile(s, ret, f, fromBackup);
                if (sp != null) {
                    ret.mPackages.put(sp.getPackageName(), sp);
                    sp.restoreParsedShortcuts(false);
                }
            });

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