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

Commit 9081a441 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Shortcut integration with AppSearch (Part 5)" into sc-dev

parents 948850fc b41bc495
Loading
Loading
Loading
Loading
+14 −0
Original line number Diff line number Diff line
@@ -40,6 +40,7 @@ import java.io.IOException;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.Set;
@@ -327,6 +328,19 @@ public class AppSearchShortcutInfo extends GenericDocument {
        return si;
    }

    /**
     * @hide
     */
    @NonNull
    public static List<GenericDocument> toGenericDocuments(
            @NonNull final Collection<ShortcutInfo> shortcuts) {
        final List<GenericDocument> docs = new ArrayList<>(shortcuts.size());
        for (ShortcutInfo si : shortcuts) {
            docs.add(AppSearchShortcutInfo.instance(si));
        }
        return docs;
    }

    /** @hide */
    @VisibleForTesting
    public static class Builder extends GenericDocument.Builder<Builder> {
+476 −383

File changed.

Preview size limit exceeded, changes collapsed.

+11 −1
Original line number Diff line number Diff line
@@ -2590,7 +2590,6 @@ public class ShortcutService extends IShortcutService.Stub {

        final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
        ps.findAll(ret, query, cloneFlags);

        return new ParceledListSlice<>(setReturnedByServer(ret));
    }

@@ -5077,6 +5076,17 @@ public class ShortcutService extends IShortcutService.Stub {
        }
    }

    @VisibleForTesting
    void updatePackageShortcutForTest(String packageName, String shortcutId, int userId,
            Consumer<ShortcutInfo> cb) {
        synchronized (mLock) {
            final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId);
            if (pkg == null) return;

            pkg.mutateShortcut(shortcutId, null, cb);
        }
    }

    @VisibleForTesting
    ShortcutLauncher getLauncherShortcutForTest(String packageName, int userId) {
        synchronized (mLock) {
+15 −6
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.appsearch.AppSearchManager;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSession;
import android.content.pm.ShortcutManager;
import android.metrics.LogMaker;
@@ -35,6 +34,7 @@ import android.util.TypedXmlPullParser;
import android.util.TypedXmlSerializer;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.server.FgThread;
@@ -715,17 +715,26 @@ class ShortcutUser {
                .setSubtype(totalSharingShortcutCount));
    }

    void runInAppSearch(@NonNull final AppSearchManager.SearchContext searchContext,
            @NonNull final Consumer<AppSearchResult<AppSearchSession>> callback) {
    AndroidFuture<AppSearchSession> getAppSearch(
            @NonNull final AppSearchManager.SearchContext searchContext) {
        final AndroidFuture<AppSearchSession> future = new AndroidFuture<>();
        if (mAppSearchManager == null) {
            Slog.e(TAG, "app search manager is null");
            return;
            future.completeExceptionally(new RuntimeException("app search manager is null"));
            return future;
        }
        final long callingIdentity = Binder.clearCallingIdentity();
        try {
            mAppSearchManager.createSearchSession(searchContext, mExecutor, callback);
            mAppSearchManager.createSearchSession(searchContext, mExecutor, result -> {
                if (!result.isSuccess()) {
                    future.completeExceptionally(
                            new RuntimeException(result.getErrorMessage()));
                    return;
                }
                future.complete(result.getResultValue());
            });
        } finally {
            Binder.restoreCallingIdentity(callingIdentity);
        }
        return future;
    }
}
+132 −17
Original line number Diff line number Diff line
@@ -48,10 +48,12 @@ import android.app.admin.DevicePolicyManager;
import android.app.appsearch.AppSearchBatchResult;
import android.app.appsearch.AppSearchManager;
import android.app.appsearch.AppSearchResult;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.IAppSearchBatchResultCallback;
import android.app.appsearch.IAppSearchManager;
import android.app.appsearch.IAppSearchResultCallback;
import android.app.appsearch.PackageIdentifier;
import android.app.appsearch.SearchResultPage;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ActivityNotFoundException;
@@ -159,7 +161,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
                case Context.DEVICE_POLICY_SERVICE:
                    return mMockDevicePolicyManager;
                case Context.APP_SEARCH_SERVICE:
                    return new AppSearchManager(getTestContext(), mMockAppSearchManager);
                    return new AppSearchManager(this, mMockAppSearchManager);
                case Context.ROLE_SERVICE:
                    // RoleManager is final and cannot be mocked, so we only override the inject
                    // accessor methods in ShortcutService.
@@ -188,6 +190,12 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
            return getTestContext().getResources();
        }

        @Override
        public Context createContextAsUser(UserHandle user, int flags) {
            when(mMockPackageManager.getUserId()).thenReturn(user.getIdentifier());
            return this;
        }

        @Override
        public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
                IntentFilter filter, String broadcastPermission, Handler scheduler) {
@@ -195,12 +203,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
            return null;
        }

        @Override
        public Context createContextAsUser(UserHandle user, int flags) {
            when(mMockPackageManager.getUserId()).thenReturn(user.getIdentifier());
            return this;
        }

        @Override
        public void unregisterReceiver(BroadcastReceiver receiver) {
            // ignore.
@@ -237,6 +239,15 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
            mInjectedCallingUid = (int) token;
        }

        @Override
        public Context createContextAsUser(UserHandle user, int flags) {
            super.createContextAsUser(user, flags);
            final ServiceContext ctx = spy(new ServiceContext());
            when(ctx.getUser()).thenReturn(user);
            when(ctx.getUserId()).thenReturn(user.getIdentifier());
            return ctx;
        }

        @Override
        public int getUserId() {
            return UserHandle.USER_SYSTEM;
@@ -620,6 +631,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {

        protected Map<String, List<PackageIdentifier>> mSchemasPackageAccessible =
                new ArrayMap<>(1);
        private Map<String, Map<String, GenericDocument>> mDocumentMap = new ArrayMap<>(1);

        private String getKey(int userId, String databaseName) {
            return new StringBuilder().append(userId).append("@").append(databaseName).toString();
        }

        @Override
        public void setSchema(String packageName, String databaseName, List<Bundle> schemaBundles,
@@ -653,21 +669,77 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        public void putDocuments(String packageName, String databaseName,
                List<Bundle> documentBundles, int userId, IAppSearchBatchResultCallback callback)
                throws RemoteException {
            ignore(callback);
            final List<GenericDocument> docs = new ArrayList<>(documentBundles.size());
            for (Bundle bundle : documentBundles) {
                docs.add(new GenericDocument(bundle));
            }
            final AppSearchBatchResult.Builder<String, Void> builder =
                    new AppSearchBatchResult.Builder<>();
            final String key = getKey(userId, databaseName);
            Map<String, GenericDocument> docMap = mDocumentMap.get(key);
            for (GenericDocument doc : docs) {
                builder.setSuccess(doc.getUri(), null);
                if (docMap == null) {
                    docMap = new ArrayMap<>(1);
                    mDocumentMap.put(key, docMap);
                }
                docMap.put(doc.getUri(), doc);
            }
            callback.onResult(builder.build());
        }

        @Override
        public void getDocuments(String packageName, String databaseName, String namespace,
                List<String> uris, Map<String, List<String>> typePropertyPaths, int userId,
                IAppSearchBatchResultCallback callback) throws RemoteException {
            ignore(callback);
            final AppSearchBatchResult.Builder<String, Bundle> builder =
                    new AppSearchBatchResult.Builder<>();
            final String key = getKey(userId, databaseName);
            if (!mDocumentMap.containsKey(key)) {
                for (String uri : uris) {
                    builder.setFailure(uri, AppSearchResult.RESULT_NOT_FOUND,
                            key + " not found when getting: " + uri);
                }
            } else {
                final Map<String, GenericDocument> docs = mDocumentMap.get(key);
                for (String uri : uris) {
                    if (docs.containsKey(uri)) {
                        builder.setSuccess(uri, docs.get(uri).getBundle());
                    } else {
                        builder.setFailure(uri, AppSearchResult.RESULT_NOT_FOUND,
                                "shortcut not found: " + uri);
                    }
                }
            }
            callback.onResult(builder.build());
        }

        @Override
        public void query(String packageName, String databaseName, String queryExpression,
                Bundle searchSpecBundle, int userId, IAppSearchResultCallback callback)
                throws RemoteException {
            ignore(callback);
            final String key = getKey(userId, databaseName);
            if (!mDocumentMap.containsKey(key)) {
                final Bundle page = new Bundle();
                page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1);
                page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, new ArrayList<>());
                callback.onResult(AppSearchResult.newSuccessfulResult(page));
                return;
            }
            final List<GenericDocument> documents = new ArrayList<>(mDocumentMap.get(key).values());
            final Bundle page = new Bundle();
            page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 0);
            final ArrayList<Bundle> resultBundles = new ArrayList<>();
            for (GenericDocument document : documents) {
                final Bundle resultBundle = new Bundle();
                resultBundle.putBundle("document", document.getBundle());
                resultBundle.putString("packageName", packageName);
                resultBundle.putString("databaseName", databaseName);
                resultBundle.putParcelableArrayList("matches", new ArrayList<>());
                resultBundles.add(resultBundle);
            }
            page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
            callback.onResult(AppSearchResult.newSuccessfulResult(page));
        }

        @Override
