Loading core/java/android/service/autofill/AutofillService.java +214 −14 Original line number Original line Diff line number Diff line Loading @@ -19,24 +19,230 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.RemoteException; import android.os.RemoteException; import android.provider.Settings; import com.android.internal.os.HandlerCaller; import com.android.internal.os.HandlerCaller; import android.annotation.SdkConstant; import android.annotation.SdkConstant; import android.app.Activity; import android.app.Service;import android.content.Intent; import android.app.Service; import android.content.Intent; import android.os.CancellationSignal; import android.os.CancellationSignal; import android.os.IBinder; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.ICancellationSignal; import android.os.Looper; import android.os.Looper; import android.util.Log; import android.util.Log; import android.view.View; import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import com.android.internal.os.SomeArgs; import com.android.internal.os.SomeArgs; /** /** * Top-level service of the current autofill service for a given user. * An {@code AutofillService} is a service used to automatically fill the contents of the screen * on behalf of a given user - for more information about autofill, read * <a href="{@docRoot}preview/features/autofill.html">Autofill Framework</a>. * * <p>An {@code AutofillService} is only bound to the Android System for autofill purposes if: * <ol> * <li>It requires the {@code android.permission.BIND_AUTOFILL_SERVICE} permission in its * manifest. * <li>The user explicitly enables it using Android Settings (the * {@link Settings#ACTION_REQUEST_SET_AUTOFILL_SERVICE} intent can be used to launch such * Settings screen). * </ol> * * <h3>Basic usage</h3> * * <p>The basic autofill process is defined by the workflow below: * <ol> * <li>User focus an editable {@link View}. * <li>View calls {@link AutofillManager#notifyViewEntered(android.view.View)}. * <li>A {@link ViewStructure} representing all views in the screen is created. * <li>The Android System binds to the service and calls {@link #onConnected()}. * <li>The service receives the view structure through the * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)}. * <li>The service replies through {@link FillCallback#onSuccess(FillResponse)}. * <li>The Android System calls {@link #onDisconnected()} and unbinds from the * {@code AutofillService}. * <li>The Android System displays an UI affordance with the options sent by the service. * <li>The user picks an option. * <li>The proper views are autofilled. * </ol> * * <p>This workflow was designed to minimize the time the Android System is bound to the service; * for each call, it: binds to service, waits for the reply, and unbinds right away. Furthermore, * those calls are considered stateless: if the service needs to keep state between calls, it must * do its own state management (keeping in mind that the service's process might be killed by the * Android System when unbound; for example, if the device is running low in memory). * * <p>Typically, the * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} will: * <ol> * <li>Parse the view structure looking for autofillable views (for example, using * {@link android.app.assist.AssistStructure.ViewNode#getAutofillHints()}. * <li>Match the autofillable views with the user's data. * <li>Create a {@link Dataset} for each set of user's data that match those fields. * <li>Fill the dataset(s) with the proper {@link AutofillId}s and {@link AutofillValue}s. * <li>Add the dataset(s) to the {@link FillResponse} passed to * {@link FillCallback#onSuccess(FillResponse)}. * </ol> * * <p>For example, for a login screen with username and password views where the user only has one * account in the service, the response could be: * * <pre class="prettyprint"> * new FillResponse.Builder() * .addDataset(new Dataset.Builder() * .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer")) * .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer")) * .build()) * .build(); * </pre> * * <p>But if the user had 2 accounts instead, the response could be: * * <pre class="prettyprint"> * new FillResponse.Builder() * .addDataset(new Dataset.Builder() * .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer")) * .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer")) * .build()) * .addDataset(new Dataset.Builder() * .setValue(id1, AutofillValue.forText("flanders"), createPresentation("flanders")) * .setValue(id2, AutofillValue.forText("OkelyDokelyDo"), createPresentation("password for flanders")) * .build()) * .build(); * </pre> * * <p>If the service does not find any autofillable view in the view structure, it should pass * {@code null} to {@link FillCallback#onSuccess(FillResponse)}; if the service encountered an error * processing the request, it should call {@link FillCallback#onFailure(CharSequence)}. For * performance reasons, it's paramount that the service calls either * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)} for * each {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} received - if it * doesn't, the request will eventually time out and be discarded by the Android System. * * <h3>Saving user data</h3> * * <p>If the service is also interested on saving the data filled by the user, it must set a * {@link SaveInfo} object in the {@link FillResponse}. See {@link SaveInfo} for more details and * examples. * * <h3>User authentication</h3> * * <p>The service can provide an extra degree of security by requiring the user to authenticate * before an app can be autofilled. The authentication is typically required in 2 scenarios: * <ul> * <li>To unlock the user data (for example, using a master password or fingerprint * authentication) - see * {@link FillResponse.Builder#setAuthentication(AutofillId[], android.content.IntentSender, android.widget.RemoteViews)}. * <li>To unlock a specific dataset (for example, by providing a CVC for a credit card) - see * {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}. * </ul> * * <p>When using authentication, it is recommended to encrypt only the sensitive data and leave * labels unencrypted, so they can be used on presentation views. For example, if the user has a * home and a work address, the {@code Home} and {@code Work} labels should be stored unencrypted * (since they don't have any sensitive data) while the address data per se could be stored in an * encrypted storage. Then when the user chooses the {@code Home} dataset, the platform starts * the authentication flow, and the service can decrypt the sensitive data. * * * <p>Apps providing autofill capabilities must extend this service. * <p>The authentication mechanism can also be used in scenarios where the service needs multiple * steps to determine the datasets that can fill a screen. For example, when autofilling a financial * app where the user has accounts for multiple banks, the workflow could be: * * <ol> * <li>The first {@link FillResponse} contains datasets with the credentials for the financial * app, plus a "fake" dataset whose presentation says "Tap here for banking apps credentials". * <li>When the user selects the fake dataset, the service displays a dialog with available * banking apps. * <li>When the user select a banking app, the service replies with a new {@link FillResponse} * containing the datasets for that bank. * </ol> * * <p>Another example of multiple-steps dataset selection is when the service stores the user * credentials in "vaults": the first response would contain fake datasets with the vault names, * and the subsequent response would contain the app credentials stored in that vault. * * <h3>Data partitioning</h3> * * <p>The autofillable views in a screen should be grouped in logical groups called "partitions". * Typical partitions are: * <ul> * <li>Credentials (username/email address, password). * <li>Address (street, city, state, zip code, etc). * <li>Payment info (credit card number, expiration date, and verification code). * </ul> * <p>For security reasons, when a screen has more than one partition, it's paramount that the * contents of a dataset do not spawn multiple partitions, specially when one of the partitions * contains data that is not specific to the application being autofilled. For example, a dataset * should not contain fields for username, password, and credit card information. The reason for * this rule is that a malicious app could draft a view structure where the credit card fields * are not visible, so when the user selects a dataset from the username UI, the credit card info is * released to the application without the user knowledge. Similar, it's recommended to always * protect a dataset that contains sensitive information by requiring dataset authentication * (see {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}). * * <p>When the service detects that a screen have multiple partitions, it should return a * {@link FillResponse} with just the datasets for the partition that originated the request (i.e., * the partition that has the {@link android.app.assist.AssistStructure.ViewNode} whose * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} returns {@code true}); then if * the user selects a field from a different partition, the Android System will make another * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} call for that partition, * and so on. * * <p>Notice that when the user autofill a partition with the data provided by the service and the * user did not change these fields, the autofilled value is sent back to the service in the * subsequent calls (and can be obtained by calling * {@link android.app.assist.AssistStructure.ViewNode#getAutofillValue()}). This is useful in the * cases where the service must create datasets for a partition based on the choice made in a * previous partition. For example, the 1st response for a screen that have credentials and address * partitions could be: * * <pre class="prettyprint"> * new FillResponse.Builder() * .addDataset(new Dataset.Builder() // partition 1 (credentials) * .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer")) * .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer")) * .build()) * .addDataset(new Dataset.Builder() // partition 1 (credentials) * .setValue(id1, AutofillValue.forText("flanders"), createPresentation("flanders")) * .setValue(id2, AutofillValue.forText("OkelyDokelyDo"), createPresentation("password for flanders")) * .build()) * .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD, * new AutofillId[] { id1, id2 }) * .build()) * .build(); * </pre> * * <p>Then if the user selected {@code flanders}, the service would get a new * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} call, with the values of * the fields {@code id1} and {@code id2} prepopulated, so the service could then fetch the address * for the Flanders account and return the following {@link FillResponse} for the address partition: * * <pre class="prettyprint"> * new FillResponse.Builder() * .addDataset(new Dataset.Builder() // partition 2 (address) * .setValue(id3, AutofillValue.forText("744 Evergreen Terrace"), createPresentation("744 Evergreen Terrace")) // street * .setValue(id4, AutofillValue.forText("Springfield"), createPresentation("Springfield")) // city * .build()) * .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD | SaveInfo.SAVE_DATA_TYPE_ADDRESS, * new AutofillId[] { id1, id2 }) // username and password * .setOptionalIds(new AutofillId[] { id3, id4 }) // state and zipcode * .build()) * .build(); * </pre> * * <p>When the service returns multiple {@link FillResponse}, the last one overrides the previous; * that's why the {@link SaveInfo} in the 2nd request above has the info for both partitions. * * <h3>Ignoring views</h3> * * <p>If the service find views that cannot be autofilled (for example, a text field representing * the response to a Captcha challenge), it should mark those views as ignored by * calling {@link FillResponse.Builder#setIgnoredIds(AutofillId...)} so the system does not trigger * a new {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} when these views are * focused. */ */ public abstract class AutofillService extends Service { public abstract class AutofillService extends Service { private static final String TAG = "AutofillService"; private static final String TAG = "AutofillService"; Loading Loading @@ -132,11 +338,6 @@ public abstract class AutofillService extends Service { private HandlerCaller mHandlerCaller; private HandlerCaller mHandlerCaller; /** * {@inheritDoc} * * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}. */ @CallSuper @CallSuper @Override @Override public void onCreate() { public void onCreate() { Loading @@ -162,8 +363,7 @@ public abstract class AutofillService extends Service { } } /** /** * Called by the Android system do decide if an {@link Activity} can be autofilled by the * Called by the Android system do decide if a screen can be autofilled by the service. * service. * * * <p>Service must call one of the {@link FillCallback} methods (like * <p>Service must call one of the {@link FillCallback} methods (like * {@link FillCallback#onSuccess(FillResponse)} * {@link FillCallback#onSuccess(FillResponse)} Loading @@ -181,7 +381,7 @@ public abstract class AutofillService extends Service { @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback); @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback); /** /** * Called when user requests service to save the fields of an {@link Activity}. * Called when user requests service to save the fields of a screen. * * * <p>Service must call one of the {@link SaveCallback} methods (like * <p>Service must call one of the {@link SaveCallback} methods (like * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)}) * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)}) Loading Loading @@ -226,7 +426,7 @@ public abstract class AutofillService extends Service { * @return The history or {@code null} if there are no events. * @return The history or {@code null} if there are no events. */ */ @Nullable public final FillEventHistory getFillEventHistory() { @Nullable public final FillEventHistory getFillEventHistory() { AutofillManager afm = getSystemService(AutofillManager.class); final AutofillManager afm = getSystemService(AutofillManager.class); if (afm == null) { if (afm == null) { return null; return null; Loading core/java/android/service/autofill/Dataset.java +29 −21 Original line number Original line Diff line number Diff line Loading @@ -31,17 +31,23 @@ import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.ArrayList; /** /** * A set of data that can be used to autofill an {@link android.app.Activity}. * A dataset object represents a group of key/value pairs used to autofill parts of a screen. * * * <p>It contains: * <p>In its simplest form, a dataset contains one or more key / value pairs (comprised of * {@link AutofillId} and {@link AutofillValue} respectively); and one or more * {@link RemoteViews presentation} for these pairs (a pair could have its own * {@link RemoteViews presentation}, or use the default {@link RemoteViews presentation} associated * with the whole dataset). When an autofill service returns datasets in a {@link FillResponse} * and the screen input is focused in a view that is present in at least one of these datasets, * the Android System displays a UI affordance containing the {@link RemoteViews presentation} of * all datasets pairs that have that view's {@link AutofillId}. Then, when the user selects a * dataset from the affordance, all views in that dataset are autofilled. * * * <ol> * <p>In a more sophisticated form, the dataset value can be protected until the user authenticates * <li>A list of values for input fields. * the dataset - see {@link Dataset.Builder#setAuthentication(IntentSender)}. * <li>A presentation view to visualize. * <li>An optional intent to authenticate. * </ol> * * * @see android.service.autofill.FillResponse for examples. * @see android.service.autofill.AutofillService for more information and examples about the * role of datasets in the autofill workflow. */ */ public final class Dataset implements Parcelable { public final class Dataset implements Parcelable { Loading Loading @@ -113,7 +119,7 @@ public final class Dataset implements Parcelable { } } /** /** * A builder for {@link Dataset} objects. You must to provide at least * A builder for {@link Dataset} objects. You must provide at least * one value for a field or set an authentication intent. * one value for a field or set an authentication intent. */ */ public static final class Builder { public static final class Builder { Loading Loading @@ -175,9 +181,9 @@ public final class Dataset implements Parcelable { * credit card information without the CVV for the data set in the {@link FillResponse * credit card information without the CVV for the data set in the {@link FillResponse * response} then the returned data set should contain the CVV entry. * response} then the returned data set should contain the CVV entry. * * * <p></><strong>Note:</strong> Do not make the provided pending intent * <p><b>NOTE:</b> Do not make the provided pending intent * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the * platform needs to fill in the authentication arguments.</p> * platform needs to fill in the authentication arguments. * * * @param authentication Intent to an activity with your authentication flow. * @param authentication Intent to an activity with your authentication flow. * @return This builder. * @return This builder. Loading @@ -191,7 +197,7 @@ public final class Dataset implements Parcelable { } } /** /** * Sets the id for the dataset. * Sets the id for the dataset so its usage history can be retrieved later. * * * <p>The id of the last selected dataset can be read from * <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 * {@link AutofillService#getFillEventHistory()}. If the id is not set it will not be clear Loading @@ -217,10 +223,9 @@ public final class Dataset implements Parcelable { * @param value value to be autofilled. Pass {@code null} if you do not have the value * @param value value to be autofilled. Pass {@code null} if you do not have the value * but the target view is a logical part of the dataset. For example, if * but the target view is a logical part of the dataset. For example, if * the dataset needs an authentication and you have no access to the value. * the dataset needs an authentication and you have no access to the value. * Filtering matches any user typed string to {@code null} values. * @return This builder. * @return This builder. * @throws IllegalStateException if the builder was constructed without a presentation * @throws IllegalStateException if the builder was constructed without a * ({@link RemoteViews}). * {@link RemoteViews presentation}. */ */ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) { public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) { throwIfDestroyed(); throwIfDestroyed(); Loading @@ -232,7 +237,8 @@ public final class Dataset implements Parcelable { } } /** /** * Sets the value of a field, using a custom presentation to visualize it. * Sets the value of a field, using a custom {@link RemoteViews presentation} to * visualize it. * * * @param id id returned by {@link * @param id id returned by {@link * android.app.assist.AssistStructure.ViewNode#getAutofillId()}. * android.app.assist.AssistStructure.ViewNode#getAutofillId()}. Loading Loading @@ -272,10 +278,12 @@ public final class Dataset implements Parcelable { } } /** /** * Creates a new {@link Dataset} instance. You should not interact * Creates a new {@link Dataset} instance. * with this builder once this method is called. It is required * * that you specified at least one field. Also it is mandatory to * <p>You should not interact with this builder once this method is called. * provide a presentation view to visualize the data set in the UI. * * <p>It is required that you specify at least one field before calling this method. It's * also mandatory to provide a presentation view to visualize the data set in the UI. * * * @return The built dataset. * @return The built dataset. */ */ Loading core/java/android/service/autofill/FillContext.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.util.ArrayMap; import android.util.SparseIntArray; import android.util.SparseIntArray; import android.view.autofill.AutofillId; import android.view.autofill.AutofillId; import java.util.ArrayList; import java.util.LinkedList; import java.util.LinkedList; /** /** Loading core/java/android/service/autofill/FillRequest.java +30 −8 Original line number Original line Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.Bundle; import android.os.CancellationSignal; import android.os.CancellationSignal; import android.os.Parcel; import android.os.Parcel; import android.os.Parcelable; import android.os.Parcelable; import android.view.View; import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions; Loading @@ -32,7 +33,7 @@ import java.util.ArrayList; import java.util.List; import java.util.List; /** /** * This class represents a request to an {@link AutofillService autofill provider} * This class represents a request to an autofill service * to interpret the screen and provide information to the system which views are * to interpret the screen and provide information to the system which views are * interesting for saving and what are the possible ways to fill the inputs on * interesting for saving and what are the possible ways to fill the inputs on * the screen if applicable. * the screen if applicable. Loading @@ -40,8 +41,29 @@ import java.util.List; * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) */ */ public final class FillRequest implements Parcelable { public final class FillRequest implements Parcelable { /** /** * Indicates autofill was explicitly requested by the user. * Indicates autofill was explicitly requested by the user. * * <p>Users typically make an explicit request to autofill a screen in two situations: * <ul> * <li>The app disabled autofill (using {@link View#setImportantForAutofill(int)}. * <li>The service could not figure out how to autofill a screen (but the user knows the * service has data for that app). * </ul> * * <p>This flag is particularly useful for the second case. For example, the service could offer * a complex UI where the user can map which screen views belong to each user data, or it could * offer a simpler UI where the user picks the data for just the view used to trigger the * request (that would be the view whose * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} method returns {@code true}). * * <p>An explicit autofill request is triggered when the * {@link android.view.autofill.AutofillManager#requestAutofill(View)} or * {@link android.view.autofill.AutofillManager#requestAutofill(View, int, android.graphics.Rect)} * is called. For example, standard {@link android.widget.TextView} views that use * an {@link android.widget.Editor} shows an {@code AUTOFILL} option in the overflow menu that * triggers such request. */ */ public static final int FLAG_MANUAL_REQUEST = 0x1; public static final int FLAG_MANUAL_REQUEST = 0x1; Loading Loading @@ -79,14 +101,14 @@ public final class FillRequest implements Parcelable { } } /** /** * @return The unique id of this request. * Gets the unique id of this request. */ */ public int getId() { public int getId() { return mId; return mId; } } /** /** * @return The flags associated with this request. * Gets the flags associated with this request. * * * @see #FLAG_MANUAL_REQUEST * @see #FLAG_MANUAL_REQUEST */ */ Loading @@ -95,7 +117,7 @@ public final class FillRequest implements Parcelable { } } /** /** * @return The contexts associated with each previous fill request. * Gets the contexts associated with each previous fill request. */ */ public @NonNull List<FillContext> getFillContexts() { public @NonNull List<FillContext> getFillContexts() { return mContexts; return mContexts; Loading @@ -104,10 +126,10 @@ public final class FillRequest implements Parcelable { /** /** * Gets the extra client state returned from the last {@link * Gets the extra client state returned from the last {@link * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) * fill request}. * fill request}, so the service can use it for state management. * <p> * * Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) * save request} is made the client state is cleared. * save request} is made, the client state is cleared. * * * @return The client state. * @return The client state. */ */ Loading core/java/android/service/autofill/FillResponse.java +14 −107 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
core/java/android/service/autofill/AutofillService.java +214 −14 Original line number Original line Diff line number Diff line Loading @@ -19,24 +19,230 @@ import android.annotation.CallSuper; import android.annotation.NonNull; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Nullable; import android.os.RemoteException; import android.os.RemoteException; import android.provider.Settings; import com.android.internal.os.HandlerCaller; import com.android.internal.os.HandlerCaller; import android.annotation.SdkConstant; import android.annotation.SdkConstant; import android.app.Activity; import android.app.Service;import android.content.Intent; import android.app.Service; import android.content.Intent; import android.os.CancellationSignal; import android.os.CancellationSignal; import android.os.IBinder; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.ICancellationSignal; import android.os.Looper; import android.os.Looper; import android.util.Log; import android.util.Log; import android.view.View; import android.view.ViewStructure; import android.view.autofill.AutofillId; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillManager; import android.view.autofill.AutofillValue; import com.android.internal.os.SomeArgs; import com.android.internal.os.SomeArgs; /** /** * Top-level service of the current autofill service for a given user. * An {@code AutofillService} is a service used to automatically fill the contents of the screen * on behalf of a given user - for more information about autofill, read * <a href="{@docRoot}preview/features/autofill.html">Autofill Framework</a>. * * <p>An {@code AutofillService} is only bound to the Android System for autofill purposes if: * <ol> * <li>It requires the {@code android.permission.BIND_AUTOFILL_SERVICE} permission in its * manifest. * <li>The user explicitly enables it using Android Settings (the * {@link Settings#ACTION_REQUEST_SET_AUTOFILL_SERVICE} intent can be used to launch such * Settings screen). * </ol> * * <h3>Basic usage</h3> * * <p>The basic autofill process is defined by the workflow below: * <ol> * <li>User focus an editable {@link View}. * <li>View calls {@link AutofillManager#notifyViewEntered(android.view.View)}. * <li>A {@link ViewStructure} representing all views in the screen is created. * <li>The Android System binds to the service and calls {@link #onConnected()}. * <li>The service receives the view structure through the * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)}. * <li>The service replies through {@link FillCallback#onSuccess(FillResponse)}. * <li>The Android System calls {@link #onDisconnected()} and unbinds from the * {@code AutofillService}. * <li>The Android System displays an UI affordance with the options sent by the service. * <li>The user picks an option. * <li>The proper views are autofilled. * </ol> * * <p>This workflow was designed to minimize the time the Android System is bound to the service; * for each call, it: binds to service, waits for the reply, and unbinds right away. Furthermore, * those calls are considered stateless: if the service needs to keep state between calls, it must * do its own state management (keeping in mind that the service's process might be killed by the * Android System when unbound; for example, if the device is running low in memory). * * <p>Typically, the * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} will: * <ol> * <li>Parse the view structure looking for autofillable views (for example, using * {@link android.app.assist.AssistStructure.ViewNode#getAutofillHints()}. * <li>Match the autofillable views with the user's data. * <li>Create a {@link Dataset} for each set of user's data that match those fields. * <li>Fill the dataset(s) with the proper {@link AutofillId}s and {@link AutofillValue}s. * <li>Add the dataset(s) to the {@link FillResponse} passed to * {@link FillCallback#onSuccess(FillResponse)}. * </ol> * * <p>For example, for a login screen with username and password views where the user only has one * account in the service, the response could be: * * <pre class="prettyprint"> * new FillResponse.Builder() * .addDataset(new Dataset.Builder() * .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer")) * .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer")) * .build()) * .build(); * </pre> * * <p>But if the user had 2 accounts instead, the response could be: * * <pre class="prettyprint"> * new FillResponse.Builder() * .addDataset(new Dataset.Builder() * .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer")) * .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer")) * .build()) * .addDataset(new Dataset.Builder() * .setValue(id1, AutofillValue.forText("flanders"), createPresentation("flanders")) * .setValue(id2, AutofillValue.forText("OkelyDokelyDo"), createPresentation("password for flanders")) * .build()) * .build(); * </pre> * * <p>If the service does not find any autofillable view in the view structure, it should pass * {@code null} to {@link FillCallback#onSuccess(FillResponse)}; if the service encountered an error * processing the request, it should call {@link FillCallback#onFailure(CharSequence)}. For * performance reasons, it's paramount that the service calls either * {@link FillCallback#onSuccess(FillResponse)} or {@link FillCallback#onFailure(CharSequence)} for * each {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} received - if it * doesn't, the request will eventually time out and be discarded by the Android System. * * <h3>Saving user data</h3> * * <p>If the service is also interested on saving the data filled by the user, it must set a * {@link SaveInfo} object in the {@link FillResponse}. See {@link SaveInfo} for more details and * examples. * * <h3>User authentication</h3> * * <p>The service can provide an extra degree of security by requiring the user to authenticate * before an app can be autofilled. The authentication is typically required in 2 scenarios: * <ul> * <li>To unlock the user data (for example, using a master password or fingerprint * authentication) - see * {@link FillResponse.Builder#setAuthentication(AutofillId[], android.content.IntentSender, android.widget.RemoteViews)}. * <li>To unlock a specific dataset (for example, by providing a CVC for a credit card) - see * {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}. * </ul> * * <p>When using authentication, it is recommended to encrypt only the sensitive data and leave * labels unencrypted, so they can be used on presentation views. For example, if the user has a * home and a work address, the {@code Home} and {@code Work} labels should be stored unencrypted * (since they don't have any sensitive data) while the address data per se could be stored in an * encrypted storage. Then when the user chooses the {@code Home} dataset, the platform starts * the authentication flow, and the service can decrypt the sensitive data. * * * <p>Apps providing autofill capabilities must extend this service. * <p>The authentication mechanism can also be used in scenarios where the service needs multiple * steps to determine the datasets that can fill a screen. For example, when autofilling a financial * app where the user has accounts for multiple banks, the workflow could be: * * <ol> * <li>The first {@link FillResponse} contains datasets with the credentials for the financial * app, plus a "fake" dataset whose presentation says "Tap here for banking apps credentials". * <li>When the user selects the fake dataset, the service displays a dialog with available * banking apps. * <li>When the user select a banking app, the service replies with a new {@link FillResponse} * containing the datasets for that bank. * </ol> * * <p>Another example of multiple-steps dataset selection is when the service stores the user * credentials in "vaults": the first response would contain fake datasets with the vault names, * and the subsequent response would contain the app credentials stored in that vault. * * <h3>Data partitioning</h3> * * <p>The autofillable views in a screen should be grouped in logical groups called "partitions". * Typical partitions are: * <ul> * <li>Credentials (username/email address, password). * <li>Address (street, city, state, zip code, etc). * <li>Payment info (credit card number, expiration date, and verification code). * </ul> * <p>For security reasons, when a screen has more than one partition, it's paramount that the * contents of a dataset do not spawn multiple partitions, specially when one of the partitions * contains data that is not specific to the application being autofilled. For example, a dataset * should not contain fields for username, password, and credit card information. The reason for * this rule is that a malicious app could draft a view structure where the credit card fields * are not visible, so when the user selects a dataset from the username UI, the credit card info is * released to the application without the user knowledge. Similar, it's recommended to always * protect a dataset that contains sensitive information by requiring dataset authentication * (see {@link Dataset.Builder#setAuthentication(android.content.IntentSender)}). * * <p>When the service detects that a screen have multiple partitions, it should return a * {@link FillResponse} with just the datasets for the partition that originated the request (i.e., * the partition that has the {@link android.app.assist.AssistStructure.ViewNode} whose * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} returns {@code true}); then if * the user selects a field from a different partition, the Android System will make another * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} call for that partition, * and so on. * * <p>Notice that when the user autofill a partition with the data provided by the service and the * user did not change these fields, the autofilled value is sent back to the service in the * subsequent calls (and can be obtained by calling * {@link android.app.assist.AssistStructure.ViewNode#getAutofillValue()}). This is useful in the * cases where the service must create datasets for a partition based on the choice made in a * previous partition. For example, the 1st response for a screen that have credentials and address * partitions could be: * * <pre class="prettyprint"> * new FillResponse.Builder() * .addDataset(new Dataset.Builder() // partition 1 (credentials) * .setValue(id1, AutofillValue.forText("homer"), createPresentation("homer")) * .setValue(id2, AutofillValue.forText("D'OH!"), createPresentation("password for homer")) * .build()) * .addDataset(new Dataset.Builder() // partition 1 (credentials) * .setValue(id1, AutofillValue.forText("flanders"), createPresentation("flanders")) * .setValue(id2, AutofillValue.forText("OkelyDokelyDo"), createPresentation("password for flanders")) * .build()) * .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD, * new AutofillId[] { id1, id2 }) * .build()) * .build(); * </pre> * * <p>Then if the user selected {@code flanders}, the service would get a new * {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} call, with the values of * the fields {@code id1} and {@code id2} prepopulated, so the service could then fetch the address * for the Flanders account and return the following {@link FillResponse} for the address partition: * * <pre class="prettyprint"> * new FillResponse.Builder() * .addDataset(new Dataset.Builder() // partition 2 (address) * .setValue(id3, AutofillValue.forText("744 Evergreen Terrace"), createPresentation("744 Evergreen Terrace")) // street * .setValue(id4, AutofillValue.forText("Springfield"), createPresentation("Springfield")) // city * .build()) * .setSaveInfo(new SaveInfo.Builder(SaveInfo.SAVE_DATA_TYPE_PASSWORD | SaveInfo.SAVE_DATA_TYPE_ADDRESS, * new AutofillId[] { id1, id2 }) // username and password * .setOptionalIds(new AutofillId[] { id3, id4 }) // state and zipcode * .build()) * .build(); * </pre> * * <p>When the service returns multiple {@link FillResponse}, the last one overrides the previous; * that's why the {@link SaveInfo} in the 2nd request above has the info for both partitions. * * <h3>Ignoring views</h3> * * <p>If the service find views that cannot be autofilled (for example, a text field representing * the response to a Captcha challenge), it should mark those views as ignored by * calling {@link FillResponse.Builder#setIgnoredIds(AutofillId...)} so the system does not trigger * a new {@link #onFillRequest(FillRequest, CancellationSignal, FillCallback)} when these views are * focused. */ */ public abstract class AutofillService extends Service { public abstract class AutofillService extends Service { private static final String TAG = "AutofillService"; private static final String TAG = "AutofillService"; Loading Loading @@ -132,11 +338,6 @@ public abstract class AutofillService extends Service { private HandlerCaller mHandlerCaller; private HandlerCaller mHandlerCaller; /** * {@inheritDoc} * * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}. */ @CallSuper @CallSuper @Override @Override public void onCreate() { public void onCreate() { Loading @@ -162,8 +363,7 @@ public abstract class AutofillService extends Service { } } /** /** * Called by the Android system do decide if an {@link Activity} can be autofilled by the * Called by the Android system do decide if a screen can be autofilled by the service. * service. * * * <p>Service must call one of the {@link FillCallback} methods (like * <p>Service must call one of the {@link FillCallback} methods (like * {@link FillCallback#onSuccess(FillResponse)} * {@link FillCallback#onSuccess(FillResponse)} Loading @@ -181,7 +381,7 @@ public abstract class AutofillService extends Service { @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback); @NonNull CancellationSignal cancellationSignal, @NonNull FillCallback callback); /** /** * Called when user requests service to save the fields of an {@link Activity}. * Called when user requests service to save the fields of a screen. * * * <p>Service must call one of the {@link SaveCallback} methods (like * <p>Service must call one of the {@link SaveCallback} methods (like * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)}) * {@link SaveCallback#onSuccess()} or {@link SaveCallback#onFailure(CharSequence)}) Loading Loading @@ -226,7 +426,7 @@ public abstract class AutofillService extends Service { * @return The history or {@code null} if there are no events. * @return The history or {@code null} if there are no events. */ */ @Nullable public final FillEventHistory getFillEventHistory() { @Nullable public final FillEventHistory getFillEventHistory() { AutofillManager afm = getSystemService(AutofillManager.class); final AutofillManager afm = getSystemService(AutofillManager.class); if (afm == null) { if (afm == null) { return null; return null; Loading
core/java/android/service/autofill/Dataset.java +29 −21 Original line number Original line Diff line number Diff line Loading @@ -31,17 +31,23 @@ import com.android.internal.util.Preconditions; import java.util.ArrayList; import java.util.ArrayList; /** /** * A set of data that can be used to autofill an {@link android.app.Activity}. * A dataset object represents a group of key/value pairs used to autofill parts of a screen. * * * <p>It contains: * <p>In its simplest form, a dataset contains one or more key / value pairs (comprised of * {@link AutofillId} and {@link AutofillValue} respectively); and one or more * {@link RemoteViews presentation} for these pairs (a pair could have its own * {@link RemoteViews presentation}, or use the default {@link RemoteViews presentation} associated * with the whole dataset). When an autofill service returns datasets in a {@link FillResponse} * and the screen input is focused in a view that is present in at least one of these datasets, * the Android System displays a UI affordance containing the {@link RemoteViews presentation} of * all datasets pairs that have that view's {@link AutofillId}. Then, when the user selects a * dataset from the affordance, all views in that dataset are autofilled. * * * <ol> * <p>In a more sophisticated form, the dataset value can be protected until the user authenticates * <li>A list of values for input fields. * the dataset - see {@link Dataset.Builder#setAuthentication(IntentSender)}. * <li>A presentation view to visualize. * <li>An optional intent to authenticate. * </ol> * * * @see android.service.autofill.FillResponse for examples. * @see android.service.autofill.AutofillService for more information and examples about the * role of datasets in the autofill workflow. */ */ public final class Dataset implements Parcelable { public final class Dataset implements Parcelable { Loading Loading @@ -113,7 +119,7 @@ public final class Dataset implements Parcelable { } } /** /** * A builder for {@link Dataset} objects. You must to provide at least * A builder for {@link Dataset} objects. You must provide at least * one value for a field or set an authentication intent. * one value for a field or set an authentication intent. */ */ public static final class Builder { public static final class Builder { Loading Loading @@ -175,9 +181,9 @@ public final class Dataset implements Parcelable { * credit card information without the CVV for the data set in the {@link FillResponse * credit card information without the CVV for the data set in the {@link FillResponse * response} then the returned data set should contain the CVV entry. * response} then the returned data set should contain the CVV entry. * * * <p></><strong>Note:</strong> Do not make the provided pending intent * <p><b>NOTE:</b> Do not make the provided pending intent * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the * immutable by using {@link android.app.PendingIntent#FLAG_IMMUTABLE} as the * platform needs to fill in the authentication arguments.</p> * platform needs to fill in the authentication arguments. * * * @param authentication Intent to an activity with your authentication flow. * @param authentication Intent to an activity with your authentication flow. * @return This builder. * @return This builder. Loading @@ -191,7 +197,7 @@ public final class Dataset implements Parcelable { } } /** /** * Sets the id for the dataset. * Sets the id for the dataset so its usage history can be retrieved later. * * * <p>The id of the last selected dataset can be read from * <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 * {@link AutofillService#getFillEventHistory()}. If the id is not set it will not be clear Loading @@ -217,10 +223,9 @@ public final class Dataset implements Parcelable { * @param value value to be autofilled. Pass {@code null} if you do not have the value * @param value value to be autofilled. Pass {@code null} if you do not have the value * but the target view is a logical part of the dataset. For example, if * but the target view is a logical part of the dataset. For example, if * the dataset needs an authentication and you have no access to the value. * the dataset needs an authentication and you have no access to the value. * Filtering matches any user typed string to {@code null} values. * @return This builder. * @return This builder. * @throws IllegalStateException if the builder was constructed without a presentation * @throws IllegalStateException if the builder was constructed without a * ({@link RemoteViews}). * {@link RemoteViews presentation}. */ */ public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) { public @NonNull Builder setValue(@NonNull AutofillId id, @Nullable AutofillValue value) { throwIfDestroyed(); throwIfDestroyed(); Loading @@ -232,7 +237,8 @@ public final class Dataset implements Parcelable { } } /** /** * Sets the value of a field, using a custom presentation to visualize it. * Sets the value of a field, using a custom {@link RemoteViews presentation} to * visualize it. * * * @param id id returned by {@link * @param id id returned by {@link * android.app.assist.AssistStructure.ViewNode#getAutofillId()}. * android.app.assist.AssistStructure.ViewNode#getAutofillId()}. Loading Loading @@ -272,10 +278,12 @@ public final class Dataset implements Parcelable { } } /** /** * Creates a new {@link Dataset} instance. You should not interact * Creates a new {@link Dataset} instance. * with this builder once this method is called. It is required * * that you specified at least one field. Also it is mandatory to * <p>You should not interact with this builder once this method is called. * provide a presentation view to visualize the data set in the UI. * * <p>It is required that you specify at least one field before calling this method. It's * also mandatory to provide a presentation view to visualize the data set in the UI. * * * @return The built dataset. * @return The built dataset. */ */ Loading
core/java/android/service/autofill/FillContext.java +0 −1 Original line number Original line Diff line number Diff line Loading @@ -30,7 +30,6 @@ import android.util.ArrayMap; import android.util.SparseIntArray; import android.util.SparseIntArray; import android.view.autofill.AutofillId; import android.view.autofill.AutofillId; import java.util.ArrayList; import java.util.LinkedList; import java.util.LinkedList; /** /** Loading
core/java/android/service/autofill/FillRequest.java +30 −8 Original line number Original line Diff line number Diff line Loading @@ -23,6 +23,7 @@ import android.os.Bundle; import android.os.CancellationSignal; import android.os.CancellationSignal; import android.os.Parcel; import android.os.Parcel; import android.os.Parcelable; import android.os.Parcelable; import android.view.View; import com.android.internal.util.Preconditions; import com.android.internal.util.Preconditions; Loading @@ -32,7 +33,7 @@ import java.util.ArrayList; import java.util.List; import java.util.List; /** /** * This class represents a request to an {@link AutofillService autofill provider} * This class represents a request to an autofill service * to interpret the screen and provide information to the system which views are * to interpret the screen and provide information to the system which views are * interesting for saving and what are the possible ways to fill the inputs on * interesting for saving and what are the possible ways to fill the inputs on * the screen if applicable. * the screen if applicable. Loading @@ -40,8 +41,29 @@ import java.util.List; * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) * @see AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) */ */ public final class FillRequest implements Parcelable { public final class FillRequest implements Parcelable { /** /** * Indicates autofill was explicitly requested by the user. * Indicates autofill was explicitly requested by the user. * * <p>Users typically make an explicit request to autofill a screen in two situations: * <ul> * <li>The app disabled autofill (using {@link View#setImportantForAutofill(int)}. * <li>The service could not figure out how to autofill a screen (but the user knows the * service has data for that app). * </ul> * * <p>This flag is particularly useful for the second case. For example, the service could offer * a complex UI where the user can map which screen views belong to each user data, or it could * offer a simpler UI where the user picks the data for just the view used to trigger the * request (that would be the view whose * {@link android.app.assist.AssistStructure.ViewNode#isFocused()} method returns {@code true}). * * <p>An explicit autofill request is triggered when the * {@link android.view.autofill.AutofillManager#requestAutofill(View)} or * {@link android.view.autofill.AutofillManager#requestAutofill(View, int, android.graphics.Rect)} * is called. For example, standard {@link android.widget.TextView} views that use * an {@link android.widget.Editor} shows an {@code AUTOFILL} option in the overflow menu that * triggers such request. */ */ public static final int FLAG_MANUAL_REQUEST = 0x1; public static final int FLAG_MANUAL_REQUEST = 0x1; Loading Loading @@ -79,14 +101,14 @@ public final class FillRequest implements Parcelable { } } /** /** * @return The unique id of this request. * Gets the unique id of this request. */ */ public int getId() { public int getId() { return mId; return mId; } } /** /** * @return The flags associated with this request. * Gets the flags associated with this request. * * * @see #FLAG_MANUAL_REQUEST * @see #FLAG_MANUAL_REQUEST */ */ Loading @@ -95,7 +117,7 @@ public final class FillRequest implements Parcelable { } } /** /** * @return The contexts associated with each previous fill request. * Gets the contexts associated with each previous fill request. */ */ public @NonNull List<FillContext> getFillContexts() { public @NonNull List<FillContext> getFillContexts() { return mContexts; return mContexts; Loading @@ -104,10 +126,10 @@ public final class FillRequest implements Parcelable { /** /** * Gets the extra client state returned from the last {@link * Gets the extra client state returned from the last {@link * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) * AutofillService#onFillRequest(FillRequest, CancellationSignal, FillCallback) * fill request}. * fill request}, so the service can use it for state management. * <p> * * Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) * <p>Once a {@link AutofillService#onSaveRequest(SaveRequest, SaveCallback) * save request} is made the client state is cleared. * save request} is made, the client state is cleared. * * * @return The client state. * @return The client state. */ */ Loading
core/java/android/service/autofill/FillResponse.java +14 −107 File changed.Preview size limit exceeded, changes collapsed. Show changes