Merge "Add GlobalSearchSession to AppSearch platform."
This commit is contained in:
@@ -140,6 +140,25 @@ public class AppSearchManager {
|
||||
AppSearchSession.createSearchSession(searchContext, mService, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link GlobalSearchSession}.
|
||||
*
|
||||
* <p>This process requires an AppSearch native indexing file system for each user. If it's not
|
||||
* created for this user, the initialization process will create one under user's directory.
|
||||
*
|
||||
* @param executor Executor on which to invoke the callback.
|
||||
* @param callback The {@link AppSearchResult}<{@link GlobalSearchSession}> of
|
||||
* performing this operation. Or a {@link AppSearchResult} with failure
|
||||
* reason code and error information.
|
||||
*/
|
||||
public void createGlobalSearchSession(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
|
||||
Objects.requireNonNull(executor);
|
||||
Objects.requireNonNull(callback);
|
||||
GlobalSearchSession.createGlobalSearchSession(mService, executor, callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the schema being used by documents provided to the {@link #putDocuments} method.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.app.appsearch;
|
||||
|
||||
|
||||
import android.annotation.CallbackExecutor;
|
||||
import android.annotation.NonNull;
|
||||
import android.os.RemoteException;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* This class provides global access to the centralized AppSearch index maintained by the system.
|
||||
*
|
||||
* <p>Apps can retrieve indexed documents through the query API.
|
||||
* @hide
|
||||
*/
|
||||
public class GlobalSearchSession {
|
||||
|
||||
private final IAppSearchManager mService;
|
||||
|
||||
static void createGlobalSearchSession(
|
||||
@NonNull IAppSearchManager service,
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
|
||||
GlobalSearchSession globalSearchSession = new GlobalSearchSession(service);
|
||||
globalSearchSession.initialize(executor, callback);
|
||||
}
|
||||
|
||||
// NOTE: No instance of this class should be created or returned except via initialize().
|
||||
// Once the callback.accept has been called here, the class is ready to use.
|
||||
private void initialize(
|
||||
@NonNull @CallbackExecutor Executor executor,
|
||||
@NonNull Consumer<AppSearchResult<GlobalSearchSession>> callback) {
|
||||
try {
|
||||
mService.initialize(new IAppSearchResultCallback.Stub() {
|
||||
public void onResult(AppSearchResult result) {
|
||||
executor.execute(() -> {
|
||||
if (result.isSuccess()) {
|
||||
callback.accept(
|
||||
AppSearchResult.newSuccessfulResult(GlobalSearchSession.this));
|
||||
} else {
|
||||
callback.accept(result);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch (RemoteException e) {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
private GlobalSearchSession(@NonNull IAppSearchManager service) {
|
||||
mService = service;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches across all documents in the storage based on a given query string.
|
||||
*
|
||||
* <p>Currently we support following features in the raw query format:
|
||||
* <ul>
|
||||
* <li>AND
|
||||
* <p>AND joins (e.g. “match documents that have both the terms ‘dog’ and
|
||||
* ‘cat’”).
|
||||
* Example: hello world matches documents that have both ‘hello’ and ‘world’
|
||||
* <li>OR
|
||||
* <p>OR joins (e.g. “match documents that have either the term ‘dog’ or
|
||||
* ‘cat’”).
|
||||
* Example: dog OR puppy
|
||||
* <li>Exclusion
|
||||
* <p>Exclude a term (e.g. “match documents that do
|
||||
* not have the term ‘dog’”).
|
||||
* Example: -dog excludes the term ‘dog’
|
||||
* <li>Grouping terms
|
||||
* <p>Allow for conceptual grouping of subqueries to enable hierarchical structures (e.g.
|
||||
* “match documents that have either ‘dog’ or ‘puppy’, and either ‘cat’ or ‘kitten’”).
|
||||
* Example: (dog puppy) (cat kitten) two one group containing two terms.
|
||||
* <li>Property restricts
|
||||
* <p> Specifies which properties of a document to specifically match terms in (e.g.
|
||||
* “match documents where the ‘subject’ property contains ‘important’”).
|
||||
* Example: subject:important matches documents with the term ‘important’ in the
|
||||
* ‘subject’ property
|
||||
* <li>Schema type restricts
|
||||
* <p>This is similar to property restricts, but allows for restricts on top-level document
|
||||
* fields, such as schema_type. Clients should be able to limit their query to documents of
|
||||
* a certain schema_type (e.g. “match documents that are of the ‘Email’ schema_type”).
|
||||
* Example: { schema_type_filters: “Email”, “Video”,query: “dog” } will match documents
|
||||
* that contain the query term ‘dog’ and are of either the ‘Email’ schema type or the
|
||||
* ‘Video’ schema type.
|
||||
* </ul>
|
||||
*
|
||||
* <p> This method is lightweight. The heavy work will be done in
|
||||
* {@link SearchResults#getNextPage}.
|
||||
*
|
||||
* @param queryExpression Query String to search.
|
||||
* @param searchSpec Spec for setting filters, raw query etc.
|
||||
* @param executor Executor on which to invoke the callback of the following request
|
||||
* {@link SearchResults#getNextPage}.
|
||||
* @return The search result of performing this operation.
|
||||
*/
|
||||
@NonNull
|
||||
public SearchResults globalQuery(
|
||||
@NonNull String queryExpression,
|
||||
@NonNull SearchSpec searchSpec,
|
||||
@NonNull @CallbackExecutor Executor executor) {
|
||||
Objects.requireNonNull(queryExpression);
|
||||
Objects.requireNonNull(searchSpec);
|
||||
Objects.requireNonNull(executor);
|
||||
return new SearchResults(mService, /*databaseName=*/null, queryExpression,
|
||||
searchSpec, executor);
|
||||
}
|
||||
}
|
||||
@@ -94,6 +94,20 @@ interface IAppSearchManager {
|
||||
in Bundle searchSpecBundle,
|
||||
in IAppSearchResultCallback callback);
|
||||
|
||||
/**
|
||||
* Executes a global query, i.e. over all permitted databases, against the AppSearch index and
|
||||
* returns results.
|
||||
*
|
||||
* @param queryExpression String to search for
|
||||
* @param searchSpecBundle SearchSpec bundle
|
||||
* @param callback {@link AppSearchResult}<{@link Bundle}> of performing this
|
||||
* operation.
|
||||
*/
|
||||
void globalQuery(
|
||||
in String queryExpression,
|
||||
in Bundle searchSpecBundle,
|
||||
in IAppSearchResultCallback callback);
|
||||
|
||||
/**
|
||||
* Fetches the next page of results of a previously executed query. Results can be empty if
|
||||
* next-page token is invalid or all pages have been returned.
|
||||
|
||||
@@ -85,23 +85,18 @@ public class SearchResults implements Closeable {
|
||||
try {
|
||||
if (mIsFirstLoad) {
|
||||
mIsFirstLoad = false;
|
||||
//TODO(b/162450968) add support for global query.
|
||||
mService.query(mDatabaseName, mQueryExpression, mSearchSpec.getBundle(),
|
||||
new IAppSearchResultCallback.Stub() {
|
||||
public void onResult(AppSearchResult result) {
|
||||
mExecutor.execute(() -> invokeCallback(result, callback));
|
||||
}
|
||||
});
|
||||
if (mDatabaseName == null) {
|
||||
mService.globalQuery(mQueryExpression, mSearchSpec.getBundle(),
|
||||
wrapCallback(callback));
|
||||
} else {
|
||||
mService.query(mDatabaseName, mQueryExpression, mSearchSpec.getBundle(),
|
||||
wrapCallback(callback));
|
||||
}
|
||||
} else {
|
||||
mService.getNextPage(mNextPageToken,
|
||||
new IAppSearchResultCallback.Stub() {
|
||||
public void onResult(AppSearchResult result) {
|
||||
mExecutor.execute(() -> invokeCallback(result, callback));
|
||||
}
|
||||
});
|
||||
mService.getNextPage(mNextPageToken, wrapCallback(callback));
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
e.rethrowFromSystemServer();
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,4 +126,13 @@ public class SearchResults implements Closeable {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private IAppSearchResultCallback wrapCallback(
|
||||
@NonNull Consumer<AppSearchResult<List<SearchResult>>> callback) {
|
||||
return new IAppSearchResultCallback.Stub() {
|
||||
public void onResult(AppSearchResult result) {
|
||||
mExecutor.execute(() -> invokeCallback(result, callback));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
@NonNull IAppSearchResultCallback callback) {
|
||||
Preconditions.checkNotNull(databaseName);
|
||||
Preconditions.checkNotNull(schemaBundles);
|
||||
Preconditions.checkNotNull(callback);
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
@@ -166,6 +167,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
Preconditions.checkNotNull(databaseName);
|
||||
Preconditions.checkNotNull(queryExpression);
|
||||
Preconditions.checkNotNull(searchSpecBundle);
|
||||
Preconditions.checkNotNull(callback);
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
@@ -185,9 +187,34 @@ public class AppSearchManagerService extends SystemService {
|
||||
}
|
||||
}
|
||||
|
||||
public void globalQuery(
|
||||
@NonNull String queryExpression,
|
||||
@NonNull Bundle searchSpecBundle,
|
||||
@NonNull IAppSearchResultCallback callback) {
|
||||
Preconditions.checkNotNull(queryExpression);
|
||||
Preconditions.checkNotNull(searchSpecBundle);
|
||||
Preconditions.checkNotNull(callback);
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
try {
|
||||
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
|
||||
SearchResultPage searchResultPage = impl.globalQuery(
|
||||
queryExpression,
|
||||
new SearchSpec(searchSpecBundle));
|
||||
invokeCallbackOnResult(callback,
|
||||
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
|
||||
} catch (Throwable t) {
|
||||
invokeCallbackOnError(callback, t);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(callingIdentity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getNextPage(long nextPageToken,
|
||||
@NonNull IAppSearchResultCallback callback) {
|
||||
Preconditions.checkNotNull(callback);
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
@@ -261,6 +288,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
Preconditions.checkNotNull(databaseName);
|
||||
Preconditions.checkNotNull(queryExpression);
|
||||
Preconditions.checkNotNull(searchSpecBundle);
|
||||
Preconditions.checkNotNull(callback);
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
@@ -279,6 +307,7 @@ public class AppSearchManagerService extends SystemService {
|
||||
|
||||
@Override
|
||||
public void initialize(@NonNull IAppSearchResultCallback callback) {
|
||||
Preconditions.checkNotNull(callback);
|
||||
int callingUid = Binder.getCallingUidOrThrow();
|
||||
int callingUserId = UserHandle.getUserId(callingUid);
|
||||
final long callingIdentity = Binder.clearCallingIdentity();
|
||||
|
||||
Reference in New Issue
Block a user