@@ -679,7 +751,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        @Override
        public void getNextPage(long nextPageToken, int userId, IAppSearchResultCallback callback)
                throws RemoteException {
            ignore(callback);
            final Bundle page = new Bundle();
            page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1);
            page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, new ArrayList<>());
            callback.onResult(AppSearchResult.newSuccessfulResult(page));
        }

        @Override
@@ -698,14 +773,40 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        public void removeByUri(String packageName, String databaseName, String namespace,
                List<String> uris, int userId, IAppSearchBatchResultCallback callback)
                throws RemoteException {
            ignore(callback);
            final AppSearchBatchResult.Builder<String, Void> builder =
                    new AppSearchBatchResult.Builder<>();
            final String key = getKey(userId, databaseName);
            if (!mDocumentMap.containsKey(key)) {
                for (String uri : uris) {
                    builder.setFailure(uri, AppSearchResult.RESULT_NOT_FOUND,
                            "package " + key + " not found when removing " + uri);
                }
            } else {
                final Map<String, GenericDocument> docs = mDocumentMap.get(key);
                for (String uri : uris) {
                    if (docs.containsKey(uri)) {
                        docs.remove(uri);
                        builder.setSuccess(uri, null);
                    } else {
                        builder.setFailure(uri, AppSearchResult.RESULT_NOT_FOUND,
                                "shortcut not found when removing " + uri);
                    }
                }
            }
            callback.onResult(builder.build());
        }

        @Override
        public void removeByQuery(String packageName, String databaseName, String queryExpression,
                Bundle searchSpecBundle, int userId, IAppSearchResultCallback callback)
                throws RemoteException {
            ignore(callback);
            final String key = getKey(userId, databaseName);
            if (!mDocumentMap.containsKey(key)) {
                callback.onResult(AppSearchResult.newSuccessfulResult(null));
                return;
            }
            mDocumentMap.get(key).clear();
            callback.onResult(AppSearchResult.newSuccessfulResult(null));
        }

        @Override
