Pay from a notification

Quick payments demo integration

Some businesses require the ability to make payments quickly in order to obtain or re-gain access to a service (for example: mobile data plans, household bills, service upgrades or previously declined payments). Many times, businesses notify users about these events on their mobile devices. However, to perform an actual payment, the user must switch context and navigate through time-consuming forms, which considerably reduces the chance to complete the payment.

This pattern helps you add a payment action directly into a notification, allowing users to take action right away and make payments with as little as two taps. In this guide, you’ll learn how to create a similar experience on your Android application.

Requirements

This guide assumes an active Google Pay integration in your Android application. If you haven’t added integrated yet, you can get started with our tutorial or step-by-step guided codelab.

The building blocks

Adding the Google Pay button to your notifications is based on two fundamental building-blocks on Android:

Custom notification layouts

Regular notifications on Android have a well defined anatomy that adapts to multiple visual contexts. Using the standard template helps you ensure that your notifications are shown correctly regardless of the orientation, form factor, and OS version of the device, and hence, it is the recommended way to inform users about events that need their attention.

In circumstances where standard layouts do not meet your needs, you can provide your own layout using custom notification layouts. In this guide, you’ll make use of a custom layout to add a Google Pay button to your notification and allow your users to initiate a payment directly from there.

Activities

Activities helps expose functionality to your users in your application. Typically, activities have an associated user interface, and make up the browsable hierarchy of screens in your application.

When the user presses the Google Pay button, Google returns a list of available payment methods for users to complete the transaction. This payments sheet must be launched from a hosting activity. You can use a transparent activitiy to create the impression that the payments sheet is displayed directly on top of the notification.

Define a layout for your notification

The process to create the layout for a notification is very similar to how you define the user interface for a regular activity. Notifications, like widgets, use the RemoteViews class to manage elements in your layout. This reduces the list of supported views available compared to regular layouts.

To start, create a layout resource file in your res/layout/ folder to describe how you want your notification to look. Take a look at the notification_account_top_up.xml in the sample application for reference.

Sample custom notification layout
Figure 1. Sample custom notification layout.

Add the Google Pay button

Once your layout is ready, the last step is to add the Google Pay button to it. To do that, simply include the appropriate button resource to your layout XML file from the collection of pre-built Google Pay assets. These assets contain graphic resources for the button that adapt to multiple screen sizes and resolutions as well as languages, and follow the Google Pay branding guidelines. You can download them directly from the brand guidelines section.

<include
  android:id="@+id/googlePayButton"
  layout="@layout/buy_with_googlepay_button"
  android:layout_width="wrap_content"
  android:layout_height="48sp" />

Now, when you look at the design view of your layout, you can see the Google Pay button:

Sample custom notification with Google Pay button
Figure 2. Sample custom notification with the Google Pay button.

Trigger the notification

Depending on the interaction flow in your application or service, you can dispatch the notification in response to different events. A common pattern is to issue a push notification from your backend servers using a messaging service. If you haven’t added push functionality to your Android application yet, take a look at Firebase Cloud Messaging and this great tutorial on how to get started.

Create and set up the view

In order to initialize a notification layout and its contained views, the process works slightly differently than regular activities. Configure both the construction of the views and the response to user interaction separately. Every time the state updates, you must redraw the notification.

First, create a RemoteViews object to hold the layout hierarchy:

Kotlin

    val notificationLayout = RemoteViews(packageName, R.layout.large_notification)

Java

    RemoteViews notificationLayout = new RemoteViews(packageName, R.layout.large_notification);

You can now use the notificationLayout object to make changes to the underlying views (buttons, texts, images, etc), such as to modify their style or configure them to respond to user interaction. In this example, the Google Pay button captures tap events in order to launch the payment flow:

Kotlin

    val selectOptionIntent = Intent(context, PaymentNotificationIntentService::class.java)
      selectOptionIntent.action = ACTION_SELECT_PREFIX + option
      notificationLayout.setOnClickPendingIntent(buttonId, PendingIntent.getService(
              context, 0, selectOptionIntent, PendingIntent.FLAG_UPDATE_CURRENT))

