page.title=Notifications @jd:body
A notification is a message you can display to the user outside of your application's normal UI. When you tell the system to issue a notification, it first appears as an icon in the notification area. To see the details of the notification, the user opens the notification drawer. Both the notification area and the notification drawer are system-controlled areas that the user can view at any time.
Note: Except where noted, this guide refers to the {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} class in the version 4 Support Library. The class {@link android.app.Notification.Builder Notification.Builder} was added in Android 3.0 (API level 11).
Notifications, as an important part of the Android user interface, have their own design guidelines. The material design changes introduced in Android 5.0 (API level 21) are of particular importance, and you should review the Material Design training for more information. To learn how to design notifications and their interactions, read the Notifications design guide.
You specify the UI information and actions for a notification in a {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder} object. To create the notification itself, you call {@link android.support.v4.app.NotificationCompat.Builder#build NotificationCompat.Builder.build()}, which returns a {@link android.app.Notification} object containing your specifications. To issue the notification, you pass the {@link android.app.Notification} object to the system by calling {@link android.app.NotificationManager#notify NotificationManager.notify()}.
A {@link android.app.Notification} object must contain the following:
All other notification settings and contents are optional. To learn more about them, see the reference documentation for {@link android.support.v4.app.NotificationCompat.Builder}.
Although they're optional, you should add at least one action to your notification. An action allows users to go directly from the notification to an {@link android.app.Activity} in your application, where they can look at one or more events or do further work.
A notification can provide multiple actions. You should always define the action that's triggered when the user clicks the notification; usually this action opens an {@link android.app.Activity} in your application. You can also add buttons to the notification that perform additional actions such as snoozing an alarm or responding immediately to a text message; this feature is available as of Android 4.1. If you use additional action buttons, you must also make their functionality available in an {@link android.app.Activity} in your app; see the section Handling compatibility for more details.
Inside a {@link android.app.Notification}, the action itself is defined by a {@link android.app.PendingIntent} containing an {@link android.content.Intent} that starts an {@link android.app.Activity} in your application. To associate the {@link android.app.PendingIntent} with a gesture, call the appropriate method of {@link android.support.v4.app.NotificationCompat.Builder}. For example, if you want to start {@link android.app.Activity} when the user clicks the notification text in the notification drawer, you add the {@link android.app.PendingIntent} by calling {@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()}.
Starting an {@link android.app.Activity} when the user clicks the notification is the most common action scenario. You can also start an {@link android.app.Activity} when the user dismisses a notification. In Android 4.1 and later, you can start an {@link android.app.Activity} from an action button. To learn more, read the reference guide for {@link android.support.v4.app.NotificationCompat.Builder}.
If you wish, you can set the priority of a notification. The priority acts as a hint to the device UI about how the notification should be displayed. To set a notification's priority, call {@link android.support.v4.app.NotificationCompat.Builder#setPriority(int) NotificationCompat.Builder.setPriority()} and pass in one of the {@link android.support.v4.app.NotificationCompat} priority constants. There are five priority levels, ranging from {@link android.support.v4.app.NotificationCompat#PRIORITY_MIN} (-2) to {@link android.support.v4.app.NotificationCompat#PRIORITY_MAX} (2); if not set, the priority defaults to {@link android.support.v4.app.NotificationCompat#PRIORITY_DEFAULT} (0).
For information about setting an appropriate priority level, see "Correctly set and manage notification priority" in the Notifications Design guide.
The following snippet illustrates a simple notification that specifies an activity to open when the user clicks the notification. Notice that the code creates a {@link android.support.v4.app.TaskStackBuilder} object and uses it to create the {@link android.app.PendingIntent} for the action. This pattern is explained in more detail in the section Preserving Navigation when Starting an Activity:
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("My notification") .setContentText("Hello World!"); // Creates an explicit intent for an Activity in your app Intent resultIntent = new Intent(this, ResultActivity.class); // The stack builder object will contain an artificial back stack for the // started Activity. // This ensures that navigating backward from the Activity leads out of // your application to the Home screen. TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); // Adds the back stack for the Intent (but not the Intent itself) stackBuilder.addParentStack(ResultActivity.class); // Adds the Intent that starts the Activity to the top of the stack stackBuilder.addNextIntent(resultIntent); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent( 0, PendingIntent.FLAG_UPDATE_CURRENT ); mBuilder.setContentIntent(resultPendingIntent); NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // mId allows you to update the notification later on. mNotificationManager.notify(mId, mBuilder.build());
That's it. Your user has now been notified.
To have a notification appear in an expanded view, first create a {@link android.support.v4.app.NotificationCompat.Builder} object with the normal view options you want. Next, call {@link android.support.v4.app.NotificationCompat.Builder#setStyle Builder.setStyle()} with an expanded layout object as its argument.
Remember that expanded notifications are not available on platforms prior to Android 4.1. To learn how to handle notifications for Android 4.1 and for earlier platforms, read the section Handling compatibility.
For example, the following code snippet demonstrates how to alter the notification created in the previous snippet to use the expanded layout:
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("Event tracker") .setContentText("Events received") NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle(); String[] events = new String[6]; // Sets a title for the Inbox in expanded layout inboxStyle.setBigContentTitle("Event tracker details:"); ... // Moves events into the expanded layout for (int i=0; i < events.length; i++) { inboxStyle.addLine(events[i]); } // Moves the expanded layout object into the notification object. mBuilder.setStyle(inBoxStyle); ... // Issue the notification here.
Not all notification features are available for a particular version, even though the methods to set them are in the support library class {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}. For example, action buttons, which depend on expanded notifications, only appear on Android 4.1 and higher, because expanded notifications themselves are only available on Android 4.1 and higher.
To ensure the best compatibility, create notifications with {@link android.support.v4.app.NotificationCompat NotificationCompat} and its subclasses, particularly {@link android.support.v4.app.NotificationCompat.Builder NotificationCompat.Builder}. In addition, follow this process when you implement a notification:
For example, if you want to use {@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} to provide a control that stops and starts media playback, first implement this control in an {@link android.app.Activity} in your app.
When you need to issue a notification multiple times for the same type of event, you should avoid making a completely new notification. Instead, you should consider updating a previous notification, either by changing some of its values or by adding to it, or both.
For example, Gmail notifies the user that new emails have arrived by increasing its count of unread messages and by adding a summary of each email to the notification. This is called "stacking" the notification; it's described in more detail in the Notifications Design guide.
Note: This Gmail feature requires the "inbox" expanded layout, which is part of the expanded notification feature available starting in Android 4.1.
The following section describes how to update notifications and also how to remove them.
To set up a notification so it can be updated, issue it with a notification ID by calling {@link android.app.NotificationManager#notify(int, android.app.Notification) NotificationManager.notify()}. To update this notification once you've issued it, update or create a {@link android.support.v4.app.NotificationCompat.Builder} object, build a {@link android.app.Notification} object from it, and issue the {@link android.app.Notification} with the same ID you used previously. If the previous notification is still visible, the system updates it from the contents of the {@link android.app.Notification} object. If the previous notification has been dismissed, a new notification is created instead.
The following snippet demonstrates a notification that is updated to reflect the number of events that have occurred. It stacks the notification, showing a summary:
mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // Sets an ID for the notification, so it can be updated int notifyID = 1; mNotifyBuilder = new NotificationCompat.Builder(this) .setContentTitle("New Message") .setContentText("You've received new messages.") .setSmallIcon(R.drawable.ic_notify_status) numMessages = 0; // Start of a loop that processes data and then notifies the user ... mNotifyBuilder.setContentText(currentText) .setNumber(++numMessages); // Because the ID remains unchanged, the existing notification is // updated. mNotificationManager.notify( notifyID, mNotifyBuilder.build()); ...
Notifications remain visible until one of the following happens:
When you start an {@link android.app.Activity} from a notification, you must preserve the user's expected navigation experience. Clicking Back should take the user back through the application's normal work flow to the Home screen, and clicking Recents should show the {@link android.app.Activity} as a separate task. To preserve the navigation experience, you should start the {@link android.app.Activity} in a fresh task. How you set up the {@link android.app.PendingIntent} to give you a fresh task depends on the nature of the {@link android.app.Activity} you're starting. There are two general situations:
Notifications from the Gmail app demonstrate this. When you click a notification for a single email message, you see the message itself. Touching Back takes you backwards through Gmail to the Home screen, just as if you had entered Gmail from the Home screen rather than entering it from a notification.
This happens regardless of the application you were in when you touched the notification. For example, if you're in Gmail composing a message, and you click a notification for a single email, you go immediately to that email. Touching Back takes you to the inbox and then the Home screen, rather than taking you to the message you were composing.
To set up a {@link android.app.PendingIntent} that starts a direct entry {@link android.app.Activity}, follow these steps:
<meta-data>
element as the child of the
<activity>
.
For this element, set
android:name="android.support.PARENT_ACTIVITY"
.
Set
android:value="<parent_activity_name>"
where <parent_activity_name>
is the value of
android:name
for the parent
<activity>
element. See the following XML for an example.
android:parentActivityName
attribute to the
<activity>
element of the {@link android.app.Activity} you're starting.
The final XML should look like this:
<activity android:name=".MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".ResultActivity" android:parentActivityName=".MainActivity"> <meta-data android:name="android.support.PARENT_ACTIVITY" android:value=".MainActivity"/> </activity>
Note: Although the argument to {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} is a reference to the started {@link android.app.Activity}, the method call doesn't add the {@link android.content.Intent} that starts the {@link android.app.Activity}. Instead, that's taken care of in the next step.
The following code snippet demonstrates the process:
... Intent resultIntent = new Intent(this, ResultActivity.class); TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); // Adds the back stack stackBuilder.addParentStack(ResultActivity.class); // Adds the Intent to the top of the stack stackBuilder.addNextIntent(resultIntent); // Gets a PendingIntent containing the entire back stack PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT); ... NotificationCompat.Builder builder = new NotificationCompat.Builder(this); builder.setContentIntent(resultPendingIntent); NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager.notify(id, builder.build());
The following section describes how to set up a special activity {@link android.app.PendingIntent}.
A special {@link android.app.Activity} doesn't need a back stack, so you don't have to define its {@link android.app.Activity} hierarchy in the manifest, and you don't have to call {@link android.support.v4.app.TaskStackBuilder#addParentStack addParentStack()} to build a back stack. Instead, use the manifest to set up the {@link android.app.Activity} task options, and create the {@link android.app.PendingIntent} by calling {@link android.app.PendingIntent#getActivity getActivity()}:
<activity>
element for the {@link android.app.Activity}
android:name="activityclass"
android:taskAffinity=""
android:excludeFromRecents="true"
This snippet shows the element:
<activity android:name=".ResultActivity" ... android:launchMode="singleTask" android:taskAffinity="" android:excludeFromRecents="true"> </activity> ...
The following code snippet demonstrates the process:
// Instantiate a Builder object. NotificationCompat.Builder builder = new NotificationCompat.Builder(this); // Creates an Intent for the Activity Intent notifyIntent = new Intent(this, ResultActivity.class); // Sets the Activity to start in a new, empty task notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); // Creates the PendingIntent PendingIntent notifyPendingIntent = PendingIntent.getActivity( this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT ); // Puts the PendingIntent into the notification builder builder.setContentIntent(notifyPendingIntent); // Notifications are issued by sending them to the // NotificationManager system service. NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // Builds an anonymous Notification object from the builder, and // passes it to the NotificationManager mNotificationManager.notify(id, builder.build());
Notifications can include an animated progress indicator that shows users the status of an ongoing operation. If you can estimate how long the operation takes and how much of it is complete at any time, use the "determinate" form of the indicator (a progress bar). If you can't estimate the length of the operation, use the "indeterminate" form of the indicator (an activity indicator).
Progress indicators are displayed with the platform's implementation of the {@link android.widget.ProgressBar} class.
To use a progress indicator on platforms starting with Android 4.0, call {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. For previous versions, you must create your own custom notification layout that includes a {@link android.widget.ProgressBar} view.
The following sections describe how to display progress in a notification using {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}.
To display a determinate progress bar, add the bar to your notification by calling
{@link android.support.v4.app.NotificationCompat.Builder#setProgress
setProgress(max, progress, false)} and then issue the notification. As your operation proceeds,
increment progress
, and update the notification. At the end of the operation,
progress
should equal max
. A common way to call
{@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}
is to set max
to 100 and then increment progress
as a
"percent complete" value for the operation.
You can either leave the progress bar showing when the operation is done, or remove it. In either case, remember to update the notification text to show that the operation is complete. To remove the progress bar, call {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)}. For example:
... mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new NotificationCompat.Builder(this); mBuilder.setContentTitle("Picture Download") .setContentText("Download in progress") .setSmallIcon(R.drawable.ic_notification); // Start a lengthy operation in a background thread new Thread( new Runnable() { @Override public void run() { int incr; // Do the "lengthy" operation 20 times for (incr = 0; incr <= 100; incr+=5) { // Sets the progress indicator to a max value, the // current completion percentage, and "determinate" // state mBuilder.setProgress(100, incr, false); // Displays the progress bar for the first time. mNotifyManager.notify(0, mBuilder.build()); // Sleeps the thread, simulating an operation // that takes time try { // Sleep for 5 seconds Thread.sleep(5*1000); } catch (InterruptedException e) { Log.d(TAG, "sleep failure"); } } // When the loop is finished, updates the notification mBuilder.setContentText("Download complete") // Removes the progress bar .setProgress(0,0,false); mNotifyManager.notify(ID, mBuilder.build()); } } // Starts the thread by calling the run() method in its Runnable ).start();
To display an indeterminate activity indicator, add it to your notification with {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)} (the first two arguments are ignored), and issue the notification. The result is an indicator that has the same style as a progress bar, except that its animation is ongoing.
Issue the notification at the beginning of the operation. The animation will run until you modify your notification. When the operation is done, call {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, false)} and then update the notification to remove the activity indicator. Always do this; otherwise, the animation will run even when the operation is complete. Also remember to change the notification text to indicate that the operation is complete.
To see how activity indicators work, refer to the preceding snippet. Locate the following lines:
// Sets the progress indicator to a max value, the current completion // percentage, and "determinate" state mBuilder.setProgress(100, incr, false); // Issues the notification mNotifyManager.notify(0, mBuilder.build());
Replace the lines you've found with the following lines:
// Sets an activity indicator for an operation of indeterminate length mBuilder.setProgress(0, 0, true); // Issues the notification mNotifyManager.notify(0, mBuilder.build());
Notifications may be sorted according to metadata that you assign with the following {@link android.support.v4.app.NotificationCompat.Builder} methods:
With Android 5.0 (API level 21), notifications can appear in a small floating window (also called a heads-up notification) when the device is active (that is, the device is unlocked and its screen is on). These notifications appear similar to the compact form of your notification, except that the heads-up notification also shows action buttons. Users can act on, or dismiss, a heads-up notification without leaving the current app.
Examples of conditions that may trigger heads-up notifications include:
With the release of Android 5.0 (API level 21), notifications may now appear on the lock screen. Your app can use this functionality to provide media playback controls and other common actions. Users can choose via Settings whether to display notifications on the lock screen, and you can designate whether a notification from your app is visible on the lock screen.
Your app can control the level of detail visible in notifications displayed on a secure lock screen. You call {@link android.support.v4.app.NotificationCompat.Builder#setVisibility(int) setVisibility()} and specify one of the following values:
When {@link android.support.v4.app.NotificationCompat#VISIBILITY_PRIVATE} is set, you can also provide an alternate version of the notification content which hides certain details. For example, an SMS app might display a notification that shows You have 3 new text messages, but hides the message contents and senders. To provide this alternative notification, first create the replacement notification using {@link android.support.v4.app.NotificationCompat.Builder}. When you create the private notification object, attach the replacement notification to it through the {@link android.support.v4.app.NotificationCompat.Builder#setPublicVersion(android.app.Notification) setPublicVersion()} method.
In Android 5.0 (API level 21) the lock screen no longer displays media controls based on the {@link android.media.RemoteControlClient}, which is now deprecated. Instead, use the {@link android.app.Notification.MediaStyle} template with the {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()} method, which converts actions into clickable icons.
Note: The template and the {@link android.app.Notification.Builder#addAction(android.app.Notification.Action) addAction()} method are not included in the support library, so these features run in Android 5.0 and higher only.
To display media playback controls on the lock screen in Android 5.0, set the visibility to {@link android.support.v4.app.NotificationCompat#VISIBILITY_PUBLIC}, as described above. Then add the actions and set the {@link android.app.Notification.MediaStyle} template, as described in the following sample code:
Notification notification = new Notification.Builder(context) // Show controls on lock screen even when user hides sensitive content. .setVisibility(Notification.VISIBILITY_PUBLIC) .setSmallIcon(R.drawable.ic_stat_player) // Add media control buttons that invoke intents in your media service .addAction(R.drawable.ic_prev, "Previous", prevPendingIntent) // #0 .addAction(R.drawable.ic_pause, "Pause", pausePendingIntent) // #1 .addAction(R.drawable.ic_next, "Next", nextPendingIntent) // #2 // Apply the media style template .setStyle(new Notification.MediaStyle() .setShowActionsInCompactView(1 /* #1: pause button */) .setMediaSession(mMediaSession.getSessionToken()) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build();
Note: The deprecation of {@link android.media.RemoteControlClient} has further implications for controlling media. See Media Playback Control for more information about the new APIs for managing the media session and controlling playback.
The notifications framework allows you to define a custom notification layout, which defines the notification's appearance in a {@link android.widget.RemoteViews} object. Custom layout notifications are similar to normal notifications, but they're based on a {@link android.widget.RemoteViews} defined in a XML layout file.
The height available for a custom notification layout depends on the notification view. Normal view layouts are limited to 64 dp, and expanded view layouts are limited to 256 dp.
To define a custom notification layout, start by instantiating a {@link android.widget.RemoteViews} object that inflates an XML layout file. Then, instead of calling methods such as {@link android.support.v4.app.NotificationCompat.Builder#setContentTitle setContentTitle()}, call {@link android.support.v4.app.NotificationCompat.Builder#setContent setContent()}. To set content details in the custom notification, use the methods in {@link android.widget.RemoteViews} to set the values of the view's children:
.xml
The {@link android.widget.RemoteViews} class also includes methods that you can use to easily add a {@link android.widget.Chronometer} or {@link android.widget.ProgressBar} to your notification's layout. For more information about creating custom layouts for your notification, refer to the {@link android.widget.RemoteViews} reference documentation.
Caution: When you use a custom notification layout, take special care to ensure that your custom layout works with different device orientations and resolutions. While this advice applies to all View layouts, it's especially important for notifications because the space in the notification drawer is very restricted. Don't make your custom layout too complex, and be sure to test it in various configurations.
Always use style resources for the text of a custom notification. The background color of the notification can vary across different devices and versions, and using style resources helps you account for this. Starting in Android 2.3, the system defined a style for the standard notification layout text. If you use the same style in applications that target Android 2.3 or higher, you'll ensure that your text is visible against the display background.