How ToTools

How to Create Auto-Fill Custom Service in Android Apps

When we buy a new phone, there are numerous apps that require a lot of login information. Auto form fill, often shortened to just autofill, is a feature of automatically filling in usernames and passwords. Many of us have used it all the time. This feature comes in handy during tasks such as filling out a registration form or completing a checkout process.

The latest version released by Android, Android O, also brings a similar feature to Android apps. Android will now help users fill out forms which belong to all the apps they have installed on their devices. This was a much-awaited feature because typing with a virtual keyboard on a small screen tends to be quite a chore. Android developers can now use this new AutoFill Framework to create their own auto-fill service in their Android applications. The service will decide how to populate an app’s input fields. In this tutorial, we’ll tell you how to create an autofill service in an app.

1.Creating a New Project in Android Studio

Create a new project with an empty activity. Choose Android 7+ in the target Android service dialog. Now add the following compile dependency to the build. gradle file of it. Press sync button to update the project.

2. Analyzing View Hierarchies

Any class which extends the abstract AutoFillService class can serve as an autofill service. So start by creating a new Java class with File > New > Java Class. In the dialog that pops up, name the class EmailAddressFiller and make sure that you set the value of the Superclass field to AutoFillService.
It will now prompt you to generate stubs for two abstract methods: onSaveRequest() and onFillRequest(). In this tutorial, we’ll be considering only the onFillRequest() method. This method is called by default whenever the user opens an activity containing input fields.

@Override public void onFillRequest(AssistStructure assistStructure,                            Bundle bundle,                           CancellationSignal cancellationSignal,                           FillCallback fillCallback) {     // More code goes here }

The autofill service requires to analyze an app’s user interface and identify input fields it can fill. That’s why the onFillRequest() method contains a tree of ViewNode objects. Let’s create a recursive method to analyze all nodes of tree:

void identifyEmailFields(AssistStructure.ViewNode node,                       
List<AssistStructure.ViewNode> emailFields) {     
// More code goes here }

As you can see, this method has a ViewNode and a List as its parameters. We’ll be using the List to store all the input fields that expect email addresses.  Now, we will simply pick all input fields whose resource IDs contain strings such as “email” and “username”. Add the following code to the method:

if(node.getClassName().contains("EditText")) {     
String viewId = node.getIdEntry();     
if(viewId!=null && (viewId.contains("email")                          
|| viewId.contains("username"))) {         
emailFields.add(node);         
return;     } 
}

Now, we must recursively call the identifyEmailFields() method to analyze all its children. The following code shows you how:
We will now call identifyEmailFields() method inside the onFillRequest() method. We’ll pass the root node of the view hierarchy to it.
If our autofill service is unable to identify any input fields for emails, it should do nothing. Therefore, add the following code to it:

for(int i=0; i<node.getChildCount();i++) {
    identifyEmailFields(node.getChildAt(i), emailFields);
}
// Create an empty list
List<AssistStructure.ViewNode> emailFields = new ArrayList<>();
// Populate the list
identifyEmailFields(assistStructure
                    .getWindowNodeAt(0)
                    .getRootViewNode(), emailFields);
if(emailFields.size() == 0)
    return;

3. RemoteViews creation

If our autofill service does find an input field it can fill, it must display a drop-down list. To display the drop-down list, we should use RemoteViews objects. It is a collection of views that can be displayed in another app. For initialization, we’ll need a layout XML file. Let’s create one now called email_suggestion.xml. For now, it’ll contain only one TextView widget to display an email address. Now, add the following code to this xml file:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/email_suggestion_item"
    android:textSize="18sp"
    android:textStyle="bold"
    android:padding="5dp">
</TextView>

We will now go back to the onFillRequest() method and create two RemoteViews objects:

RemoteViews rvPrimaryEmail = 
            new RemoteViews(getPackageName(), 
                            R.layout.email_suggestion);
RemoteViews rvSecondaryEmail = 
            new RemoteViews(getPackageName(),
                            R.layout.email_suggestion);

To open the file, we will use the getSharedPreferences() method. Once it’s opened, we can use its getString() method to fetch both the email addresses. Finally, to set the contents of the remote TextView widgets, we must use the setTextViewText() method.

// Load the email addresses from preferences
SharedPreferences sharedPreferences = 
                getSharedPreferences("EMAIL_STORAGE", MODE_PRIVATE);
String primaryEmail = 
                sharedPreferences.getString("PRIMARY_EMAIL", "");
String secondaryEmail = 
                sharedPreferences.getString("SECONDARY_EMAIL", "");
// Update remote TextViews
rvPrimaryEmail.setTextViewText(R.id.email_suggestion_item, 
                               primaryEmail);
rvSecondaryEmail.setTextViewText(R.id.email_suggestion_item,
                                 secondaryEmail);

4. Creating Datasets

We can now use the remote views to create autofill data sets. These datasets can be sent to any app. We’ll be creating data sets only for the 1st email input field we encounter. The following code tells how to pick only the first email input field:

AssistStructure.ViewNode emailField = emailFields.get(0);

In order to specify the text that should be written into the input field, we must use the AutoFillValue.forText() method. Copy the following code:

Dataset primaryEmailDataSet = 
            new Dataset.Builder(rvPrimaryEmail)
                        .setValue(
                           emailField.getAutoFillId(),
                            AutoFillValue.forText(primaryEmail)
                        ).build();
Dataset secondaryEmailDataSet = 
            new Dataset.Builder(rvSecondaryEmail)
                        .setValue(
                            emailField.getAutoFillId(),
                            AutoFillValue.forText(secondaryEmail)
                        ).build();

Before we send data sets to an app, we must add them to a FillResponse object. Call its addDataset() method twice to add both the data sets. Once the full response object is ready, pass it as an argument to the onSuccess() method of the FillCallback object, that is one of the parameters of the onFillRequest() method.

FillResponse response = new FillResponse.Builder()
                            .addDataset(primaryEmailDataSet)
                            .addDataset(secondaryEmailDataSet)
                            .build();
fillCallback.onSuccess(response);

The autofill service should be coded in the project’s AndroidManifest.xml file. This service also needs a tag that allows it to respond to the android.service.autofill.AutoFillService action, and a tag that points to the meta-data XML file we created in an earlier step. Accordingly, add the following lines to the manifest file:

<service android:name=".EmailAddressFiller"
    android:permission="android.permission.BIND_AUTO_FILL">
    <meta-data android:name="android.autofill"
        android:resource="@xml/email_address_filler"/>
    <intent-filter>
        <action android:name="android.service.autofill.AutoFillService"/>
    </intent-filter>
</service>

Our auto-fill service and app are now ready. Build the project and install the app on your device.

5. Activating Auto-fill

For activation of the autofill service, open the Settings menu and navigate to: Apps & Notifications > Advanced > Default apps > Autofill app. In the next screen, select the app from the list of available autofill apps. Now open any app which asks for an email address to see the autofill service in action.

Aamir Jamal

An Android Geek and audiophile who love to read and write reviews/tutorials about gadgets and new tech stuff. He has written 1007 guides and other posts.

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Close
Close