Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 013efe17 authored by Svet Ganov's avatar Svet Ganov
Browse files

Add support for multiple fill contexts

When saving data filled by the user the platform provides to
an autofill provider the state of the UI allowing the provider
to interpret this state and store relevant information.

A limitation of the current design is that the fill provider
needs to interpret the screen content twice, once handling a
fill request and once handling a save request. To address this
we are introducing a id for each fill request allowing the
autofill provider to associate arbitrary state with each fill
request and store it in the client data bundle later passed
to save.

Another limitation of the current design is that if the screen
changes dynamically while the user interacts with the app the
UI state passed on save represents a static snapshot, therefore
it is not possible to the autofill provider to determine the
context in which the data in the UI was filled. We could
keep the views and have deltas for views being removed/added
/moved/changed but this is not enough as the fill provider
needs to know not only what changed but what changed for every
fill request and in one session there could be multiple fill
requests. To address this we provide a list of fill contexts
on save each of which has the id of the corresponding fill
request. This allows the fill provider to know the exact context
in which the data was popuplated and also use its custom client
state for this fill request if desired.

This change deprecates the old APIs and the new ones delegate
to the old ones. Once the clients migrate to the new APIs we
will remove the old ones.

Test: all autofill CTS tests pass

Change-Id: Idcebcc671aa3c078a305d8c358e225274fccc588
parent 9d2f03ec
Loading
Loading
Loading
Loading
+34 −4
Original line number Diff line number Diff line
@@ -37030,8 +37030,10 @@ package android.service.autofill {
    method public final android.os.IBinder onBind(android.content.Intent);
    method public void onConnected();
    method public void onDisconnected();
    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
    method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
    method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
    field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
  }
