diff options
| author | Philip P. Moltmann <moltmann@google.com> | 2017-04-17 14:18:33 -0700 |
|---|---|---|
| committer | Philip P. Moltmann <moltmann@google.com> | 2017-04-18 16:59:40 -0700 |
| commit | cc684ed41f17ccdce45a056fd4034efc35b213d5 (patch) | |
| tree | 945c876249cccd9dee95c43c5ae33a826b7442f5 /core/java | |
| parent | 7fa4198ab1e44ea8336e177f52ec8fdc501a6904 (diff) | |
Add a way to read the last AutofillSelection.
- Check UID to make sure one service cannot read FillSelections of other
services
- Add id to Dataset to allow to tag the datasets. This id is then found
in the FillSelection.Event
- Add clientState to FillSelection to allow service to store more data
Fixes: 36871500
Test: CtsAutoFillServiceTestCases
Change-Id: Ice894245508227265294a1c59ea97842175e5aec
Diffstat (limited to 'core/java')
6 files changed, 300 insertions, 1 deletions
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java index 5e49b8f0553f..8fcb87c5c0d0 100644 --- a/core/java/android/service/autofill/AutofillService.java +++ b/core/java/android/service/autofill/AutofillService.java @@ -285,4 +285,22 @@ public abstract class AutofillService extends Service { // TODO(b/33197203): Remove when GCore has migrated off this API getSystemService(AutofillManager.class).disableOwnedAutofillServices(); } + + /** + * Returns the {@link FillEventHistory.Event events} since the last {@link FillResponse} was + * returned. + * + * <p>The history is not persisted over reboots. + * + * @return The history or {@code null} if there are not events. + */ + @Nullable public final FillEventHistory getFillEventHistory() { + AutofillManager afm = getSystemService(AutofillManager.class); + + if (afm == null) { + return null; + } else { + return afm.getFillEventHistory(); + } + } } diff --git a/core/java/android/service/autofill/Dataset.java b/core/java/android/service/autofill/Dataset.java index e77bd0d753ac..e04fae7bc2b5 100644 --- a/core/java/android/service/autofill/Dataset.java +++ b/core/java/android/service/autofill/Dataset.java @@ -24,6 +24,7 @@ import android.content.IntentSender; import android.os.Parcel; import android.os.Parcelable; import android.view.autofill.AutofillId; +import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import android.widget.RemoteViews; import com.android.internal.util.Preconditions; @@ -50,6 +51,7 @@ public final class Dataset implements Parcelable { private final ArrayList<RemoteViews> mFieldPresentations; private final RemoteViews mPresentation; private final IntentSender mAuthentication; + @Nullable String mId; private Dataset(Builder builder) { mFieldIds = builder.mFieldIds; @@ -57,6 +59,7 @@ public final class Dataset implements Parcelable { mFieldPresentations = builder.mFieldPresentations; mPresentation = builder.mPresentation; mAuthentication = builder.mAuthentication; + mId = builder.mId; } /** @hide */ @@ -89,7 +92,7 @@ public final class Dataset implements Parcelable { public String toString() { if (!DEBUG) return super.toString(); - return new StringBuilder("Dataset [") + return new StringBuilder("Dataset " + mId + " [") .append("fieldIds=").append(mFieldIds) .append(", fieldValues=").append(mFieldValues) .append(", fieldPresentations=") @@ -100,6 +103,17 @@ public final class Dataset implements Parcelable { } /** + * Gets the id of this dataset. + * + * @return The id of this dataset or {@code null} if not set + * + * @hide + */ + public String getId() { + return mId; + } + + /** * A builder for {@link Dataset} objects. You must to provide at least * one value for a field or set an authentication intent. */ @@ -110,6 +124,7 @@ public final class Dataset implements Parcelable { private RemoteViews mPresentation; private IntentSender mAuthentication; private boolean mDestroyed; + @Nullable private String mId; /** * Creates a new builder. @@ -173,6 +188,25 @@ public final class Dataset implements Parcelable { } /** + * Sets the id for the dataset. + * + * <p>The id of the last selected dataset can be read from + * {@link AutofillService#getFillEventHistory()}. If the id is not set it will not be clear + * if a dataset was selected as {@link AutofillService#getFillEventHistory()} uses + * {@code null} to indicate that no dataset was selected. + * + * @param id id for this dataset or {@code null} to unset. + + * @return This builder. + */ + public @NonNull Builder setId(@Nullable String id) { + throwIfDestroyed(); + + mId = id; + return this; + } + + /** * Sets the value of a field. * * @param id id returned by {@link @@ -269,6 +303,7 @@ public final class Dataset implements Parcelable { parcel.writeTypedArrayList(mFieldValues, flags); parcel.writeParcelableList(mFieldPresentations, flags); parcel.writeParcelable(mAuthentication, flags); + parcel.writeString(mId); } public static final Creator<Dataset> CREATOR = new Creator<Dataset>() { @@ -295,6 +330,7 @@ public final class Dataset implements Parcelable { builder.setValueAndPresentation(id, value, fieldPresentation); } builder.setAuthentication(parcel.readParcelable(null)); + builder.setId(parcel.readString()); return builder.build(); } diff --git a/core/java/android/service/autofill/FillEventHistory.aidl b/core/java/android/service/autofill/FillEventHistory.aidl new file mode 100644 index 000000000000..3c4852423d1b --- /dev/null +++ b/core/java/android/service/autofill/FillEventHistory.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2017, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.autofill; + +parcelable FillEventHistory; diff --git a/core/java/android/service/autofill/FillEventHistory.java b/core/java/android/service/autofill/FillEventHistory.java new file mode 100644 index 000000000000..3d72fccece9c --- /dev/null +++ b/core/java/android/service/autofill/FillEventHistory.java @@ -0,0 +1,208 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.service.autofill; + +import android.annotation.IntDef; +import android.annotation.Nullable; +import android.content.IntentSender; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.view.autofill.AutofillId; +import android.widget.RemoteViews; + +import com.android.internal.util.Preconditions; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +/** + * Describes what happened after the latest call to {@link FillCallback#onSuccess(FillResponse)}. + */ +public final class FillEventHistory implements Parcelable { + /** + * Not in parcel. The UID of the {@link AutofillService} that created the {@link FillResponse}. + */ + private final int mServiceUid; + + @Nullable private final Bundle mClientState; + @Nullable List<Event> mEvents; + + /** + * Gets the UID of the {@link AutofillService} that created the {@link FillResponse}. + * + * @return The UID of the {@link AutofillService} + * + * @hide + */ + public int getServiceUid() { + return mServiceUid; + } + + /** + * Returns the client state of the {@link FillResponse}. + * + * @return The client state set by the last {@link FillResponse} + */ + @Nullable public Bundle getClientState() { + return mClientState; + } + + /** + * Returns the events occurred after the latest call to + * {@link FillCallback#onSuccess(FillResponse)}. + * + * @return The list of events or {@code null} if non occurred. + */ + @Nullable public List<Event> getEvents() { + return mEvents; + } + + /** + * @hide + */ + public void addEvent(Event event) { + if (mEvents == null) { + mEvents = new ArrayList<>(1); + } + mEvents.add(event); + } + + /** + * @hide + */ + public FillEventHistory(int serviceUid, @Nullable Bundle clientState) { + mClientState = clientState; + mServiceUid = serviceUid; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeBundle(mClientState); + + if (mEvents == null) { + dest.writeInt(0); + } else { + dest.writeInt(mEvents.size()); + + int numEvents = mEvents.size(); + for (int i = 0; i < numEvents; i++) { + Event event = mEvents.get(i); + dest.writeInt(event.getType()); + dest.writeString(event.getDatasetId()); + } + } + } + + /** + * Description of an event that occured after the latest call to + * {@link FillCallback#onSuccess(FillResponse)}. + */ + public static final class Event { + /** + * A dataset was selected. The dataset selected can be read from {@link #getDatasetId()}. + */ + public static final int TYPE_DATASET_SELECTED = 0; + + /** + * A {@link Dataset.Builder#setAuthentication(IntentSender) dataset authentication} was + * selected. The dataset authenticated can be read from {@link #getDatasetId()}. + */ + public static final int TYPE_DATASET_AUTHENTICATION_SELECTED = 1; + + /** + * A {@link FillResponse.Builder#setAuthentication(AutofillId[], IntentSender, RemoteViews) + * fill response authentication} was selected. + */ + public static final int TYPE_AUTHENTICATION_SELECTED = 2; + + /** A save UI was shown. */ + public static final int TYPE_SAVE_SHOWN = 3; + + /** @hide */ + @IntDef( + value = {TYPE_DATASET_SELECTED, + TYPE_DATASET_AUTHENTICATION_SELECTED, + TYPE_AUTHENTICATION_SELECTED, + TYPE_SAVE_SHOWN}) + @Retention(RetentionPolicy.SOURCE) + @interface EventIds{} + + @EventIds private final int mEventType; + @Nullable private final String mDatasetId; + + /** + * Returns the type of the event. + * + * @return The type of the event + */ + public int getType() { + return mEventType; + } + + /** + * Returns the id of dataset the id was on. + * + * @return The id of dataset, or {@code null} the event is not associated with a dataset. + */ + @Nullable public String getDatasetId() { + return mDatasetId; + } + + /** + * Creates a new event. + * + * @param eventType The type of the event + * @param datasetId The dataset the event was on, or {@code null} if the event was on the + * whole response. + * + * @hide + */ + public Event(int eventType, String datasetId) { + mEventType = Preconditions.checkArgumentInRange(eventType, 0, TYPE_SAVE_SHOWN, + "eventType"); + mDatasetId = datasetId; + } + } + + public static final Parcelable.Creator<FillEventHistory> CREATOR = + new Parcelable.Creator<FillEventHistory>() { + @Override + public FillEventHistory createFromParcel(Parcel parcel) { + FillEventHistory selection = new FillEventHistory(0, parcel.readBundle()); + + int numEvents = parcel.readInt(); + for (int i = 0; i < numEvents; i++) { + selection.addEvent(new Event(parcel.readInt(), parcel.readString())); + } + + return selection; + } + + @Override + public FillEventHistory[] newArray(int size) { + return new FillEventHistory[size]; + } + }; +} diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index f9f400d83b09..34e30564c10b 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -31,6 +31,8 @@ import android.os.Bundle; import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; +import android.service.autofill.AutofillService; +import android.service.autofill.FillEventHistory; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -334,6 +336,20 @@ public final class AutofillManager { } /** + * Should always be called from {@link AutofillService#getFillEventHistory()}. + * + * @hide + */ + @Nullable public FillEventHistory getFillEventHistory() { + try { + return mService.getFillEventHistory(); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return null; + } + } + + /** * Explicitly requests a new autofill context. * * <p>Normally, the autofill context is automatically started when autofillable views are diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl index 68b3ccabc8be..df777c4a6869 100644 --- a/core/java/android/view/autofill/IAutoFillManager.aidl +++ b/core/java/android/view/autofill/IAutoFillManager.aidl @@ -19,6 +19,7 @@ package android.view.autofill; import android.graphics.Rect; import android.os.Bundle; import android.os.IBinder; +import android.service.autofill.FillEventHistory; import android.view.autofill.AutofillId; import android.view.autofill.AutofillValue; import android.view.autofill.IAutoFillManagerClient; @@ -33,6 +34,7 @@ interface IAutoFillManager { int startSession(IBinder activityToken, IBinder windowToken, in IBinder appCallback, in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags, String packageName); + FillEventHistory getFillEventHistory(); boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback); void setWindow(int sessionId, in IBinder windowToken); void updateSession(int sessionId, in AutofillId id, in Rect bounds, |
