Save the date! Android Dev Summit is coming to Mountain View, CA on November 7-8, 2018.

Autofill Framework

Learn about the Autofill Framework available in Android 8.0 (API level 26) and later.

Users can save time filling out forms by using autofill in their devices. Android makes filling forms, such as account and credit card forms, easier with the introduction of the Autofill Framework. The Autofill Framework manages the communication between the app and an autofill service.

Benefits

Filling out forms is a time-consuming and error-prone task. Users can easily get frustrated with apps that require these type of tasks. The Autofill Framework improves the user experience by providing the following benefits:

  • Less time spent in filling fields Autofill saves users from re-typing information.
  • Minimize user input errors Typing is prone to errors, especially in mobile devices. Removing the necessity of typing information also removes the errors that come with it.

Combined, these benefits mean users of your app are able to use your features more efficiently and with less frustration from errors.

Prerequisites

An Autofill service must be configured on your device for your app to use the Autofill framework. While most Android 8.0 phones and tables ship with an Autofill service, we recommend that you use a test service when testing your app, such as the Autofill service in the Android Autofill Framework sample. When you're using an emulator you must explicitly set an autofill service as the emulator may not come with a default service.

After you have installed the test autofill service from the sample app, you should enable the autofill service in Settings > System > Languages & input > Advanced > Input assistance > Autofill service.

See Test your app with autofill for more information about configuring an emulator for testing Autofill.

Optimizing your app for autofill

Apps that use standard views work with the Autofill Framework out of the box. However, you can take some steps to optimize how your app works with the framework. For a guided tutorial, see the Optimize your app for autofill codelab.

Providing hints for autofill

The Autofill service attempts to determine the type of all views via heuristics. However, if your app relies on these heuristics Autofill behavior may unexpectedly change as you update app. To ensure that the Autofill service correctly identifies your app's forms, you should provide Autofill hints.

You can set these hints using the android:autofillHints attribute:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:autofillHints="password" />

You may also set them using the setAutofillHints() method:

TextView password = findViewById(R.id.password);
password.setAutofillHints(View.AUTOFILL_HINT_PASSWORD);

The Autofill Framework doesn't validate the hints; they are just passed along as is to the autofill service. Hence, they can have any value, but it is recommended to use predefined values such as AUTOFILL_HINT_USERNAME for a username or AUTOFILL_HINT_CREDIT_CARD_NUMBER for a credit card number. For a list of all predefined autofill hint constants, see the View reference.

Mark fields as important for autofill

You can tell the system whether the individual fields in your app should be included in a view structure for autofill purposes. By default, the view uses the IMPORTANT_FOR_AUTOFILL_AUTO mode, which lets Android use its heuristics to determine if the view is important for autofill.

You can set the importance using the android:importantForAutofill attribute:

<TextView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:importantForAutofill="no" />

The value of importantForAutofill may be any of the values defined in android:importantForAutofill:

auto
Let the Android System use its heuristics to determine if the view is important for autofill.
no
This view is not important for autofill.
noExcludeDescendants
This view, and its children, are not important for autofill.
yes
This view is important for autofill.
yesExcludeDescendants
This view is important for autofill, but its children are not important for autofill.

You can also use the setImportantForAutofill() method:

TextView captcha = findViewById(R.id.captcha);
captcha.setImportantForAutofill(View.IMPORTANT_FOR_AUTOFILL_NO);

There are cases when a view, a view structure, or the whole activity isn't important for autofill:

  • A CAPTCHA field in a login activity is usually not important for autofill. In cases like this, you can mark the view as IMPORTANT_FOR_AUTOFILL_NO.
  • In a view where the user creates content, such as a text or spreadsheet editor, the whole view structure is usually not important for autofill. In cases like this, you can mark the view as IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS to make sure that all the children are also marked as not important for autofill.
  • In some activities within gaming apps, such as those that display gameplay, none of the views in the activities are important for autofill. You can mark the root view as IMPORTANT_FOR_AUTOFILL_NO_EXCLUDE_DESCENDANTS to ensure that all the views in the activity are marked as not important for autofill.

Associate website and mobile app data