@@ -37056,6 +37058,25 @@ package android.service.autofill {
    method public void onSuccess(android.service.autofill.FillResponse);
  }
  public final class FillContext implements android.os.Parcelable {
    method public int describeContents();
    method public int getRequestId();
    method public android.app.assist.AssistStructure getStructure();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR;
  }
  public final class FillRequest implements android.os.Parcelable {
    method public int describeContents();
    method public android.os.Bundle getClientState();
    method public int getFlags();
    method public int getId();
    method public android.app.assist.AssistStructure getStructure();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
  }
  public final class FillResponse implements android.os.Parcelable {
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
@@ -37067,7 +37088,8 @@ package android.service.autofill {
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
    method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
  }
@@ -37096,6 +37118,14 @@ package android.service.autofill {
    method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
  }
  public final class SaveRequest implements android.os.Parcelable {
    method public int describeContents();
    method public android.os.Bundle getClientState();
    method public java.util.List<android.service.autofill.FillContext> getFillContexts();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
  }
}
package android.service.carrier {
@@ -47798,7 +47828,7 @@ package android.view.autofill {
    field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
    field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
    field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
    field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
  }
  public static abstract class AutofillManager.AutofillCallback {
+34 −4
Original line number Diff line number Diff line
@@ -40143,8 +40143,10 @@ package android.service.autofill {
    method public final android.os.IBinder onBind(android.content.Intent);
    method public void onConnected();
    method public void onDisconnected();
    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
    method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
    method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
    field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
  }
@@ -40169,6 +40171,25 @@ package android.service.autofill {
    method public void onSuccess(android.service.autofill.FillResponse);
  }
  public final class FillContext implements android.os.Parcelable {
    method public int describeContents();
    method public int getRequestId();
    method public android.app.assist.AssistStructure getStructure();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR;
  }
  public final class FillRequest implements android.os.Parcelable {
    method public int describeContents();
    method public android.os.Bundle getClientState();
    method public int getFlags();
    method public int getId();
    method public android.app.assist.AssistStructure getStructure();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
  }
  public final class FillResponse implements android.os.Parcelable {
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
@@ -40180,7 +40201,8 @@ package android.service.autofill {
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
    method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
  }
@@ -40209,6 +40231,14 @@ package android.service.autofill {
    method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
  }
  public final class SaveRequest implements android.os.Parcelable {
    method public int describeContents();
    method public android.os.Bundle getClientState();
    method public java.util.List<android.service.autofill.FillContext> getFillContexts();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
  }
}
package android.service.carrier {
@@ -51367,7 +51397,7 @@ package android.view.autofill {
    field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
    field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
    field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
    field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
  }
  public static abstract class AutofillManager.AutofillCallback {
+34 −4
Original line number Diff line number Diff line
@@ -37183,8 +37183,10 @@ package android.service.autofill {
    method public final android.os.IBinder onBind(android.content.Intent);
    method public void onConnected();
    method public void onDisconnected();
    method public abstract void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public abstract void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
    method public void onFillRequest(android.service.autofill.FillRequest, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public abstract deprecated void onFillRequest(android.app.assist.AssistStructure, android.os.Bundle, int, android.os.CancellationSignal, android.service.autofill.FillCallback);
    method public void onSaveRequest(android.service.autofill.SaveRequest, android.service.autofill.SaveCallback);
    method public abstract deprecated void onSaveRequest(android.app.assist.AssistStructure, android.os.Bundle, android.service.autofill.SaveCallback);
    field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutofillService";
    field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
  }
@@ -37209,6 +37211,25 @@ package android.service.autofill {
    method public void onSuccess(android.service.autofill.FillResponse);
  }
  public final class FillContext implements android.os.Parcelable {
    method public int describeContents();
    method public int getRequestId();
    method public android.app.assist.AssistStructure getStructure();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.FillContext> CREATOR;
  }
  public final class FillRequest implements android.os.Parcelable {
    method public int describeContents();
    method public android.os.Bundle getClientState();
    method public int getFlags();
    method public int getId();
    method public android.app.assist.AssistStructure getStructure();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.FillRequest> CREATOR;
    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
  }
  public final class FillResponse implements android.os.Parcelable {
    method public int describeContents();
    method public void writeToParcel(android.os.Parcel, int);
@@ -37220,7 +37241,8 @@ package android.service.autofill {
    method public android.service.autofill.FillResponse.Builder addDataset(android.service.autofill.Dataset);
    method public android.service.autofill.FillResponse build();
    method public android.service.autofill.FillResponse.Builder setAuthentication(android.view.autofill.AutofillId[], android.content.IntentSender, android.widget.RemoteViews);
    method public android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setClientState(android.os.Bundle);
    method public deprecated android.service.autofill.FillResponse.Builder setExtras(android.os.Bundle);
    method public android.service.autofill.FillResponse.Builder setSaveInfo(android.service.autofill.SaveInfo);
  }
@@ -37249,6 +37271,14 @@ package android.service.autofill {
    method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
  }
  public final class SaveRequest implements android.os.Parcelable {
    method public int describeContents();
    method public android.os.Bundle getClientState();
    method public java.util.List<android.service.autofill.FillContext> getFillContexts();
    method public void writeToParcel(android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.service.autofill.SaveRequest> CREATOR;
  }
}
package android.service.carrier {
@@ -48176,7 +48206,7 @@ package android.view.autofill {
    field public static final java.lang.String EXTRA_ASSIST_STRUCTURE = "android.view.autofill.extra.ASSIST_STRUCTURE";
    field public static final java.lang.String EXTRA_AUTHENTICATION_RESULT = "android.view.autofill.extra.AUTHENTICATION_RESULT";
    field public static final java.lang.String EXTRA_DATA_EXTRAS = "android.view.autofill.extra.DATA_EXTRAS";
    field public static final int FLAG_MANUAL_REQUEST = 1; // 0x1
    field public static final deprecated int FLAG_MANUAL_REQUEST = 1; // 0x1
  }
  public static abstract class AutofillManager.AutofillCallback {
+56 −18
Original line number Diff line number Diff line
@@ -34,6 +34,8 @@ import android.view.autofill.AutofillManager;

import com.android.internal.os.SomeArgs;

import java.util.List;

//TODO(b/33197203): improve javadoc (of both class and methods); in particular, make sure the
//life-cycle (and how state could be maintained on server-side) is well documented.

@@ -103,24 +105,22 @@ public abstract class AutofillService extends Service {
        }

        @Override
        public void onFillRequest(AssistStructure structure, Bundle extras,
                IFillCallback callback, int flags) {
        public void onFillRequest(FillRequest request, IFillCallback callback) {
            ICancellationSignal transport = CancellationSignal.createTransport();
            try {
                callback.onCancellable(transport);
            } catch (RemoteException e) {
                e.rethrowFromSystemServer();
            }
            mHandlerCaller.obtainMessageIIOOOO(MSG_ON_FILL_REQUEST, flags, UNUSED_ARG, structure,
                    CancellationSignal.fromTransport(transport), extras, callback)
            mHandlerCaller.obtainMessageOOO(MSG_ON_FILL_REQUEST, request,
                    CancellationSignal.fromTransport(transport), callback)
                    .sendToTarget();
        }

        @Override
        public void onSaveRequest(AssistStructure structure, Bundle extras,
                ISaveCallback callback) {
            mHandlerCaller.obtainMessageOOO(MSG_ON_SAVE_REQUEST, structure,
                    extras, callback).sendToTarget();
        public void onSaveRequest(SaveRequest request, ISaveCallback callback) {
            mHandlerCaller.obtainMessageOO(MSG_ON_SAVE_REQUEST, request,
                    callback).sendToTarget();
        }
    };

@@ -131,23 +131,20 @@ public abstract class AutofillService extends Service {
                break;
            } case MSG_ON_FILL_REQUEST: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final AssistStructure structure = (AssistStructure) args.arg1;
                final FillRequest request = (FillRequest) args.arg1;
                final CancellationSignal cancellation = (CancellationSignal) args.arg2;
                final Bundle extras = (Bundle) args.arg3;
                final IFillCallback callback = (IFillCallback) args.arg4;
                final FillCallback fillCallback = new FillCallback(callback);
                final int flags = msg.arg1;
                final IFillCallback callback = (IFillCallback) args.arg3;
                final FillCallback fillCallback = new FillCallback(callback, request.getId());
                args.recycle();
                onFillRequest(structure, extras, flags, cancellation, fillCallback);
                onFillRequest(request, cancellation, fillCallback);
                break;
            } case MSG_ON_SAVE_REQUEST: {
                final SomeArgs args = (SomeArgs) msg.obj;
                final AssistStructure structure = (AssistStructure) args.arg1;
                final Bundle extras = (Bundle) args.arg2;
                final ISaveCallback callback = (ISaveCallback) args.arg3;
                final SaveRequest request = (SaveRequest) args.arg1;
                final ISaveCallback callback = (ISaveCallback) args.arg2;
                final SaveCallback saveCallback = new SaveCallback(callback);
                args.recycle();
                onSaveRequest(structure, extras, saveCallback);
                onSaveRequest(request, saveCallback);
                break;
            } case MSG_DISCONNECT: {
                onDisconnected();
@@ -189,6 +186,28 @@ public abstract class AutofillService extends Service {
    public void onConnected() {
    }

    /**
     * Called by the Android system do decide if an {@link Activity} can be autofilled by the
     * service.
     *
     * <p>Service must call one of the {@link FillCallback} methods (like
     * {@link FillCallback#onSuccess(FillResponse)}
     * or {@link FillCallback#onFailure(CharSequence)})
     * to notify the result of the request.
     *
     * @param request the {@link FillRequest request} to handle.
     *        See {@link FillResponse} for examples of multiple-sections requests.
     * @param cancellationSignal signal for observing cancellation requests. The system will use
     *     this to notify you that the fill result is no longer needed and you should stop
     *     handling this fill request in order to save resources.
     * @param callback object used to notify the result of the request.
     */
    public void onFillRequest(@NonNull FillRequest request,
            @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback) {
        onFillRequest(request.getStructure(), request.getClientState(), request.getFlags(),
                cancellationSignal, callback);
    }

    /**
     * Called by the Android system do decide if an {@link Activity} can be autofilled by the
     * service.
@@ -211,10 +230,28 @@ public abstract class AutofillService extends Service {
     *     handling this fill request in order to save resources.
     * @param callback object used to notify the result of the request.
     */
    @Deprecated
    public abstract void onFillRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
            int flags, @NonNull CancellationSignal cancellationSignal,
            @NonNull FillCallback callback);

    /**
     * Called when user requests service to save the fields of an {@link Activity}.
     *
     * <p>Service must call one of the {@link SaveCallback} methods (like
     * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)})
     * to notify the result of the request.
     *
     * @param request the {@link SaveRequest request} to handle.
     *        See {@link FillResponse} for examples of multiple-sections requests.
     * @param callback object used to notify the result of the request.
     */
    public void onSaveRequest(@NonNull SaveRequest request, @NonNull SaveCallback callback) {
        List<FillContext> contexts = request.getFillContexts();
        onSaveRequest(contexts.get(contexts.size() - 1).getStructure(),
                request.getClientState(), callback);
    }

    /**
     * Called when user requests service to save the fields of an {@link Activity}.
     *
@@ -231,6 +268,7 @@ public abstract class AutofillService extends Service {
     *        See {@link FillResponse} for examples of multiple-sections requests.
     * @param callback object used to notify the result of the request.
     */
    @Deprecated
    public abstract void onSaveRequest(@NonNull AssistStructure structure, @Nullable Bundle data,
            @NonNull SaveCallback callback);

+4 −2
Original line number Diff line number Diff line
@@ -27,11 +27,13 @@ import android.os.RemoteException;
 */
public final class FillCallback {
    private final IFillCallback mCallback;
    private final int mRequestId;
    private boolean mCalled;

    /** @hide */
    public FillCallback(IFillCallback callback) {
    public FillCallback(IFillCallback callback, int requestId) {
        mCallback = callback;
        mRequestId = requestId;
    }

    /**
@@ -47,7 +49,7 @@ public final class FillCallback {
        assertNotCalled();
        mCalled = true;
        try {
            mCallback.onSuccess(response);
            mCallback.onSuccess(response, mRequestId);
        } catch (RemoteException e) {
            e.rethrowAsRuntimeException();
        }
Loading