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.
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:
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.