Autofill services, such as Autofill with Google, are able to share user login data between the browser and Android devices after the app and website are associated. When a user chooses the same autofill service on both platforms, they can sign-in to your web app and the login credentials are available to autofill when the same user signs-in on Android.

To associate your Android app with your website you must host a Digital Asset Link with the delegate_permission/common.get_login_creds relation in your site. Then, declare the association in your app's AndroidManifest.xml file. For detailed instructions about how to associate your website with your Android app, see Enable automatic sign-in across apps and websites.

Determine if autofill is enabled

You can implement additional autofill functionality in your app, or even in particular views of your app, if autofill is available to the user. For example, TextView shows an autofill entry in the overflow menu if autofill is enabled to the user. To check if autofill is enabled for the user, call the isEnabled() method of the AutofillManager object (see Addressing known issues to learn more).

Users can enable or disable autofill as well as change the autofill service in Settings > System > Languages & input > Advanced > Input assistance > Autofill service. Your app cannot override the user's Autofill settings.

To ensure your sign up and login experience is optimized for users without Autofill consider implementing Smart Lock for Passwords.

Force an autofill request

Sometimes, you may need to force an autofill request to occur in response to a user action. For example, TextView offers an autofill menu item when the user long-presses the view. The following code example shows how to force an autofill request:

public void eventHandler(View view) {
    AutofillManager afm = context.getSystemService(AutofillManager.class);
    if (afm != null) {
        afm.requestAutofill();
    }
}

You can also use the cancel() method to cancel the current autofill context. This can be useful, for example, if you have a button that clears the fields in a login page.

Finishing the autofill context

The Autofill Framework saves user input for future use by showing a "Save for autofill?" dialog after the autofill context is finished. Typically, the autofill context is finished when an activity finishes. However, there are some situations where you need to explicitly notify the framework; for example, if you're using the same activity but different fragments for both your login and content screens. In these special situations, you can explicitly finish the context by calling AutofillManager.commit().

Note: It is important you do not call commit() when a user has not completed a multi-step form. For example, if you have a username `Fragment` followed by a password `Fragment`, wait until the password is entered to call `commit`.

Use the correct autofill type for data in picker controls

Pickers are useful in some autofill scenarios by providing a UI that lets users change the value of a field that stores date or time data. For example, in a credit card form, a date picker lets users enter or change the expiration date of their credit card. However, you must use another view, such as an EditText, to display the data when the picker isn't visible.

An EditText object natively expects autofill data of type AUTOFILL_TYPE_TEXT. If you are using a different type of data, you should create a custom view that inherits from EditText and implements the methods required to handle the corresponding type of data. For instance, if you have a date field, implement the methods with logic that correctly handles values of type AUTOFILL_TYPE_DATE.

When you specify the autofill data type, the autofill service is able to create an appropriate representation of the data displayed in the view. For more information, see Using pickers with autofill.

Customize the autofill highlighted drawable

When a view is autofilled, the platform renders a Drawable over the view to indicate the view contents have been autofilled. By default, this drawable is a solid rectangle with a translucent color that is slightly darker than the theme's color used to draw backgrounds. The drawable doesn't need to be changed, but it can be customized by overriding the android:autofilledHighlight item of the theme used by the application or activity, as shown in this example:

res/values/styles.xml

<resources>
    <style name="MyAutofilledHighlight" parent="...">
        <item name="android:autofilledHighlight">@drawable/my_drawable</item>
    </style>
</resources>

res/drawable/my_drawable.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <solid android:color="#4DFF0000" />
</shape>

AndroidManifest.xml

<application ...
    android:theme="@style/MyAutofilledHighlight">
<!-- or -->
<activity ...
    android:theme="@style/MyAutofilledHighlight">

Support for custom views

Custom views can specify the metadata that is exposed to the Autofill Framework by using the autofill API. Some views act as a container of virtual children, such as views that contain OpenGL rendered UI. These views must use the API to specify the structure of the information used in the app before they can work with the Autofill Framework.

If your app uses custom views, you must consider the following scenarios:

  • The custom view provides a view structure by default, which is referred to as a standard view structure in this document.
  • The custom view has a view structure that isn't available to the Autofill Framework. This type of view structure is referred to as virtual structure.

