Safeparcelables in AppSearch - SearchSuggestionResult

Bug: 275629842
Test: atest CtsAppSearchTestCases CtsAppSearchHostTestCases AppSearchServicesTests AppSearchCoreTests ContactsIndexerTests

Change-Id: I100e82222d8705eac9316f395775fc3ab906c1e4
API-Coverage-Bug: b/309179274
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 0083035..120c4e3 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -467,8 +467,11 @@
     method @NonNull public android.app.appsearch.SearchSpec.Builder setVerbatimSearchEnabled(boolean);
   }
 
-  public final class SearchSuggestionResult {
+  public final class SearchSuggestionResult implements android.os.Parcelable {
+    method @FlaggedApi("com.android.appsearch.flags.enable_safe_parcelable") public final int describeContents();
     method @NonNull public String getSuggestedResult();
+    method @FlaggedApi("com.android.appsearch.flags.enable_safe_parcelable") public void writeToParcel(@NonNull android.os.Parcel, int);
+    field @FlaggedApi("com.android.appsearch.flags.enable_safe_parcelable") @NonNull public static final android.os.Parcelable.Creator<android.app.appsearch.SearchSuggestionResult> CREATOR;
   }
 
   public static final class SearchSuggestionResult.Builder {
diff --git a/framework/java/android/app/appsearch/AppSearchSession.java b/framework/java/android/app/appsearch/AppSearchSession.java
index ea42253..7272224 100644
--- a/framework/java/android/app/appsearch/AppSearchSession.java
+++ b/framework/java/android/app/appsearch/AppSearchSession.java
@@ -564,21 +564,10 @@
                         public void onResult(AppSearchResultParcel resultParcel) {
                             safeExecute(executor, callback, () -> {
                                 try {
-                                    AppSearchResult<List<Bundle>> result = resultParcel.getResult();
+                                    AppSearchResult<List<SearchSuggestionResult>> result =
+                                            resultParcel.getResult();
                                     if (result.isSuccess()) {
-                                        List<Bundle> suggestionResultBundles =
-                                                result.getResultValue();
-                                        List<SearchSuggestionResult> searchSuggestionResults =
-                                                new ArrayList<>(suggestionResultBundles.size());
-                                        for (int i = 0; i < suggestionResultBundles.size(); i++) {
-                                            SearchSuggestionResult searchSuggestionResult =
-                                                    new SearchSuggestionResult(
-                                                            suggestionResultBundles.get(i));
-                                            searchSuggestionResults.add(searchSuggestionResult);
-                                        }
-                                        callback.accept(
-                                                AppSearchResult.newSuccessfulResult(
-                                                        searchSuggestionResults));
+                                        callback.accept(result);
                                     } else {
                                         // TODO(b/261897334) save SDK errors/crashes and send to
                                         //  server for logging.
diff --git a/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl b/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
index 4562a09..76bde11 100644
--- a/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
+++ b/framework/java/android/app/appsearch/aidl/IAppSearchManager.aidl
@@ -312,8 +312,8 @@
      * @param searchSuggestionSpecBundle SearchSuggestionSpec bundle
      * @param userHandle Handle of the calling user
      * @param binderCallStartTimeMillis start timestamp of binder call in Millis
-     * @param callback {@link AppSearchResult}&lt;List&lt;{@link Bundle}&gt; of performing this
-     *   operation. List contains SearchSuggestionResult bundles.
+     * @param callback {@link AppSearchResult}&lt;List&lt;{@link SearchSuggestionResult}&gt; of
+     *   performing this operation.
      */
     void searchSuggestion(
             in AppSearchAttributionSource callerAttributionSource,
diff --git a/framework/java/external/android/app/appsearch/SearchSuggestionResult.java b/framework/java/external/android/app/appsearch/SearchSuggestionResult.java
index fab8770..623c0db 100644
--- a/framework/java/external/android/app/appsearch/SearchSuggestionResult.java
+++ b/framework/java/external/android/app/appsearch/SearchSuggestionResult.java
@@ -16,35 +16,38 @@
 
 package android.app.appsearch;
 
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.appsearch.annotation.CanIgnoreReturnValue;
-import android.app.appsearch.util.BundleUtil;
+import android.app.appsearch.flags.Flags;
+import android.app.appsearch.safeparcel.AbstractSafeParcelable;
+import android.app.appsearch.safeparcel.SafeParcelable;
 import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 import com.android.internal.util.Preconditions;
 
 import java.util.Objects;
 
 /** The result class of the {@link AppSearchSession#searchSuggestion}. */
-public final class SearchSuggestionResult {
+@SafeParcelable.Class(creator = "SearchSuggestionResultCreator")
+public final class SearchSuggestionResult extends AbstractSafeParcelable {
+    @FlaggedApi(Flags.FLAG_ENABLE_SAFE_PARCELABLE)
+    @NonNull public static final Parcelable.Creator<SearchSuggestionResult> CREATOR =
+            new SearchSuggestionResultCreator();
 
     private static final String SUGGESTED_RESULT_FIELD = "suggestedResult";
-    private final Bundle mBundle;
     @Nullable private Integer mHashCode;
 
-    SearchSuggestionResult(@NonNull Bundle bundle) {
-        mBundle = Objects.requireNonNull(bundle);
-    }
+    @SafeParcelable.Field(id = 1, getter = "getSuggestedResult")
+    private final String mSuggestedResult;
 
-    /**
-     * Returns the {@link Bundle} populated by this builder.
-     *
-     * @hide
-     */
-    @NonNull
-    public Bundle getBundle() {
-        return mBundle;
+    @Constructor
+    SearchSuggestionResult(
+            @Param(id = 1) @NonNull String suggestedResult) {
+        mSuggestedResult = Objects.requireNonNull(suggestedResult);
     }
 
     /**
@@ -57,7 +60,7 @@
      */
     @NonNull
     public String getSuggestedResult() {
-        return Objects.requireNonNull(mBundle.getString(SUGGESTED_RESULT_FIELD));
+        return mSuggestedResult;
     }
 
     @Override
@@ -69,13 +72,13 @@
             return false;
         }
         SearchSuggestionResult otherResult = (SearchSuggestionResult) other;
-        return BundleUtil.deepEquals(this.mBundle, otherResult.mBundle);
+        return mSuggestedResult.equals(otherResult.mSuggestedResult);
     }
 
     @Override
     public int hashCode() {
         if (mHashCode == null) {
-            mHashCode = BundleUtil.deepHashCode(mBundle);
+            mHashCode = mSuggestedResult.hashCode();
         }
         return mHashCode;
     }
@@ -104,7 +107,13 @@
         public SearchSuggestionResult build() {
             Bundle bundle = new Bundle();
             bundle.putString(SUGGESTED_RESULT_FIELD, mSuggestedResult);
-            return new SearchSuggestionResult(bundle);
+            return new SearchSuggestionResult(mSuggestedResult);
         }
     }
+
+    @FlaggedApi(Flags.FLAG_ENABLE_SAFE_PARCELABLE)
+    @Override
+    public void writeToParcel(@NonNull Parcel dest, int flags) {
+        SearchSuggestionResultCreator.writeToParcel(this, dest, flags);
+    }
 }
diff --git a/service/java/com/android/server/appsearch/AppSearchManagerService.java b/service/java/com/android/server/appsearch/AppSearchManagerService.java
index 5e05448..07709bf 100644
--- a/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -1493,16 +1493,10 @@
                                     databaseName,
                                     searchQueryExpression,
                                     new SearchSuggestionSpec(searchSuggestionSpecBundle));
-                    List<Bundle> searchSuggestionResultBundles =
-                            new ArrayList<>(searchSuggestionResults.size());
-                    for (int i = 0; i < searchSuggestionResults.size(); i++) {
-                        searchSuggestionResultBundles.add(
-                                searchSuggestionResults.get(i).getBundle());
-                    }
                     ++operationSuccessCount;
                     invokeCallbackOnResult(
                             callback,
-                            AppSearchResult.newSuccessfulResult(searchSuggestionResultBundles));
+                            AppSearchResult.newSuccessfulResult(searchSuggestionResults));
                 } catch (AppSearchException | RuntimeException e) {
                     ++operationFailureCount;
                     AppSearchResult<Void> failedResult = throwableToFailedResult(e);