summaryrefslogtreecommitdiff
path: root/apex
diff options
context:
space:
mode:
Diffstat (limited to 'apex')
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java48
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl35
-rw-r--r--apex/appsearch/framework/java/android/app/appsearch/SearchResultPage.java78
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java116
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java414
-rw-r--r--apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java21
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobParameters.java4
-rw-r--r--apex/jobscheduler/framework/java/android/app/job/JobScheduler.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java2
-rw-r--r--apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java3
-rw-r--r--apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java9
-rw-r--r--apex/permission/Android.bp2
-rw-r--r--apex/statsd/Android.bp2
13 files changed, 385 insertions, 352 deletions
diff --git a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
index 18bc59b91aa0..f2c9942edbb3 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
+++ b/apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java
@@ -267,14 +267,14 @@ public class AppSearchManager {
searchResultsFuture.completeExceptionally(e);
}
- // Translate the list of Bundle into a list of SearchResult
- AppSearchResult<SearchResults> searchResultsResult = getFutureOrThrow(searchResultsFuture);
- if (!searchResultsResult.isSuccess()) {
- return AppSearchResult.newFailedResult(
- searchResultsResult.getResultCode(), searchResultsResult.getErrorMessage());
+ // Translate the Bundle into a searchResultPage.
+ AppSearchResult<Bundle> bundleResult = getFutureOrThrow(searchResultsFuture);
+ if (!bundleResult.isSuccess()) {
+ return AppSearchResult.newFailedResult(bundleResult.getResultCode(),
+ bundleResult.getErrorMessage());
}
- SearchResults searchResults = searchResultsResult.getResultValue();
- return AppSearchResult.newSuccessfulResult(searchResults.mResults);
+ SearchResultPage searchResultPage = new SearchResultPage(bundleResult.getResultValue());
+ return AppSearchResult.newSuccessfulResult(searchResultPage.getResults());
}
/**
@@ -294,39 +294,7 @@ public class AppSearchManager {
List<String> uris = new ArrayList<>(request.getUris());
AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
try {
- mService.delete(DEFAULT_DATABASE, request.getNamespace(), uris, future);
- } catch (RemoteException e) {
- future.completeExceptionally(e);
- }
- return getFutureOrThrow(future);
- }
-
- /**
- * Deletes {@link android.app.appsearch.GenericDocument}s by schema type.
- *
- * <p>You should not call this method directly; instead, use the
- * {@code AppSearch#deleteByType()} API provided by JetPack.
- *
- * @param schemaTypes Schema types whose documents to delete.
- * @return An {@link AppSearchBatchResult} mapping each schema type to a {@code null} success if
- * deletion was successful, to a {@code null} failure if the type did not exist, or to a
- * {@code throwable} failure if deletion failed for another reason.
- */
- public AppSearchBatchResult<String, Void> deleteByTypes(@NonNull List<String> schemaTypes) {
- AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>();
- try {
- mService.deleteByTypes(DEFAULT_DATABASE, schemaTypes, future);
- } catch (RemoteException e) {
- future.completeExceptionally(e);
- }
- return getFutureOrThrow(future);
- }
-
- /** Deletes all documents owned by the calling app. */
- public AppSearchResult<Void> deleteAll() {
- AndroidFuture<AppSearchResult> future = new AndroidFuture<>();
- try {
- mService.deleteAll(DEFAULT_DATABASE, future);
+ mService.removeByUri(DEFAULT_DATABASE, request.getNamespace(), uris, future);
} catch (RemoteException e) {
future.completeExceptionally(e);
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
index 352a980eef27..01260ea193f6 100644
--- a/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
+++ b/apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl
@@ -92,7 +92,7 @@ interface IAppSearchManager {
in AndroidFuture<AppSearchResult> callback);
/**
- * Deletes documents by URI.
+ * Removes documents by URI.
*
* @param databaseName The databaseName the document is in.
* @param namespace Namespace of the document to remove.
@@ -105,36 +105,23 @@ interface IAppSearchManager {
* where the keys are document URIs. If a document doesn't exist, it will be reported as a
* failure where the {@code throwable} is {@code null}.
*/
- void delete(
+ void removeByUri(
in String databaseName,
in String namespace,
in List<String> uris,
in AndroidFuture<AppSearchBatchResult> callback);
/**
- * Deletes documents by schema type.
+ * Removes documents by given query.
*
- * @param databaseName The databaseName the document is in.
- * @param schemaTypes The schema types of the documents to delete
- * @param callback
- * {@link AndroidFuture}&lt;{@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;&gt;.
- * If the call fails to start, {@code callback} will be completed exceptionally. Otherwise,
- * {@code callback} will be completed with an
- * {@link AppSearchBatchResult}&lt;{@link String}, {@link Void}&gt;
- * where the keys are schema types. If a schema type doesn't exist, it will be reported as a
- * failure where the {@code throwable} is {@code null}.
+ * @param databaseName The databaseName this query for.
+ * @param queryExpression String to search for
+ * @param searchSpecBundle SearchSpec bundle
+ * @param callback {@link AndroidFuture}&lt;{@link AppSearchResult}&lt;{@link SearchResults}&gt;&gt;
*/
- void deleteByTypes(
+ void removeByQuery(
in String databaseName,
- in List<String> schemaTypes,
- in AndroidFuture<AppSearchBatchResult> callback);
-
- /**
- * Deletes all documents belonging to the calling app.
- *
- * @param databaseName The databaseName to remove all documents from.
- * @param callback {@link AndroidFuture}&lt;{@link AppSearchResult}&lt;{@link Void}&gt;&gt;.
- * Will be completed with the result of the call.
- */
- void deleteAll(in String databaseName, in AndroidFuture<AppSearchResult> callback);
+ in String queryExpression,
+ in Bundle searchSpecBundle,
+ in AndroidFuture<AppSearchResult> callback);
}
diff --git a/apex/appsearch/framework/java/android/app/appsearch/SearchResultPage.java b/apex/appsearch/framework/java/android/app/appsearch/SearchResultPage.java
new file mode 100644
index 000000000000..756d1b5d673f
--- /dev/null
+++ b/apex/appsearch/framework/java/android/app/appsearch/SearchResultPage.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright 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.os.Bundle;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class represents a page of {@link SearchResult}s
+ * @hide
+ */
+
+public class SearchResultPage {
+ public static final String RESULTS_FIELD = "results";
+ public static final String NEXT_PAGE_TOKEN_FIELD = "nextPageToken";
+ private final long mNextPageToken;
+
+ @Nullable
+ private List<SearchResult> mResults;
+
+ @NonNull
+ private final Bundle mBundle;
+
+ public SearchResultPage(@NonNull Bundle bundle) {
+ mBundle = Preconditions.checkNotNull(bundle);
+ mNextPageToken = mBundle.getLong(NEXT_PAGE_TOKEN_FIELD);
+ }
+
+ /** Returns the {@link Bundle} of this class. */
+ @NonNull
+ public Bundle getBundle() {
+ return mBundle;
+ }
+
+ /** Returns the Token to get next {@link SearchResultPage}. */
+ public long getNextPageToken() {
+ return mNextPageToken;
+ }
+
+ /** Returns all {@link android.app.appsearch.SearchResult}s of this page */
+ @NonNull
+ public List<SearchResult> getResults() {
+ if (mResults == null) {
+ ArrayList<Bundle> resultBundles = mBundle.getParcelableArrayList(RESULTS_FIELD);
+ if (resultBundles == null) {
+ mResults = Collections.emptyList();
+ } else {
+ mResults = new ArrayList<>(resultBundles.size());
+ for (int i = 0; i < resultBundles.size(); i++) {
+ mResults.add(new SearchResult(resultBundles.get(i)));
+ }
+ }
+ }
+ return mResults;
+ }
+}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index f2830e5b8e6d..1dfde528e69b 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -21,33 +21,23 @@ import android.app.appsearch.AppSearchResult;
import android.app.appsearch.AppSearchSchema;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.IAppSearchManager;
-import android.app.appsearch.SearchResult;
-import android.app.appsearch.SearchResults;
+import android.app.appsearch.SearchResultPage;
import android.app.appsearch.SearchSpec;
import android.app.appsearch.exceptions.AppSearchException;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.os.UserHandle;
+import android.util.ArraySet;
import com.android.internal.infra.AndroidFuture;
import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
import com.android.server.appsearch.external.localstorage.AppSearchImpl;
-import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
-import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
-import com.android.server.appsearch.external.localstorage.converter.SearchResultToProtoConverter;
-import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;
-
-import com.google.android.icing.proto.DocumentProto;
-import com.google.android.icing.proto.SchemaProto;
-import com.google.android.icing.proto.SchemaTypeConfigProto;
-import com.google.android.icing.proto.SearchResultProto;
-import com.google.android.icing.proto.SearchSpecProto;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
+import java.util.Set;
/**
* TODO(b/142567528): add comments when implement this class
@@ -72,21 +62,20 @@ public class AppSearchManagerService extends SystemService {
@NonNull List<Bundle> schemaBundles,
boolean forceOverride,
@NonNull AndroidFuture<AppSearchResult> callback) {
+ Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(schemaBundles);
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- SchemaProto.Builder schemaProtoBuilder = SchemaProto.newBuilder();
+ Set<AppSearchSchema> schemas = new ArraySet<>(schemaBundles.size());
for (int i = 0; i < schemaBundles.size(); i++) {
- AppSearchSchema schema = new AppSearchSchema(schemaBundles.get(i));
- SchemaTypeConfigProto schemaTypeProto = SchemaToProtoConverter.convert(schema);
- schemaProtoBuilder.addTypes(schemaTypeProto);
+ schemas.add(new AppSearchSchema(schemaBundles.get(i)));
}
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
- impl.setSchema(databaseName, schemaProtoBuilder.build(), forceOverride);
+ impl.setSchema(databaseName, schemas, forceOverride);
callback.complete(AppSearchResult.newSuccessfulResult(/*result=*/ null));
} catch (Throwable t) {
callback.complete(throwableToFailedResult(t));
@@ -100,6 +89,7 @@ public class AppSearchManagerService extends SystemService {
@NonNull String databaseName,
@NonNull List<Bundle> documentBundles,
@NonNull AndroidFuture<AppSearchBatchResult> callback) {
+ Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(documentBundles);
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
@@ -112,9 +102,8 @@ public class AppSearchManagerService extends SystemService {
new AppSearchBatchResult.Builder<>();
for (int i = 0; i < documentBundles.size(); i++) {
GenericDocument document = new GenericDocument(documentBundles.get(i));
- DocumentProto documentProto = GenericDocumentToProtoConverter.convert(document);
try {
- impl.putDocument(databaseName, documentProto);
+ impl.putDocument(databaseName, document);
resultBuilder.setSuccess(document.getUri(), /*result=*/ null);
} catch (Throwable t) {
resultBuilder.setResult(document.getUri(), throwableToFailedResult(t));
@@ -131,6 +120,8 @@ public class AppSearchManagerService extends SystemService {
@Override
public void getDocuments(@NonNull String databaseName, @NonNull String namespace,
@NonNull List<String> uris, @NonNull AndroidFuture<AppSearchBatchResult> callback) {
+ Preconditions.checkNotNull(databaseName);
+ Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(uris);
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
@@ -144,16 +135,8 @@ public class AppSearchManagerService extends SystemService {
for (int i = 0; i < uris.size(); i++) {
String uri = uris.get(i);
try {
- DocumentProto documentProto = impl.getDocument(
- databaseName, namespace, uri);
- if (documentProto == null) {
- resultBuilder.setFailure(
- uri, AppSearchResult.RESULT_NOT_FOUND, /*errorMessage=*/ null);
- } else {
- GenericDocument genericDocument =
- GenericDocumentToProtoConverter.convert(documentProto);
- resultBuilder.setSuccess(uri, genericDocument.getBundle());
- }
+ GenericDocument document = impl.getDocument(databaseName, namespace, uri);
+ resultBuilder.setSuccess(uri, document.getBundle());
} catch (Throwable t) {
resultBuilder.setResult(uri, throwableToFailedResult(t));
}
@@ -167,12 +150,14 @@ public class AppSearchManagerService extends SystemService {
}
// TODO(sidchhabra): Do this in a threadpool.
+ // TODO(b/162450968) handle pagination after getNextPage and SearchResults is ready.
@Override
public void query(
@NonNull String databaseName,
@NonNull String queryExpression,
@NonNull Bundle searchSpecBundle,
@NonNull AndroidFuture<AppSearchResult> callback) {
+ Preconditions.checkNotNull(databaseName);
Preconditions.checkNotNull(queryExpression);
Preconditions.checkNotNull(searchSpecBundle);
Preconditions.checkNotNull(callback);
@@ -180,29 +165,14 @@ public class AppSearchManagerService extends SystemService {
int callingUserId = UserHandle.getUserId(callingUid);
final long callingIdentity = Binder.clearCallingIdentity();
try {
- SearchSpec searchSpec = new SearchSpec(searchSpecBundle);
- SearchSpecProto searchSpecProto =
- SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
- searchSpecProto = searchSpecProto.toBuilder()
- .setQuery(queryExpression).build();
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
- // TODO(adorokhine): handle pagination
- SearchResultProto searchResultProto = impl.query(
+ SearchResultPage searchResultPage = impl.query(
databaseName,
- searchSpecProto,
- SearchSpecToProtoConverter.toResultSpecProto(searchSpec),
- SearchSpecToProtoConverter.toScoringSpecProto(searchSpec));
- List<SearchResult> searchResultList =
- new ArrayList<>(searchResultProto.getResultsCount());
- for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
- SearchResult result = SearchResultToProtoConverter.convertSearchResult(
- searchResultProto.getResults(i));
- searchResultList.add(result);
- }
- SearchResults searchResults =
- new SearchResults(searchResultList, searchResultProto.getNextPageToken());
- callback.complete(AppSearchResult.newSuccessfulResult(searchResults));
+ queryExpression,
+ new SearchSpec(searchSpecBundle));
+ callback.complete(
+ AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
} catch (Throwable t) {
callback.complete(throwableToFailedResult(t));
} finally {
@@ -211,8 +181,10 @@ public class AppSearchManagerService extends SystemService {
}
@Override
- public void delete(@NonNull String databaseName, @NonNull String namespace,
+ public void removeByUri(@NonNull String databaseName, @NonNull String namespace,
List<String> uris, AndroidFuture<AppSearchBatchResult> callback) {
+ Preconditions.checkNotNull(databaseName);
+ Preconditions.checkNotNull(namespace);
Preconditions.checkNotNull(uris);
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
@@ -241,38 +213,14 @@ public class AppSearchManagerService extends SystemService {
}
@Override
- public void deleteByTypes(@NonNull String databaseName,
- List<String> schemaTypes, AndroidFuture<AppSearchBatchResult> callback) {
- Preconditions.checkNotNull(schemaTypes);
- Preconditions.checkNotNull(callback);
- int callingUid = Binder.getCallingUidOrThrow();
- int callingUserId = UserHandle.getUserId(callingUid);
- final long callingIdentity = Binder.clearCallingIdentity();
- try {
- AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
- databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
- AppSearchBatchResult.Builder<String, Void> resultBuilder =
- new AppSearchBatchResult.Builder<>();
- for (int i = 0; i < schemaTypes.size(); i++) {
- String schemaType = schemaTypes.get(i);
- try {
- impl.removeByType(databaseName, schemaType);
- resultBuilder.setSuccess(schemaType, /*result=*/ null);
- } catch (Throwable t) {
- resultBuilder.setResult(schemaType, throwableToFailedResult(t));
- }
- }
- callback.complete(resultBuilder.build());
- } catch (Throwable t) {
- callback.completeExceptionally(t);
- } finally {
- Binder.restoreCallingIdentity(callingIdentity);
- }
- }
-
- @Override
- public void deleteAll(@NonNull String databaseName,
+ public void removeByQuery(
+ @NonNull String databaseName,
+ @NonNull String queryExpression,
+ @NonNull Bundle searchSpecBundle,
@NonNull AndroidFuture<AppSearchResult> callback) {
+ Preconditions.checkNotNull(databaseName);
+ Preconditions.checkNotNull(queryExpression);
+ Preconditions.checkNotNull(searchSpecBundle);
Preconditions.checkNotNull(callback);
int callingUid = Binder.getCallingUidOrThrow();
int callingUserId = UserHandle.getUserId(callingUid);
@@ -280,8 +228,8 @@ public class AppSearchManagerService extends SystemService {
try {
AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId);
databaseName = rewriteDatabaseNameWithUid(databaseName, callingUid);
- impl.removeAll(databaseName);
- callback.complete(AppSearchResult.newSuccessfulResult(null));
+ impl.removeByQuery(databaseName, queryExpression, new SearchSpec(searchSpecBundle));
+ callback.complete(AppSearchResult.newSuccessfulResult(/*result= */null));
} catch (Throwable t) {
callback.complete(throwableToFailedResult(t));
} finally {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index b1a79f84714d..e021544976b5 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -16,21 +16,27 @@
package com.android.server.appsearch.external.localstorage;
+import android.os.Bundle;
import android.util.Log;
import com.android.internal.annotations.GuardedBy;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import com.android.internal.annotations.VisibleForTesting;
import android.annotation.WorkerThread;
import android.app.appsearch.AppSearchResult;
+import android.app.appsearch.AppSearchSchema;
+import android.app.appsearch.GenericDocument;
+import android.app.appsearch.SearchResultPage;
+import android.app.appsearch.SearchSpec;
import android.app.appsearch.exceptions.AppSearchException;
import com.android.internal.util.Preconditions;
+import com.android.server.appsearch.external.localstorage.converter.GenericDocumentToProtoConverter;
+import com.android.server.appsearch.external.localstorage.converter.SchemaToProtoConverter;
+import com.android.server.appsearch.external.localstorage.converter.SearchResultToProtoConverter;
+import com.android.server.appsearch.external.localstorage.converter.SearchSpecToProtoConverter;
import com.google.android.icing.IcingSearchEngine;
-import com.google.android.icing.proto.DeleteByNamespaceResultProto;
-import com.google.android.icing.proto.DeleteBySchemaTypeResultProto;
import com.google.android.icing.proto.DeleteResultProto;
import com.google.android.icing.proto.DocumentProto;
import com.google.android.icing.proto.GetAllNamespacesResultProto;
@@ -54,8 +60,10 @@ import com.google.android.icing.proto.SetSchemaResultProto;
import com.google.android.icing.proto.StatusProto;
import java.io.File;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReadWriteLock;
@@ -89,12 +97,14 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* </ul>
*
* <p>This class is thread safe.
+ *
* @hide
*/
@WorkerThread
public final class AppSearchImpl {
private static final String TAG = "AppSearchImpl";
+ private static final char DATABASE_DELIMITER = '/';
@VisibleForTesting
static final int OPTIMIZE_THRESHOLD_DOC_COUNT = 1000;
@@ -173,20 +183,27 @@ public final class AppSearchImpl {
* <p>This method belongs to mutate group.
*
* @param databaseName The name of the database where this schema lives.
- * @param origSchema The schema to set for this app.
+ * @param schemas Schemas to set for this app.
* @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
* which do not comply with the new schema will be deleted.
* @throws AppSearchException on IcingSearchEngine error.
*/
- public void setSchema(@NonNull String databaseName, @NonNull SchemaProto origSchema,
+ public void setSchema(@NonNull String databaseName, @NonNull Set<AppSearchSchema> schemas,
boolean forceOverride) throws AppSearchException {
SchemaProto schemaProto = getSchemaProto();
SchemaProto.Builder existingSchemaBuilder = schemaProto.toBuilder();
+ SchemaProto.Builder newSchemaBuilder = SchemaProto.newBuilder();
+ for (AppSearchSchema schema : schemas) {
+ SchemaTypeConfigProto schemaTypeProto = SchemaToProtoConverter.convert(schema);
+ newSchemaBuilder.addTypes(schemaTypeProto);
+ }
+
// Combine the existing schema (which may have types from other databases) with this
// database's new schema. Modifies the existingSchemaBuilder.
- Set<String> newTypeNames = rewriteSchema(databaseName, existingSchemaBuilder, origSchema);
+ Set<String> newTypeNames = rewriteSchema(databaseName, existingSchemaBuilder,
+ newSchemaBuilder.build());
SetSchemaResultProto setSchemaResultProto;
mReadWriteLock.writeLock().lock();
@@ -220,7 +237,7 @@ public final class AppSearchImpl {
if (setSchemaResultProto.getDeletedSchemaTypesCount() > 0
|| (setSchemaResultProto.getIncompatibleSchemaTypesCount() > 0
&& forceOverride)) {
- // Any existing schemas which is not in origSchema will be deleted, and all
+ // Any existing schemas which is not in 'schemas' will be deleted, and all
// documents of these types were also deleted. And so well if we force override
// incompatible schemas.
checkForOptimize(/* force= */true);
@@ -239,10 +256,11 @@ public final class AppSearchImpl {
* @param document The document to index.
* @throws AppSearchException on IcingSearchEngine error.
*/
- public void putDocument(@NonNull String databaseName, @NonNull DocumentProto document)
+ public void putDocument(@NonNull String databaseName, @NonNull GenericDocument document)
throws AppSearchException {
- DocumentProto.Builder documentBuilder = document.toBuilder();
- rewriteDocumentTypes(getDatabasePrefix(databaseName), documentBuilder, /*add=*/ true);
+ DocumentProto.Builder documentBuilder = GenericDocumentToProtoConverter.convert(
+ document).toBuilder();
+ addPrefixToDocument(documentBuilder, getDatabasePrefix(databaseName));
PutResultProto putResultProto;
mReadWriteLock.writeLock().lock();
@@ -266,11 +284,11 @@ public final class AppSearchImpl {
* @param databaseName The databaseName this document resides in.
* @param namespace The namespace this document resides in.
* @param uri The URI of the document to get.
- * @return The Document contents, or {@code null} if no such URI exists in the system.
+ * @return The Document contents
* @throws AppSearchException on IcingSearchEngine error.
*/
- @Nullable
- public DocumentProto getDocument(@NonNull String databaseName, @NonNull String namespace,
+ @NonNull
+ public GenericDocument getDocument(@NonNull String databaseName, @NonNull String namespace,
@NonNull String uri) throws AppSearchException {
GetResultProto getResultProto;
mReadWriteLock.readLock().lock();
@@ -283,8 +301,8 @@ public final class AppSearchImpl {
checkSuccess(getResultProto.getStatus());
DocumentProto.Builder documentBuilder = getResultProto.getDocument().toBuilder();
- rewriteDocumentTypes(getDatabasePrefix(databaseName), documentBuilder, /*add=*/ false);
- return documentBuilder.build();
+ removeDatabasesFromDocument(documentBuilder);
+ return GenericDocumentToProtoConverter.convert(documentBuilder.build());
}
/**
@@ -292,33 +310,60 @@ public final class AppSearchImpl {
*
* <p>This method belongs to query group.
*
- * @param databaseName The databaseName this query for.
- * @param searchSpec Defines what and how to search
- * @param resultSpec Defines what results to show
- * @param scoringSpec Defines how to order results
- * @return The results of performing this search The proto might have no {@code results} if no
- * documents matched the query.
+ * @param databaseName The databaseName this query for.
+ * @param queryExpression Query String to search.
+ * @param searchSpec Spec for setting filters, raw query etc.
+ * @return The results of performing this search. It may contain an empty list of results if
+ * no documents matched the query.
* @throws AppSearchException on IcingSearchEngine error.
*/
@NonNull
- public SearchResultProto query(
+ public SearchResultPage query(
@NonNull String databaseName,
- @NonNull SearchSpecProto searchSpec,
- @NonNull ResultSpecProto resultSpec,
- @NonNull ScoringSpecProto scoringSpec) throws AppSearchException {
- SearchSpecProto.Builder searchSpecBuilder = searchSpec.toBuilder();
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec) throws AppSearchException {
+ return doQuery(Collections.singleton(databaseName), queryExpression, searchSpec);
+ }
+
+ /**
+ * Executes a global query, i.e. over all permitted databases, against the AppSearch index and
+ * returns results.
+ *
+ * <p>This method belongs to query group.
+ *
+ * @param queryExpression Query String to search.
+ * @param searchSpec Spec for setting filters, raw query etc.
+ * @return The results of performing this search. It may contain an empty list of results if
+ * no documents matched the query.
+ * @throws AppSearchException on IcingSearchEngine error.
+ */
+ @NonNull
+ public SearchResultPage globalQuery(
+ @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec) throws AppSearchException {
+ return doQuery(mNamespaceMap.keySet(), queryExpression, searchSpec);
+ }
+
+ private SearchResultPage doQuery(
+ @NonNull Set<String> databases, @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec)
+ throws AppSearchException {
+ SearchSpecProto searchSpecProto =
+ SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
+ SearchSpecProto.Builder searchSpecBuilder = searchSpecProto.toBuilder()
+ .setQuery(queryExpression);
+
+ ResultSpecProto resultSpec = SearchSpecToProtoConverter.toResultSpecProto(searchSpec);
+ ScoringSpecProto scoringSpec = SearchSpecToProtoConverter.toScoringSpecProto(searchSpec);
SearchResultProto searchResultProto;
mReadWriteLock.readLock().lock();
try {
- // Only rewrite SearchSpec for non empty database.
- // rewriteSearchSpecForNonEmptyDatabase will return false for empty database, we
- // should just return an empty SearchResult and skip sending request to Icing.
- if (!rewriteSearchSpecForNonEmptyDatabase(databaseName, searchSpecBuilder)) {
- return SearchResultProto.newBuilder()
- .setStatus(StatusProto.newBuilder()
- .setCode(StatusProto.Code.OK)
- .build())
- .build();
+ // rewriteSearchSpecForDatabases will return false if none of the databases have
+ // documents, so we can return an empty SearchResult and skip sending request to Icing.
+ // We use the mNamespaceMap.keySet here because it's the smaller set of valid databases
+ // that could exist.
+ if (!rewriteSearchSpecForDatabases(searchSpecBuilder, databases)) {
+ return new SearchResultPage(Bundle.EMPTY);
}
searchResultProto = mIcingSearchEngine.search(
searchSpecBuilder.build(), scoringSpec, resultSpec);
@@ -326,34 +371,32 @@ public final class AppSearchImpl {
mReadWriteLock.readLock().unlock();
}
checkSuccess(searchResultProto.getStatus());
- if (searchResultProto.getResultsCount() == 0) {
- return searchResultProto;
- }
- return rewriteSearchResultProto(databaseName, searchResultProto);
+ return rewriteSearchResultProto(searchResultProto);
}
/**
* 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.
*
- * @param databaseName The databaseName of the previously executed query.
+ * <p>This method belongs to query group.
+ *
* @param nextPageToken The token of pre-loaded results of previously executed query.
* @return The next page of results of previously executed query.
* @throws AppSearchException on IcingSearchEngine error.
*/
@NonNull
- public SearchResultProto getNextPage(@NonNull String databaseName, long nextPageToken)
+ public SearchResultPage getNextPage(long nextPageToken)
throws AppSearchException {
SearchResultProto searchResultProto = mIcingSearchEngine.getNextPage(nextPageToken);
checkSuccess(searchResultProto.getStatus());
- if (searchResultProto.getResultsCount() == 0) {
- return searchResultProto;
- }
- return rewriteSearchResultProto(databaseName, searchResultProto);
+ return rewriteSearchResultProto(searchResultProto);
}
/**
* Invalidates the next-page token so that no more results of the related query can be returned.
+ *
+ * <p>This method belongs to query group.
+ *
* @param nextPageToken The token of pre-loaded results of previously executed query to be
* Invalidated.
*/
@@ -386,93 +429,43 @@ public final class AppSearchImpl {
}
/**
- * Removes all documents having the given {@code schemaType} in given database.
+ * Removes documents by given query.
*
* <p>This method belongs to mutate group.
*
- * @param databaseName The databaseName that contains documents of schemaType.
- * @param schemaType The schemaType of documents to remove.
+ * @param databaseName The databaseName the document is in.
+ * @param queryExpression Query String to search.
+ * @param searchSpec Defines what and how to remove
* @throws AppSearchException on IcingSearchEngine error.
*/
- public void removeByType(@NonNull String databaseName, @NonNull String schemaType)
+ public void removeByQuery(@NonNull String databaseName, @NonNull String queryExpression,
+ @NonNull SearchSpec searchSpec)
throws AppSearchException {
- String qualifiedType = getDatabasePrefix(databaseName) + schemaType;
- DeleteBySchemaTypeResultProto deleteBySchemaTypeResultProto;
- mReadWriteLock.writeLock().lock();
- try {
- Set<String> existingSchemaTypes = mSchemaMap.get(databaseName);
- if (existingSchemaTypes == null || !existingSchemaTypes.contains(qualifiedType)) {
- return;
- }
- deleteBySchemaTypeResultProto = mIcingSearchEngine.deleteBySchemaType(qualifiedType);
- checkForOptimize(/* force= */true);
- } finally {
- mReadWriteLock.writeLock().unlock();
- }
- checkSuccess(deleteBySchemaTypeResultProto.getStatus());
- }
-
- /**
- * Removes all documents having the given {@code namespace} in given database.
- *
- * <p>This method belongs to mutate group.
- *
- * @param databaseName The databaseName that contains documents of namespace.
- * @param namespace The namespace of documents to remove.
- * @throws AppSearchException on IcingSearchEngine error.
- */
- public void removeByNamespace(@NonNull String databaseName, @NonNull String namespace)
- throws AppSearchException {
- String qualifiedNamespace = getDatabasePrefix(databaseName) + namespace;
- DeleteByNamespaceResultProto deleteByNamespaceResultProto;
- mReadWriteLock.writeLock().lock();
- try {
- Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
- if (existingNamespaces == null || !existingNamespaces.contains(qualifiedNamespace)) {
- return;
- }
- deleteByNamespaceResultProto = mIcingSearchEngine.deleteByNamespace(qualifiedNamespace);
- checkForOptimize(/* force= */true);
- } finally {
- mReadWriteLock.writeLock().unlock();
- }
- checkSuccess(deleteByNamespaceResultProto.getStatus());
- }
- /**
- * Clears the given database by removing all documents and types.
- *
- * <p>The schemas will remain. To clear everything including schemas, please call
- * {@link #setSchema} with an empty schema and {@code forceOverride} set to true.
- *
- * <p>This method belongs to mutate group.
- *
- * @param databaseName The databaseName to remove all documents from.
- * @throws AppSearchException on IcingSearchEngine error.
- */
- public void removeAll(@NonNull String databaseName)
- throws AppSearchException {
+ SearchSpecProto searchSpecProto =
+ SearchSpecToProtoConverter.toSearchSpecProto(searchSpec);
+ SearchSpecProto.Builder searchSpecBuilder = searchSpecProto.toBuilder()
+ .setQuery(queryExpression);
+ DeleteResultProto deleteResultProto;
mReadWriteLock.writeLock().lock();
try {
- Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
- if (existingNamespaces == null) {
+ // Only rewrite SearchSpec for non empty database.
+ // rewriteSearchSpecForNonEmptyDatabase will return false for empty database, we
+ // should skip sending request to Icing and return in here.
+ if (!rewriteSearchSpecForDatabases(searchSpecBuilder,
+ Collections.singleton(databaseName))) {
return;
}
- for (String namespace : existingNamespaces) {
- DeleteByNamespaceResultProto deleteByNamespaceResultProto =
- mIcingSearchEngine.deleteByNamespace(namespace);
- // There's no way for AppSearch to know that all documents in a particular
- // namespace have been deleted, but if you try to delete an empty namespace, Icing
- // returns NOT_FOUND. Just ignore that code.
- checkCodeOneOf(
- deleteByNamespaceResultProto.getStatus(),
- StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
- }
- mNamespaceMap.remove(databaseName);
+ deleteResultProto = mIcingSearchEngine.deleteByQuery(
+ searchSpecBuilder.build());
checkForOptimize(/* force= */true);
} finally {
mReadWriteLock.writeLock().unlock();
}
+ // It seems that the caller wants to get success if the data matching the query is not in
+ // the DB because it was not there or was successfully deleted.
+ checkCodeOneOf(deleteResultProto.getStatus(),
+ StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
}
/**
@@ -565,36 +558,63 @@ public final class AppSearchImpl {
}
/**
- * Rewrites all types and namespaces mentioned anywhere in {@code documentBuilder} to prepend
- * or remove {@code prefix}.
+ * Prepends {@code prefix} to all types and namespaces mentioned anywhere in
+ * {@code documentBuilder}.
*
- * @param prefix The prefix to add or remove
* @param documentBuilder The document to mutate
- * @param add Whether to add prefix to the types and namespaces. If {@code false},
- * prefix will be removed.
- * @throws IllegalStateException If {@code add=false} and the document has a type or namespace
- * that doesn't start with {@code prefix}.
+ * @param prefix The prefix to add
*/
@VisibleForTesting
- void rewriteDocumentTypes(
- @NonNull String prefix,
+ void addPrefixToDocument(
@NonNull DocumentProto.Builder documentBuilder,
- boolean add) {
+ @NonNull String prefix) {
// Rewrite the type name to include/remove the prefix.
- String newSchema;
- if (add) {
- newSchema = prefix + documentBuilder.getSchema();
- } else {
- newSchema = removePrefix(prefix, "schemaType", documentBuilder.getSchema());
- }
+ String newSchema = prefix + documentBuilder.getSchema();
documentBuilder.setSchema(newSchema);
// Rewrite the namespace to include/remove the prefix.
- if (add) {
- documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
- } else {
- documentBuilder.setNamespace(
- removePrefix(prefix, "namespace", documentBuilder.getNamespace()));
+ documentBuilder.setNamespace(prefix + documentBuilder.getNamespace());
+
+ // Recurse into derived documents
+ for (int propertyIdx = 0;
+ propertyIdx < documentBuilder.getPropertiesCount();
+ propertyIdx++) {
+ int documentCount = documentBuilder.getProperties(propertyIdx).getDocumentValuesCount();
+ if (documentCount > 0) {
+ PropertyProto.Builder propertyBuilder =
+ documentBuilder.getProperties(propertyIdx).toBuilder();
+ for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
+ DocumentProto.Builder derivedDocumentBuilder =
+ propertyBuilder.getDocumentValues(documentIdx).toBuilder();
+ addPrefixToDocument(derivedDocumentBuilder, prefix);
+ propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
+ }
+ documentBuilder.setProperties(propertyIdx, propertyBuilder);
+ }
+ }
+ }
+
+ /**
+ * Removes any database names from types and namespaces mentioned anywhere in
+ * {@code documentBuilder}.
+ *
+ * @param documentBuilder The document to mutate
+ */
+ @VisibleForTesting
+ void removeDatabasesFromDocument(@NonNull DocumentProto.Builder documentBuilder) {
+ int delimiterIndex;
+ if ((delimiterIndex = documentBuilder.getSchema().indexOf(DATABASE_DELIMITER)) != -1) {
+ // Rewrite the type name to remove the prefix.
+ // Add 1 to include the char size of the DATABASE_DELIMITER
+ String newSchema = documentBuilder.getSchema().substring(delimiterIndex + 1);
+ documentBuilder.setSchema(newSchema);
+ }
+
+ if ((delimiterIndex = documentBuilder.getNamespace().indexOf(DATABASE_DELIMITER)) != -1) {
+ // Rewrite the namespace to remove the prefix.
+ // Add 1 to include the char size of the DATABASE_DELIMITER
+ String newNamespace = documentBuilder.getNamespace().substring(delimiterIndex + 1);
+ documentBuilder.setNamespace(newNamespace);
}
// Recurse into derived documents
@@ -608,7 +628,7 @@ public final class AppSearchImpl {
for (int documentIdx = 0; documentIdx < documentCount; documentIdx++) {
DocumentProto.Builder derivedDocumentBuilder =
propertyBuilder.getDocumentValues(documentIdx).toBuilder();
- rewriteDocumentTypes(prefix, derivedDocumentBuilder, add);
+ removeDatabasesFromDocument(derivedDocumentBuilder);
propertyBuilder.setDocumentValues(documentIdx, derivedDocumentBuilder);
}
documentBuilder.setProperties(propertyIdx, propertyBuilder);
@@ -617,51 +637,68 @@ public final class AppSearchImpl {
}
/**
- * Rewrites searchSpec by adding schemaTypeFilter and namespacesFilter
+ * Rewrites the schemaTypeFilters and namespacesFilters that exist in {@code databaseNames}.
*
- * <p>If user input empty filter lists, will look up {@link #mSchemaMap} and
- * {@link #mNamespaceMap} and put all values belong to current database to narrow down Icing
- * search area.
+ * <p>If the searchSpec has empty filter lists, all existing databases from
+ * {@code databaseNames} will be added.
* <p>This method should be only called in query methods and get the READ lock to keep thread
* safety.
- * @return false if the current database is brand new and contains nothing. We should just
- * return an empty query result to user.
+ *
+ * @return false if none of the requested databases exist.
*/
@VisibleForTesting
@GuardedBy("mReadWriteLock")
- boolean rewriteSearchSpecForNonEmptyDatabase(@NonNull String databaseName,
- @NonNull SearchSpecProto.Builder searchSpecBuilder) {
- Set<String> existingSchemaTypes = mSchemaMap.get(databaseName);
- Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
- if (existingSchemaTypes == null || existingSchemaTypes.isEmpty()
- || existingNamespaces == null || existingNamespaces.isEmpty()) {
+ boolean rewriteSearchSpecForDatabases(
+ @NonNull SearchSpecProto.Builder searchSpecBuilder,
+ @NonNull Set<String> databaseNames) {
+ // Create a copy since retainAll() modifies the original set.
+ Set<String> existingDatabases = new HashSet<>(mNamespaceMap.keySet());
+ existingDatabases.retainAll(databaseNames);
+
+ if (existingDatabases.isEmpty()) {
+ // None of the databases exist, empty query.
return false;
}
- // Rewrite any existing schema types specified in the searchSpec, or add schema types to
- // limit the search to this database instance.
- if (searchSpecBuilder.getSchemaTypeFiltersCount() > 0) {
- for (int i = 0; i < searchSpecBuilder.getSchemaTypeFiltersCount(); i++) {
- String qualifiedType = getDatabasePrefix(databaseName)
- + searchSpecBuilder.getSchemaTypeFilters(i);
- if (existingSchemaTypes.contains(qualifiedType)) {
- searchSpecBuilder.setSchemaTypeFilters(i, qualifiedType);
+
+ // Cache the schema type filters and namespaces before clearing everything.
+ List<String> schemaTypeFilters = searchSpecBuilder.getSchemaTypeFiltersList();
+ searchSpecBuilder.clearSchemaTypeFilters();
+
+ List<String> namespaceFilters = searchSpecBuilder.getNamespaceFiltersList();
+ searchSpecBuilder.clearNamespaceFilters();
+
+ // Rewrite filters to include a database prefix.
+ for (String databaseName : existingDatabases) {
+ Set<String> existingSchemaTypes = mSchemaMap.get(databaseName);
+ if (schemaTypeFilters.isEmpty()) {
+ // Include all schema types
+ searchSpecBuilder.addAllSchemaTypeFilters(existingSchemaTypes);
+ } else {
+ // Qualify the given schema types
+ for (String schemaType : schemaTypeFilters) {
+ String qualifiedType = getDatabasePrefix(databaseName) + schemaType;
+ if (existingSchemaTypes.contains(qualifiedType)) {
+ searchSpecBuilder.addSchemaTypeFilters(qualifiedType);
+ }
+
}
}
- } else {
- searchSpecBuilder.addAllSchemaTypeFilters(existingSchemaTypes);
- }
- // Rewrite any existing namespaces specified in the searchSpec, or add namespaces to
- // limit the search to this database instance.
- if (searchSpecBuilder.getNamespaceFiltersCount() > 0) {
- for (int i = 0; i < searchSpecBuilder.getNamespaceFiltersCount(); i++) {
- String qualifiedNamespace = getDatabasePrefix(databaseName)
- + searchSpecBuilder.getNamespaceFilters(i);
- searchSpecBuilder.setNamespaceFilters(i, qualifiedNamespace);
+ Set<String> existingNamespaces = mNamespaceMap.get(databaseName);
+ if (namespaceFilters.isEmpty()) {
+ // Include all namespaces
+ searchSpecBuilder.addAllNamespaceFilters(existingNamespaces);
+ } else {
+ // Qualify the given namespaces.
+ for (String namespace : namespaceFilters) {
+ String qualifiedNamespace = getDatabasePrefix(databaseName) + namespace;
+ if (existingNamespaces.contains(qualifiedNamespace)) {
+ searchSpecBuilder.addNamespaceFilters(qualifiedNamespace);
+ }
+ }
}
- } else {
- searchSpecBuilder.addAllNamespaceFilters(existingNamespaces);
}
+
return true;
}
@@ -676,12 +713,13 @@ public final class AppSearchImpl {
@NonNull
private String getDatabasePrefix(@NonNull String databaseName) {
- return databaseName + "/";
+ // TODO(b/170370381): Reconsider the way we separate database names for security reasons.
+ return databaseName + DATABASE_DELIMITER;
}
@NonNull
private String getDatabaseName(@NonNull String prefixedValue) throws AppSearchException {
- int delimiterIndex = prefixedValue.indexOf('/');
+ int delimiterIndex = prefixedValue.indexOf(DATABASE_DELIMITER);
if (delimiterIndex == -1) {
throw new AppSearchException(AppSearchResult.RESULT_UNKNOWN_ERROR,
"The databaseName prefixed value doesn't contains a valid database name.");
@@ -689,17 +727,6 @@ public final class AppSearchImpl {
return prefixedValue.substring(0, delimiterIndex);
}
- @NonNull
- private static String removePrefix(@NonNull String prefix, @NonNull String inputType,
- @NonNull String input) {
- if (!input.startsWith(prefix)) {
- throw new IllegalStateException(
- "Unexpected " + inputType + " \"" + input
- + "\" does not start with \"" + prefix + "\"");
- }
- return input.substring(prefix.length());
- }
-
@GuardedBy("mReadWriteLock")
private void addToMap(Map<String, Set<String>> map, String databaseName, String prefixedValue) {
Set<String> values = map.get(databaseName);
@@ -733,7 +760,7 @@ public final class AppSearchImpl {
}
if (statusProto.getCode() == StatusProto.Code.WARNING_DATA_LOSS) {
- // TODO: May want to propagate WARNING_DATA_LOSS up to AppSearchManager so they can
+ // TODO: May want to propagate WARNING_DATA_LOSS up to AppSearchSession so they can
// choose to log the error or potentially pass it on to clients.
Log.w(TAG, "Encountered WARNING_DATA_LOSS: " + statusProto.getMessage());
return;
@@ -776,22 +803,21 @@ public final class AppSearchImpl {
}
}
- /** Remove the rewritten schema types from any result documents.*/
- private SearchResultProto rewriteSearchResultProto(@NonNull String databaseName,
+ /** Remove the rewritten schema types from any result documents. */
+ private SearchResultPage rewriteSearchResultProto(
@NonNull SearchResultProto searchResultProto) {
- SearchResultProto.Builder searchResultsBuilder = searchResultProto.toBuilder();
- for (int i = 0; i < searchResultsBuilder.getResultsCount(); i++) {
+ SearchResultProto.Builder resultsBuilder = searchResultProto.toBuilder();
+ for (int i = 0; i < searchResultProto.getResultsCount(); i++) {
if (searchResultProto.getResults(i).hasDocument()) {
SearchResultProto.ResultProto.Builder resultBuilder =
- searchResultsBuilder.getResults(i).toBuilder();
+ searchResultProto.getResults(i).toBuilder();
DocumentProto.Builder documentBuilder = resultBuilder.getDocument().toBuilder();
- rewriteDocumentTypes(
- getDatabasePrefix(databaseName), documentBuilder, /*add=*/false);
+ removeDatabasesFromDocument(documentBuilder);
resultBuilder.setDocument(documentBuilder);
- searchResultsBuilder.setResults(i, resultBuilder);
+ resultsBuilder.setResults(i, resultBuilder);
}
}
- return searchResultsBuilder.build();
+ return SearchResultToProtoConverter.convertToSearchResultPage(resultsBuilder);
}
@VisibleForTesting
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
index 9f7c6968e993..4310b4216266 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/converter/SearchResultToProtoConverter.java
@@ -22,8 +22,10 @@ import android.annotation.NonNull;
import android.app.appsearch.GenericDocument;
import android.app.appsearch.SearchResult;
+import android.app.appsearch.SearchResultPage;
import com.google.android.icing.proto.SearchResultProto;
+import com.google.android.icing.proto.SearchResultProtoOrBuilder;
import com.google.android.icing.proto.SnippetMatchProto;
import com.google.android.icing.proto.SnippetProto;
@@ -38,9 +40,24 @@ import java.util.ArrayList;
public class SearchResultToProtoConverter {
private SearchResultToProtoConverter() {}
+
+ /** Translate a {@link SearchResultProto} into {@link SearchResultPage}. */
+ @NonNull
+ public static SearchResultPage convertToSearchResultPage(
+ @NonNull SearchResultProtoOrBuilder proto) {
+ Bundle bundle = new Bundle();
+ bundle.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, proto.getNextPageToken());
+ ArrayList<Bundle> resultBundles = new ArrayList<>(proto.getResultsCount());
+ for (int i = 0; i < proto.getResultsCount(); i++) {
+ resultBundles.add(convertToSearchResultBundle(proto.getResults(i)));
+ }
+ bundle.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles);
+ return new SearchResultPage(bundle);
+ }
+
/** Translate a {@link SearchResultProto.ResultProto} into {@link SearchResult}. */
@NonNull
- public static SearchResult convertSearchResult(
+ private static Bundle convertToSearchResultBundle(
@NonNull SearchResultProto.ResultProtoOrBuilder proto) {
Bundle bundle = new Bundle();
GenericDocument document = GenericDocumentToProtoConverter.convert(proto.getDocument());
@@ -59,7 +76,7 @@ public class SearchResultToProtoConverter {
}
bundle.putParcelableArrayList(SearchResult.MATCHES_FIELD, matchList);
- return new SearchResult(bundle);
+ return bundle;
}
private static Bundle convertToMatchInfoBundle(
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
index 62c90dfa8a86..e251ff00a47d 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobParameters.java
@@ -21,6 +21,7 @@ import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ClipData;
import android.net.Network;
+import android.net.NetworkRequest;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
@@ -242,8 +243,9 @@ public class JobParameters implements Parcelable {
*
* @return the network that should be used to perform any network requests
* for this job, or {@code null} if this job didn't set any required
- * network type.
+ * network type or if the job executed when there was no available network to use.
* @see JobInfo.Builder#setRequiredNetworkType(int)
+ * @see JobInfo.Builder#setRequiredNetwork(NetworkRequest)
*/
public @Nullable Network getNetwork() {
return network;
diff --git a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
index bf5781beb52b..361325dae7fd 100644
--- a/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
+++ b/apex/jobscheduler/framework/java/android/app/job/JobScheduler.java
@@ -169,6 +169,7 @@ public abstract class JobScheduler {
* @param tag Debugging tag for dumps associated with this job (instead of the service class)
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
@SystemApi
@RequiresPermission(android.Manifest.permission.UPDATE_DEVICE_STATS)
public abstract @Result int scheduleAsPackage(@NonNull JobInfo job, @NonNull String packageName,
@@ -211,6 +212,7 @@ public abstract class JobScheduler {
* Returns a list of all currently-executing jobs.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract List<JobInfo> getStartedJobs();
/**
@@ -220,5 +222,6 @@ public abstract class JobScheduler {
* <p class="note">This is a slow operation, so it should be called sparingly.
* @hide
*/
+ @SuppressWarnings("HiddenAbstractMethod")
public abstract List<JobSnapshot> getAllJobSnapshots();
} \ No newline at end of file
diff --git a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
index ba2a8a34a92b..d4ea7af06ed1 100644
--- a/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
+++ b/apex/jobscheduler/service/java/com/android/server/alarm/AlarmManagerService.java
@@ -439,7 +439,7 @@ public class AlarmManagerService extends SystemService {
private static final int DEFAULT_APP_STANDBY_RESTRICTED_QUOTA = 1;
private static final long DEFAULT_APP_STANDBY_RESTRICTED_WINDOW = MILLIS_IN_DAY;
- private static final boolean DEFAULT_LAZY_BATCHING = false;
+ private static final boolean DEFAULT_LAZY_BATCHING = true;
// Minimum futurity of a new alarm
public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY;
diff --git a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
index cc202130ab07..1e7206287566 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/JobSchedulerShellCommand.java
@@ -20,11 +20,10 @@ import android.app.ActivityManager;
import android.app.AppGlobals;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
+import android.os.BasicShellCommandHandler;
import android.os.Binder;
import android.os.UserHandle;
-import com.android.modules.utils.BasicShellCommandHandler;
-
import java.io.PrintWriter;
public final class JobSchedulerShellCommand extends BasicShellCommandHandler {
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index 6f7dde292c56..1157ee905b86 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -2390,7 +2390,8 @@ public class AppStandbyController implements AppStandbyInternal {
false, this);
mInjector.registerDeviceConfigPropertiesChangedListener(this);
// Load all the constants.
- onPropertiesChanged(mInjector.getDeviceConfigProperties());
+ // postOneTimeCheckIdleStates() doesn't need to be called on boot.
+ processProperties(mInjector.getDeviceConfigProperties());
updateSettings();
}
@@ -2402,6 +2403,11 @@ public class AppStandbyController implements AppStandbyInternal {
@Override
public void onPropertiesChanged(DeviceConfig.Properties properties) {
+ processProperties(properties);
+ postOneTimeCheckIdleStates();
+ }
+
+ private void processProperties(DeviceConfig.Properties properties) {
boolean timeThresholdsUpdated = false;
synchronized (mAppIdleLock) {
for (String name : properties.getKeyset()) {
@@ -2482,7 +2488,6 @@ public class AppStandbyController implements AppStandbyInternal {
}
}
}
- postOneTimeCheckIdleStates();
}
private void updateTimeThresholds() {
diff --git a/apex/permission/Android.bp b/apex/permission/Android.bp
index 71a52bb216ea..e30df05b2340 100644
--- a/apex/permission/Android.bp
+++ b/apex/permission/Android.bp
@@ -21,7 +21,7 @@ apex {
apex_defaults {
name: "com.android.permission-defaults",
updatable: true,
- min_sdk_version: "R",
+ min_sdk_version: "30",
key: "com.android.permission.key",
certificate: ":com.android.permission.certificate",
java_libs: [
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index ede8852c5905..f13861e7ee85 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -35,7 +35,7 @@ apex_defaults {
prebuilts: ["com.android.os.statsd.init.rc"],
name: "com.android.os.statsd-defaults",
updatable: true,
- min_sdk_version: "R",
+ min_sdk_version: "30",
key: "com.android.os.statsd.key",
certificate: ":com.android.os.statsd.certificate",
}