Merge "Uses ParceledListSlice to allow larger number of datasets." into oc-mr1-dev
diff --git a/core/java/android/service/autofill/FillResponse.java b/core/java/android/service/autofill/FillResponse.java
index e13fdf6..95e8c88 100644
--- a/core/java/android/service/autofill/FillResponse.java
+++ b/core/java/android/service/autofill/FillResponse.java
@@ -23,15 +23,16 @@
 import android.annotation.Nullable;
 import android.app.Activity;
 import android.content.IntentSender;
+import android.content.pm.ParceledListSlice;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillManager;
 import android.widget.RemoteViews;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
 
 /**
  * Response for a {@link
@@ -41,7 +42,7 @@
  */
 public final class FillResponse implements Parcelable {
 
-    private final @Nullable ArrayList<Dataset> mDatasets;
+    private final @Nullable ParceledListSlice<Dataset> mDatasets;
     private final @Nullable SaveInfo mSaveInfo;
     private final @Nullable Bundle mClientState;
     private final @Nullable RemoteViews mPresentation;
@@ -51,7 +52,7 @@
     private int mRequestId;
 
     private FillResponse(@NonNull Builder builder) {
-        mDatasets = builder.mDatasets;
+        mDatasets = (builder.mDatasets != null) ? new ParceledListSlice<>(builder.mDatasets) : null;
         mSaveInfo = builder.mSaveInfo;
         mClientState = builder.mCLientState;
         mPresentation = builder.mPresentation;
@@ -67,8 +68,8 @@
     }
 
     /** @hide */
-    public @Nullable ArrayList<Dataset> getDatasets() {
-        return mDatasets;
+    public @Nullable List<Dataset> getDatasets() {
+        return (mDatasets != null) ? mDatasets.getList() : null;
     }
 
     /** @hide */
@@ -143,12 +144,13 @@
          * for the user to trigger your authentication flow.
          *
          * <p>When a user triggers autofill, the system launches the provided intent
-         * whose extras will have the {@link AutofillManager#EXTRA_ASSIST_STRUCTURE screen
+         * whose extras will have the
+         * {@link android.view.autofill.AutofillManager#EXTRA_ASSIST_STRUCTURE screen
          * content} and your {@link android.view.autofill.AutofillManager#EXTRA_CLIENT_STATE
          * client state}. Once you complete your authentication flow you should set the
          * {@link Activity} result to {@link android.app.Activity#RESULT_OK} and provide the fully
-         * populated {@link FillResponse response} by setting it to the {@link
-         * AutofillManager#EXTRA_AUTHENTICATION_RESULT} extra.
+         * populated {@link FillResponse response} by setting it to the
+         * {@link android.view.autofill.AutofillManager#EXTRA_AUTHENTICATION_RESULT} extra.
          * For example, if you provided an empty {@link FillResponse resppnse} because the
          * user's data was locked and marked that the response needs an authentication then
          * in the response returned if authentication succeeds you need to provide all
@@ -205,6 +207,15 @@
         /**
          * Adds a new {@link Dataset} to this response.
          *
+         * <p><b>Note: </b> on Android {@link android.os.Build.VERSION_CODES#O}, the total number of
+         * datasets is limited by the Binder transaction size, so it's recommended to keep it
+         * small (in the range of 10-20 at most) and use pagination by adding a fake
+         * {@link Dataset.Builder#setAuthentication(IntentSender) authenticated} at the end with
+         * a presentation string like "Next 10" that would return a new {@link FillResponse} with
+         * the next 10 datasets, and so on. This limitation was lifted on
+         * Android {@link android.os.Build.VERSION_CODES#O_MR1}, although the Binder transaction
+         * size can still be reached if each dataset itself is too big.
+         *
          * @return This builder.
          */
         public @NonNull Builder addDataset(@Nullable Dataset dataset) {
@@ -313,7 +324,7 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeTypedArrayList(mDatasets, flags);
+        parcel.writeParcelable(mDatasets, flags);
         parcel.writeParcelable(mSaveInfo, flags);
         parcel.writeParcelable(mClientState, flags);
         parcel.writeParcelableArray(mAuthenticationIds, flags);
@@ -331,7 +342,8 @@
             // the system obeys the contract of the builder to avoid attacks
             // using specially crafted parcels.
             final Builder builder = new Builder();
-            final ArrayList<Dataset> datasets = parcel.readTypedArrayList(null);
+            final ParceledListSlice<Dataset> datasetSlice = parcel.readParcelable(null);
+            final List<Dataset> datasets = (datasetSlice != null) ? datasetSlice.getList() : null;
             final int datasetCount = (datasets != null) ? datasets.size() : 0;
             for (int i = 0; i < datasetCount; i++) {
                 builder.addDataset(datasets.get(i));
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4107756..f8fb13a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -928,7 +928,7 @@
 
                 // Make sure the service doesn't have the fields already by checking the datasets
                 // content.
-                final ArrayList<Dataset> datasets = response.getDatasets();
+                final List<Dataset> datasets = response.getDatasets();
                 if (datasets != null) {
                     datasets_loop: for (int i = 0; i < datasets.size(); i++) {
                         final Dataset dataset = datasets.get(i);
@@ -1157,7 +1157,7 @@
                 }
             }
 
-            final ArrayList<Dataset> datasets = response.getDatasets();
+            final List<Dataset> datasets = response.getDatasets();
             if (datasets != null) {
                 final int numDatasets = datasets.size();
 
@@ -1353,7 +1353,7 @@
         // Must also track that are part of datasets, otherwise the FillUI won't be hidden when
         // they go away (if they're not savable).
 
-        final ArrayList<Dataset> datasets = response.getDatasets();
+        final List<Dataset> datasets = response.getDatasets();
         ArraySet<AutofillId> fillableIds = null;
         if (datasets != null) {
             for (int i = 0; i < datasets.size(); i++) {
@@ -1426,7 +1426,7 @@
      * Sets the state of all views in the given response.
      */
     private void setViewStatesLocked(FillResponse response, int state, boolean clearResponse) {
-        final ArrayList<Dataset> datasets = response.getDatasets();
+        final List<Dataset> datasets = response.getDatasets();
         if (datasets != null) {
             for (int i = 0; i < datasets.size(); i++) {
                 final Dataset dataset = datasets.get(i);