Custom views with standard view structure

Custom views can define the metadata that autofill requires to work. You should make sure that your custom view manages the metadata appropriately to work with the Autofill Framework. Your custom view should take the following actions:

  • Handle the autofill value that the framework sends to your app.
  • Provide the autofill type and value to the framework.

When autofill is triggered, the Autofill Framework calls autofill() on your view and sends the value that your view should use. You should implement autofill() to specify how your custom view handles the autofill value.

Your view should specify an autofill type and value by overriding the getAutofillType() and getAutofillValue() methods, respectively. By adding this code, you ensure that your view can provide appropriate autofill types and values to the framework.

Finally, autofill shouldn't fill the view if the user can't provide a value for the view in its current state (for example, if the view is disabled). In these cases, getAutofillType() and getAutofillValue() should return null, and autofill() should do nothing. The following cases require additional steps to properly work within the framework:

  • The custom view is editable.
  • The custom view contains sensitive data.

The custom view is editable

If the view is editable, you should notify the Autofill Framework about changes by calling notifyValueChanged() on the AutofillManager object.

The custom view contains sensitive data

If the view contains personally identifiable information (PII)—such as email addresses, credit card numbers, and passwords—it should be marked as such. In general, views whose content come from static resources don't contain sensitive data, but views whose content is dynamically set can contain sensitive data. For example, a label that contains type your user name doesn't contain sensitive data, while a label that contains Hello, John does. To mark whether the view contains sensitive data or not, implement onProvideAutofillStructure() and call setDataIsSensitive() on the ViewStructure object.

The following code example shows how to mark the data in the view structure as sensitive or not:

@Override
public void onProvideAutofillStructure(ViewStructure structure, int flags) {
    super.onProvideAutofillStructure(structure, flags);

    // Content that comes from static resources is generally not sensitive
    boolean sensitive = !contentIsSetFromResources();
    structure.setDataIsSensitive(sensitive);
}

If the view accepts only predefined values, you can use the setAutofillOptions() method to set the options that can be used to autofill this view. In particular, views whose autofill type is AUTOFILL_TYPE_LIST should use this method because the autofill service can do a better job if it knows the options that are available to fill the view.

Views that use an adapter, such as a Spinner, are a similar case. For example, a spinner that provides dynamically-created years (based on the current year) to use in credit card expiration fields can implement the getAutofillOptions() method of the Adapter interface to provide a list of years.

Views that use an ArrayAdapter also can provide lists of values. Although ArrayAdapter automatically sets the autofill options for static resources, you should override getAutofillOptions() if you provide the values dynamically.

Custom views with virtual structure

The Autofill Framework requires a view structure before it can edit and save the information in your app's UI. There are some situations where the view structure isn't available to the framework:

  • The app uses a low-level rendering engine, such as OpenGL, to render the UI.
  • The app uses an instance of Canvas to draw the UI.

In these cases, you can specify a view structure by implementing onProvideAutofillVirtualStructure() and following these steps:

  1. Increase the child count of the view structure by calling addChildCount().
  2. Add a child by calling newChild().
  3. Set the autofill ID for the child by calling setAutofillId().
  4. Set relevant properties, such as the autofill value and type.
  5. If the data in the virtual child is sensitive, you should pass true to setDataIsSensitive() or false otherwise.

The following code example shows how to create a new child in the virtual structure:

@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure,
                                              int flags) {
    super.onProvideAutofillVirtualStructure(structure, flags);

    // Create a new child in the virtual structure.
    structure.addChildCount(1);
    ViewStructure child =
        structure.newChild(childIndex);

    // Set the autofill ID for the child
    child.setAutofillId(structure.getAutofillId(), childVirtualId);

    // Populate the child by providing properties such as value and type.
    child.setAutofillValue(childAutofillValue);
    child.setAutoFillType(childAutofillType);

    // Some children can provide a list of values. For example, if the child is
    // a spinner.
    CharSequence childAutofillOptions[] = { "option1", "option2" };
    child.setAutofillOptions(childAutofillOptions);

    // Just like other types of views, mark the data as sensitive, if
    // appropriate.
    boolean sensitive = !contentIsSetFromResources();
    child.setDataIsSensitive(sensitive);
}

