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);