@@ -724,12 +825,12 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
            return null;
        }

        private void ignore(IAppSearchResultCallback callback) throws RemoteException {
            callback.onResult(AppSearchResult.newSuccessfulResult(null));
        private void removeShortcuts() {
            mDocumentMap.clear();
        }

        private void ignore(IAppSearchBatchResultCallback callback) throws RemoteException {
            callback.onResult(new AppSearchBatchResult.Builder().build());
        private void ignore(IAppSearchResultCallback callback) throws RemoteException {
            callback.onResult(AppSearchResult.newSuccessfulResult(null));
        }
    }

@@ -1146,6 +1247,9 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {

        shutdownServices();

        mMockAppSearchManager.removeShortcuts();
        mMockAppSearchManager = null;

        super.tearDown();
    }

@@ -1891,6 +1995,11 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        return mService.getPackageShortcutForTest(packageName, shortcutId, userId);
    }

    protected void updatePackageShortcut(String packageName, String shortcutId, int userId,
            Consumer<ShortcutInfo> cb) {
        mService.updatePackageShortcutForTest(packageName, shortcutId, userId, cb);
    }

    protected void assertShortcutExists(String packageName, String shortcutId, int userId) {
        assertTrue(getPackageShortcut(packageName, shortcutId, userId) != null);
    }
@@ -2086,6 +2195,10 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        return getPackageShortcut(getCallingPackage(), shortcutId, getCallingUserId());
    }

    protected void updateCallerShortcut(String shortcutId, Consumer<ShortcutInfo> cb) {
        updatePackageShortcut(getCallingPackage(), shortcutId, getCallingUserId(), cb);
    }

    protected List<ShortcutInfo> getLauncherShortcuts(String launcher, int userId, int queryFlags) {
        final List<ShortcutInfo>[] ret = new List[1];
        runWithCaller(launcher, userId, () -> {
@@ -2245,6 +2358,8 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {

        deleteAllSavedFiles();

        mMockAppSearchManager.removeShortcuts();

        initService();
        mService.applyRestore(payload, USER_0);

Loading