Java

    Intent payIntent = new Intent(context, PaymentTransparentActivity.class);
    payIntent.setAction(ACTION_PAY_GOOGLE_PAY);
    payIntent.putExtra(OPTION_PRICE_EXTRA, OPTION_PRICE_CENTS.get(selectedOption));
    notificationLayout.setOnClickPendingIntent(
        R.id.googlePayButton, pendingIntentForActivity(context, payIntent));

In this instance, the Intent that displays the payment sheet contains an action which identifies the objective of the Intent and includes extra information, like the price of the item selected. Also, the Intent associates an event to the Google Pay button, so that whenever the user taps it, the Intent executes and brings the payment activity to the foreground.

Show the notification

After you create and configure the notification, the last step is to show it to the user. To do that, build a notification object with the parameters defined above and additional configuration to determine how it behaves:

Kotlin

    val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle(context.getString(R.string.notification_title))
            .setContentText(context.getString(R.string.notification_text))
            .setCustomBigContentView(notificationLayout)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setAutoCancel(false)
            .setOnlyAlertOnce(true)
            .build()

Java

    Notification notification = new NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentTitle(context.getString(R.string.notification_title))
        .setContentText(context.getString(R.string.notification_text))
        .setCustomBigContentView(notificationLayout)
        .setPriority(NotificationCompat.PRIORITY_DEFAULT)
        .setAutoCancel(false)
        .setOnlyAlertOnce(true)
        .build();

Some properties in this configuration show how this notification works, while others may differ in your applications based on your preference and use cases. Some of these fields are:

Field Value Description
Notification channel NOTIFICATION_CHANNEL_ID Starting in Android 8.0 (API level 26), you must assign all notifications to a channel. Channels group notifications in categorical topics that users can manage. You can learn more about notification channels in the Android docs.
Custom big content view notificationLayout This is where the layout you prepared earlier connects to the notification.
Auto cancel false If you make your notification interactive (like the one used in this example), you can set the auto-cancel parameter to false to ensure that the notification is not automatically dismissed when the user touches any of the views inside it.
Alert only once true This notification reacts to user input. Set this parameter to true to avoid sounds, prompts and vibration when the notification updates.

To learn about other configurations and general concepts around notifications, take a look at the custom notifications and overview sections in the Android documentation.

Finally, to trigger and display the notification, use the notify method to pass in the notification object created earlier:

Kotlin

    NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notification)

Java

    NotificationManagerCompat.from(context).notify(NOTIFICATION_ID, notification);

The NOTIFICATION_ID is an arbitrary integer that identifies the notification and is necessary to update it or remove it later on.

Make the payment

When a user taps the Google Pay button, show the payment sheet so that your users can select a payment method to complete the transaction. You can use the Google Pay APIs to display the payment sheet on top of an activity. Because the notification starts a new payment process, make this activity transparent to give users the impression that the operation completes without opening your application. Take a look at the onCreate method for this activity:

Kotlin

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    // Dismiss the notification UI if the activity was opened from a notification
    if (Notifications.ACTION_PAY_GOOGLE_PAY == intent.action) {
      sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS))
    }

    // Initialise the payments client
    startPayment()
  }

Java

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Dismiss the notification UI if the activity was opened from a notification
    if (Notifications.ACTION_PAY_GOOGLE_PAY.equals(getIntent().getAction())) {
      sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
    }

    // Initialise the payments client
    startPayment();
  }

As you can see, not much happens in this activity yet. The broadcast with the intent constant ACTION_CLOSE_SYSTEM_DIALOGS dismisses the notification menu. Remember that this activity only accesses through the Google Pay button in the notification, and without the broadcast, the notification dialog remains open.

Apart from that, the only action this activity needs is to display the payments sheet, which initiates through the showPaymentsSheet method. From there, simply call the loadPaymentData method in the Google Pay API. Take a look at the PaymentTransparentActivity.java file in the sample application to explore all the logic in the activity.