Loading apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java +19 −7 Original line number Original line Diff line number Diff line Loading @@ -34,11 +34,11 @@ import java.util.Map; * @hide * @hide */ */ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mSuccesses; @NonNull private final Map<KeyType, ValueType> mSuccesses; @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures; @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures; private AppSearchBatchResult( private AppSearchBatchResult( @NonNull Map<KeyType, AppSearchResult<ValueType>> successes, @NonNull Map<KeyType, ValueType> successes, @NonNull Map<KeyType, AppSearchResult<ValueType>> failures) { @NonNull Map<KeyType, AppSearchResult<ValueType>> failures) { mSuccesses = successes; mSuccesses = successes; mFailures = failures; mFailures = failures; Loading @@ -61,13 +61,13 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { } } /** /** * Returns a {@link Map} of all successful keys mapped to the successful * Returns a {@link Map} of all successful keys mapped to the successful {@link ValueType} * {@link AppSearchResult}s they produced. * values they produced. * * * <p>The values of the {@link Map} will not be {@code null}. * <p>The values of the {@link Map} will not be {@code null}. */ */ @NonNull @NonNull public Map<KeyType, AppSearchResult<ValueType>> getSuccesses() { public Map<KeyType, ValueType> getSuccesses() { return mSuccesses; return mSuccesses; } } Loading Loading @@ -110,7 +110,7 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { * @hide * @hide */ */ public static final class Builder<KeyType, ValueType> { public static final class Builder<KeyType, ValueType> { private final Map<KeyType, AppSearchResult<ValueType>> mSuccesses = new ArrayMap<>(); private final Map<KeyType, ValueType> mSuccesses = new ArrayMap<>(); private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>(); private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>(); /** Creates a new {@link Builder} for this {@link AppSearchBatchResult}. */ /** Creates a new {@link Builder} for this {@link AppSearchBatchResult}. */ Loading @@ -125,6 +125,18 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { return setResult(key, AppSearchResult.newSuccessfulResult(result)); return setResult(key, AppSearchResult.newSuccessfulResult(result)); } } /** * Associates the {@code key} with the given failure code and error message. * * <p>Any previous mapping for a key, whether success or failure, is deleted. */ public Builder setFailure( @NonNull KeyType key, @AppSearchResult.ResultCode int resultCode, @Nullable String errorMessage) { return setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage)); } /** /** * Associates the {@code key} with the given {@code result}. * Associates the {@code key} with the given {@code result}. * * Loading @@ -133,7 +145,7 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { @NonNull @NonNull public Builder setResult(@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) { public Builder setResult(@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) { if (result.isSuccess()) { if (result.isSuccess()) { mSuccesses.put(key, result); mSuccesses.put(key, result.getResultValue()); mFailures.remove(key); mFailures.remove(key); } else { } else { mFailures.put(key, result); mFailures.put(key, result); Loading apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +52 −33 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,7 @@ import com.google.android.icing.protobuf.InvalidProtocolBufferException; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Arrays; import java.util.List; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.BiConsumer; Loading Loading @@ -193,44 +194,62 @@ public class AppSearchManager { * {@code AppSearch#getDocuments()} API provided by JetPack. * {@code AppSearch#getDocuments()} API provided by JetPack. * * * @param uris URIs of the documents to look up. * @param uris URIs of the documents to look up. * @param executor Executor on which to invoke the callback. * @return An {@link AppSearchBatchResult} mapping the document URIs to * @param callback Callback to receive the documents or error. * {@link AppSearchDocument} values if they were successfully retrieved, a {@code null} * failure if they were not found, or a {@link Throwable} failure describing the problem if * an error occurred. */ */ public void getDocuments( public AppSearchBatchResult<String, AppSearchDocument> getDocuments( @NonNull List<String> uris, @NonNull List<String> uris) { @NonNull @CallbackExecutor Executor executor, // TODO(b/146386470): Transmit the result documents as a RemoteStream instead of sending @NonNull BiConsumer<List<AppSearchDocument>, ? super Throwable> callback) { // them in one big list. AndroidFuture<List<byte[]>> future = new AndroidFuture<>(); AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>(); future.whenCompleteAsync((documentProtos, err) -> { try { if (err != null) { mService.getDocuments(uris, future); callback.accept(null, err); } catch (RemoteException e) { return; future.completeExceptionally(e); } } if (documentProtos != null) { List<AppSearchDocument> results = new ArrayList<>(documentProtos.size()); // Deserialize the protos into Document objects for (int i = 0; i < documentProtos.size(); i++) { AppSearchBatchResult<String, byte[]> protoResults = getFutureOrThrow(future); AppSearchBatchResult.Builder<String, AppSearchDocument> documentResultBuilder = new AppSearchBatchResult.Builder<>(); // Translate successful results for (Map.Entry<String, byte[]> protoResult : protoResults.getSuccesses().entrySet()) { DocumentProto documentProto; DocumentProto documentProto; try { try { documentProto = DocumentProto.parseFrom(documentProtos.get(i)); documentProto = DocumentProto.parseFrom(protoResult.getValue()); } catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) { callback.accept(null, e); documentResultBuilder.setFailure( return; protoResult.getKey(), AppSearchResult.RESULT_IO_ERROR, e.getMessage()); continue; } } results.add(new AppSearchDocument(documentProto)); AppSearchDocument document; try { document = new AppSearchDocument(documentProto); } catch (Throwable t) { // These documents went through validation, so how could this fail? We must have // done something wrong. documentResultBuilder.setFailure( protoResult.getKey(), AppSearchResult.RESULT_INTERNAL_ERROR, t.getMessage()); continue; } } callback.accept(results, null); documentResultBuilder.setSuccess(protoResult.getKey(), document); return; } } // Nothing was supplied in the future at all callback.accept(null, new IllegalStateException( // Translate failed results "Unknown failure occurred while retrieving documents")); for (Map.Entry<String, AppSearchResult<byte[]>> protoResult : }, executor); protoResults.getFailures().entrySet()) { // TODO(b/146386470) stream uris? documentResultBuilder.setFailure( try { protoResult.getKey(), mService.getDocuments(uris.toArray(new String[uris.size()]), future); protoResult.getValue().getResultCode(), } catch (RemoteException e) { protoResult.getValue().getErrorMessage()); future.completeExceptionally(e); } } return documentResultBuilder.build(); } } /** /** Loading apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -56,7 +56,6 @@ public class AppSearchResult<ValueType> implements Parcelable { /** /** * An internal error occurred within AppSearch, which the caller cannot address. * An internal error occurred within AppSearch, which the caller cannot address. * * * * This error may be considered similar to {@link IllegalStateException} * This error may be considered similar to {@link IllegalStateException} */ */ public static final int RESULT_INTERNAL_ERROR = 2; public static final int RESULT_INTERNAL_ERROR = 2; Loading apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +7 −4 Original line number Original line Diff line number Diff line Loading @@ -51,11 +51,14 @@ interface IAppSearchManager { * Retrieves documents from the index. * Retrieves documents from the index. * * * @param uris The URIs of the documents to retrieve * @param uris The URIs of the documents to retrieve * @param callback {@link AndroidFuture}<{@link List}<byte[]>>. Will be completed * @param callback * with a {@link List} containing serialized DocumentProtos, or completed exceptionally if * {@link AndroidFuture}<{@link AppSearchBatchResult}<{@link String}, {@link byte[]}>>. * get fails. * If the call fails to start, {@code callback} will be completed exceptionally. Otherwise, * {@code callback} will be completed with an * {@link AppSearchBatchResult}<{@link String}, {@link byte[]}> * where the keys are document URIs, and the values are serialized Document protos. */ */ void getDocuments(in String[] uris, in AndroidFuture callback); void getDocuments(in List<String> uris, in AndroidFuture<AppSearchBatchResult> callback); /** /** * Searches a document based on a given specifications. * Searches a document based on a given specifications. Loading apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +18 −8 Original line number Original line Diff line number Diff line Loading @@ -37,7 +37,6 @@ import com.google.android.icing.proto.SearchSpecProto; import com.google.android.icing.protobuf.InvalidProtocolBufferException; import com.google.android.icing.protobuf.InvalidProtocolBufferException; import java.io.IOException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.List; /** /** Loading Loading @@ -112,7 +111,8 @@ public class AppSearchManagerService extends SystemService { } } @Override @Override public void getDocuments(String[] uris, AndroidFuture callback) { public void getDocuments( @NonNull List<String> uris, @NonNull AndroidFuture<AppSearchBatchResult> callback) { Preconditions.checkNotNull(uris); Preconditions.checkNotNull(uris); Preconditions.checkNotNull(callback); Preconditions.checkNotNull(callback); int callingUid = Binder.getCallingUidOrThrow(); int callingUid = Binder.getCallingUidOrThrow(); Loading @@ -120,13 +120,23 @@ public class AppSearchManagerService extends SystemService { long callingIdentity = Binder.clearCallingIdentity(); long callingIdentity = Binder.clearCallingIdentity(); try { try { AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); // Contains serialized DocumentProto. byte[][] is not transmissible via Binder. AppSearchBatchResult.Builder<String, byte[]> resultBuilder = List<byte[]> results = new ArrayList<>(uris.length); new AppSearchBatchResult.Builder<>(); for (String uri : uris) { for (int i = 0; i < uris.size(); i++) { DocumentProto result = impl.getDocument(callingUid, uri); String uri = uris.get(i); results.add(result.toByteArray()); try { DocumentProto document = impl.getDocument(callingUid, uri); if (document == null) { resultBuilder.setFailure( uri, AppSearchResult.RESULT_NOT_FOUND, /*errorMessage=*/ null); } else { resultBuilder.setSuccess(uri, document.toByteArray()); } } callback.complete(results); } catch (Throwable t) { resultBuilder.setResult(uri, throwableToFailedResult(t)); } } callback.complete(resultBuilder.build()); } catch (Throwable t) { } catch (Throwable t) { callback.completeExceptionally(t); callback.completeExceptionally(t); } finally { } finally { Loading Loading
apex/appsearch/framework/java/android/app/appsearch/AppSearchBatchResult.java +19 −7 Original line number Original line Diff line number Diff line Loading @@ -34,11 +34,11 @@ import java.util.Map; * @hide * @hide */ */ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mSuccesses; @NonNull private final Map<KeyType, ValueType> mSuccesses; @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures; @NonNull private final Map<KeyType, AppSearchResult<ValueType>> mFailures; private AppSearchBatchResult( private AppSearchBatchResult( @NonNull Map<KeyType, AppSearchResult<ValueType>> successes, @NonNull Map<KeyType, ValueType> successes, @NonNull Map<KeyType, AppSearchResult<ValueType>> failures) { @NonNull Map<KeyType, AppSearchResult<ValueType>> failures) { mSuccesses = successes; mSuccesses = successes; mFailures = failures; mFailures = failures; Loading @@ -61,13 +61,13 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { } } /** /** * Returns a {@link Map} of all successful keys mapped to the successful * Returns a {@link Map} of all successful keys mapped to the successful {@link ValueType} * {@link AppSearchResult}s they produced. * values they produced. * * * <p>The values of the {@link Map} will not be {@code null}. * <p>The values of the {@link Map} will not be {@code null}. */ */ @NonNull @NonNull public Map<KeyType, AppSearchResult<ValueType>> getSuccesses() { public Map<KeyType, ValueType> getSuccesses() { return mSuccesses; return mSuccesses; } } Loading Loading @@ -110,7 +110,7 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { * @hide * @hide */ */ public static final class Builder<KeyType, ValueType> { public static final class Builder<KeyType, ValueType> { private final Map<KeyType, AppSearchResult<ValueType>> mSuccesses = new ArrayMap<>(); private final Map<KeyType, ValueType> mSuccesses = new ArrayMap<>(); private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>(); private final Map<KeyType, AppSearchResult<ValueType>> mFailures = new ArrayMap<>(); /** Creates a new {@link Builder} for this {@link AppSearchBatchResult}. */ /** Creates a new {@link Builder} for this {@link AppSearchBatchResult}. */ Loading @@ -125,6 +125,18 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { return setResult(key, AppSearchResult.newSuccessfulResult(result)); return setResult(key, AppSearchResult.newSuccessfulResult(result)); } } /** * Associates the {@code key} with the given failure code and error message. * * <p>Any previous mapping for a key, whether success or failure, is deleted. */ public Builder setFailure( @NonNull KeyType key, @AppSearchResult.ResultCode int resultCode, @Nullable String errorMessage) { return setResult(key, AppSearchResult.newFailedResult(resultCode, errorMessage)); } /** /** * Associates the {@code key} with the given {@code result}. * Associates the {@code key} with the given {@code result}. * * Loading @@ -133,7 +145,7 @@ public class AppSearchBatchResult<KeyType, ValueType> implements Parcelable { @NonNull @NonNull public Builder setResult(@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) { public Builder setResult(@NonNull KeyType key, @NonNull AppSearchResult<ValueType> result) { if (result.isSuccess()) { if (result.isSuccess()) { mSuccesses.put(key, result); mSuccesses.put(key, result.getResultValue()); mFailures.remove(key); mFailures.remove(key); } else { } else { mFailures.put(key, result); mFailures.put(key, result); Loading
apex/appsearch/framework/java/android/app/appsearch/AppSearchManager.java +52 −33 Original line number Original line Diff line number Diff line Loading @@ -33,6 +33,7 @@ import com.google.android.icing.protobuf.InvalidProtocolBufferException; import java.util.ArrayList; import java.util.ArrayList; import java.util.Arrays; import java.util.Arrays; import java.util.List; import java.util.List; import java.util.Map; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.BiConsumer; Loading Loading @@ -193,44 +194,62 @@ public class AppSearchManager { * {@code AppSearch#getDocuments()} API provided by JetPack. * {@code AppSearch#getDocuments()} API provided by JetPack. * * * @param uris URIs of the documents to look up. * @param uris URIs of the documents to look up. * @param executor Executor on which to invoke the callback. * @return An {@link AppSearchBatchResult} mapping the document URIs to * @param callback Callback to receive the documents or error. * {@link AppSearchDocument} values if they were successfully retrieved, a {@code null} * failure if they were not found, or a {@link Throwable} failure describing the problem if * an error occurred. */ */ public void getDocuments( public AppSearchBatchResult<String, AppSearchDocument> getDocuments( @NonNull List<String> uris, @NonNull List<String> uris) { @NonNull @CallbackExecutor Executor executor, // TODO(b/146386470): Transmit the result documents as a RemoteStream instead of sending @NonNull BiConsumer<List<AppSearchDocument>, ? super Throwable> callback) { // them in one big list. AndroidFuture<List<byte[]>> future = new AndroidFuture<>(); AndroidFuture<AppSearchBatchResult> future = new AndroidFuture<>(); future.whenCompleteAsync((documentProtos, err) -> { try { if (err != null) { mService.getDocuments(uris, future); callback.accept(null, err); } catch (RemoteException e) { return; future.completeExceptionally(e); } } if (documentProtos != null) { List<AppSearchDocument> results = new ArrayList<>(documentProtos.size()); // Deserialize the protos into Document objects for (int i = 0; i < documentProtos.size(); i++) { AppSearchBatchResult<String, byte[]> protoResults = getFutureOrThrow(future); AppSearchBatchResult.Builder<String, AppSearchDocument> documentResultBuilder = new AppSearchBatchResult.Builder<>(); // Translate successful results for (Map.Entry<String, byte[]> protoResult : protoResults.getSuccesses().entrySet()) { DocumentProto documentProto; DocumentProto documentProto; try { try { documentProto = DocumentProto.parseFrom(documentProtos.get(i)); documentProto = DocumentProto.parseFrom(protoResult.getValue()); } catch (InvalidProtocolBufferException e) { } catch (InvalidProtocolBufferException e) { callback.accept(null, e); documentResultBuilder.setFailure( return; protoResult.getKey(), AppSearchResult.RESULT_IO_ERROR, e.getMessage()); continue; } } results.add(new AppSearchDocument(documentProto)); AppSearchDocument document; try { document = new AppSearchDocument(documentProto); } catch (Throwable t) { // These documents went through validation, so how could this fail? We must have // done something wrong. documentResultBuilder.setFailure( protoResult.getKey(), AppSearchResult.RESULT_INTERNAL_ERROR, t.getMessage()); continue; } } callback.accept(results, null); documentResultBuilder.setSuccess(protoResult.getKey(), document); return; } } // Nothing was supplied in the future at all callback.accept(null, new IllegalStateException( // Translate failed results "Unknown failure occurred while retrieving documents")); for (Map.Entry<String, AppSearchResult<byte[]>> protoResult : }, executor); protoResults.getFailures().entrySet()) { // TODO(b/146386470) stream uris? documentResultBuilder.setFailure( try { protoResult.getKey(), mService.getDocuments(uris.toArray(new String[uris.size()]), future); protoResult.getValue().getResultCode(), } catch (RemoteException e) { protoResult.getValue().getErrorMessage()); future.completeExceptionally(e); } } return documentResultBuilder.build(); } } /** /** Loading
apex/appsearch/framework/java/android/app/appsearch/AppSearchResult.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -56,7 +56,6 @@ public class AppSearchResult<ValueType> implements Parcelable { /** /** * An internal error occurred within AppSearch, which the caller cannot address. * An internal error occurred within AppSearch, which the caller cannot address. * * * * This error may be considered similar to {@link IllegalStateException} * This error may be considered similar to {@link IllegalStateException} */ */ public static final int RESULT_INTERNAL_ERROR = 2; public static final int RESULT_INTERNAL_ERROR = 2; Loading
apex/appsearch/framework/java/android/app/appsearch/IAppSearchManager.aidl +7 −4 Original line number Original line Diff line number Diff line Loading @@ -51,11 +51,14 @@ interface IAppSearchManager { * Retrieves documents from the index. * Retrieves documents from the index. * * * @param uris The URIs of the documents to retrieve * @param uris The URIs of the documents to retrieve * @param callback {@link AndroidFuture}<{@link List}<byte[]>>. Will be completed * @param callback * with a {@link List} containing serialized DocumentProtos, or completed exceptionally if * {@link AndroidFuture}<{@link AppSearchBatchResult}<{@link String}, {@link byte[]}>>. * get fails. * If the call fails to start, {@code callback} will be completed exceptionally. Otherwise, * {@code callback} will be completed with an * {@link AppSearchBatchResult}<{@link String}, {@link byte[]}> * where the keys are document URIs, and the values are serialized Document protos. */ */ void getDocuments(in String[] uris, in AndroidFuture callback); void getDocuments(in List<String> uris, in AndroidFuture<AppSearchBatchResult> callback); /** /** * Searches a document based on a given specifications. * Searches a document based on a given specifications. Loading
apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java +18 −8 Original line number Original line Diff line number Diff line Loading @@ -37,7 +37,6 @@ import com.google.android.icing.proto.SearchSpecProto; import com.google.android.icing.protobuf.InvalidProtocolBufferException; import com.google.android.icing.protobuf.InvalidProtocolBufferException; import java.io.IOException; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.List; /** /** Loading Loading @@ -112,7 +111,8 @@ public class AppSearchManagerService extends SystemService { } } @Override @Override public void getDocuments(String[] uris, AndroidFuture callback) { public void getDocuments( @NonNull List<String> uris, @NonNull AndroidFuture<AppSearchBatchResult> callback) { Preconditions.checkNotNull(uris); Preconditions.checkNotNull(uris); Preconditions.checkNotNull(callback); Preconditions.checkNotNull(callback); int callingUid = Binder.getCallingUidOrThrow(); int callingUid = Binder.getCallingUidOrThrow(); Loading @@ -120,13 +120,23 @@ public class AppSearchManagerService extends SystemService { long callingIdentity = Binder.clearCallingIdentity(); long callingIdentity = Binder.clearCallingIdentity(); try { try { AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); AppSearchImpl impl = ImplInstanceManager.getInstance(getContext(), callingUserId); // Contains serialized DocumentProto. byte[][] is not transmissible via Binder. AppSearchBatchResult.Builder<String, byte[]> resultBuilder = List<byte[]> results = new ArrayList<>(uris.length); new AppSearchBatchResult.Builder<>(); for (String uri : uris) { for (int i = 0; i < uris.size(); i++) { DocumentProto result = impl.getDocument(callingUid, uri); String uri = uris.get(i); results.add(result.toByteArray()); try { DocumentProto document = impl.getDocument(callingUid, uri); if (document == null) { resultBuilder.setFailure( uri, AppSearchResult.RESULT_NOT_FOUND, /*errorMessage=*/ null); } else { resultBuilder.setSuccess(uri, document.toByteArray()); } } callback.complete(results); } catch (Throwable t) { resultBuilder.setResult(uri, throwableToFailedResult(t)); } } callback.complete(resultBuilder.build()); } catch (Throwable t) { } catch (Throwable t) { callback.completeExceptionally(t); callback.completeExceptionally(t); } finally { } finally { Loading