When elements in a virtual structure change, you should notify the framework by performing the following tasks:

Using callbacks on autofill events

Apps can provide their own autocomplete views. If your app does so, it needs a mechanism that tells the app to enable or disable the views in response to changes in the UI autofill affordance. The Autofill Framework provides this mechanism in the form of AutofillCallback.

This class provides the onAutofillEvent(View, int) method, which the app calls after a change in the autofill state associated with a view. There is also an overloaded version of this method, which includes a childId parameter that your app can use with virtual views. The available states are defined as constants in the callback.

You can register a callback using the registerCallback(AutofillCallback) method of the AutofillManager class. The following code example shows how to declare a callback for autofill events:

AutofillManager afm = this.getSystemService(AutofillManager.class);

afm.registerCallback(new AutofillManager.AutofillCallback() {
    // For virtual structures, override
    // onAutofillEvent(View view, int childId, int event) instead
    @Override
    public void onAutofillEvent(View view, int event) {
        super.onAutofillEvent(view, event);
        switch (event) {
            case EVENT_INPUT_HIDDEN:
                // The autofill affordance associated with the view was hidden
                break;
            case EVENT_INPUT_SHOWN:
                // The autofill affordance associated with the view was shown
                break;
            case EVENT_INPUT_UNAVAILABLE:
                // Autofill isn't available.
                break;
        }
    }
});

Use the unregisterCallback(AutofillCallback) method when it's time to remove the callback.

Authenticating for autofill

An autofill service can require the user to authenticate before the autofill data can be used to complete fields in your app. You don't need to update your app because this authentication happens on the service.

Addressing known issues

This section presents workarounds to known issues within the Autofill framework. To avoid unnecessary operations, you should first check whether autofill is enabled in the device. The following code example shows how to check if autofill is supported in the device and enabled for the current user:

public class AutofillHelper {
    public static boolean isDialogResizedWorkaroundRequired(Context context) {
        // After the issue is resolved on Android, you should check if the
        // workaround is still required for the current device.
        return isAutofillAvailable(context);
    }

    public static boolean isAutofillAvailable(Context context) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
            // Autofill Framework is only available on Android 8.0 or higher.
            return false;
        }

        AutofillManager afm = context.getSystemService(AutofillManager.class);
        // Return true if autofill is supported by the device and enabled
        // for the current user.
        return afm != null && afm.isEnabled();
    }
}

Resized dialogs aren't considered for autofill

On Android 8.1 and lower, if a view in a dialog is resized after it's already displayed, the view isn't considered for autofill. Such views aren't included in the AssistStructure object that the Android system sends to the autofill service. As a result, the service can't fill out the views.

To work around this issue, you must replace the token property of the dialog window parameters with the token property of the activity that creates the dialog. After you validate that autofill is enabled, save the window parameters in the onWindowAttributesChanged() method of the class that inherits from Dialog. Then, replace the token property of the saved parameters with the token property of the parent activity in the onAttachedToWindow() method. The following code example shows a class that implements the workaround:

public class MyDialog extends Dialog {
    // Used to store the dialog window parameters.
    private IBinder mToken;

    @Override
    public void onWindowAttributesChanged(WindowManager.LayoutParams params) {
        if (params.token == null && mToken != null) {
            params.token = mToken;
        }

        super.onWindowAttributesChanged(params);
    }

    @Override
    public void onAttachedToWindow() {
        if (isDialogResizedWorkaroundRequired()) {
            mToken = getOwnerActivity().getWindow().getAttributes().token;
        }

        super.onAttachedToWindow();
    }

    private boolean isDialogResizedWorkaroundRequired() {
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O
                || Build.VERSION.SDK_INT != Build.VERSION_CODES.O_MR1) {
            return false;
        }
        AutofillManager autofillManager =
            getContext().getSystemService(AutofillManager.class);
        return autofillManager != null && autofillManager.isEnabled();
    }

}