diff --git a/docs/downloads/training/NotifyUser.zip b/docs/downloads/training/NotifyUser.zip new file mode 100644 index 0000000000000..c335157db6e55 Binary files /dev/null and b/docs/downloads/training/NotifyUser.zip differ diff --git a/docs/html/images/training/notifications-bigview.png b/docs/html/images/training/notifications-bigview.png new file mode 100644 index 0000000000000..83a5610c93c20 Binary files /dev/null and b/docs/html/images/training/notifications-bigview.png differ diff --git a/docs/html/images/training/notifications-normalview.png b/docs/html/images/training/notifications-normalview.png new file mode 100644 index 0000000000000..06ea970496d72 Binary files /dev/null and b/docs/html/images/training/notifications-normalview.png differ diff --git a/docs/html/training/notify-user/build-notification.jd b/docs/html/training/notify-user/build-notification.jd new file mode 100644 index 0000000000000..ba6602884848d --- /dev/null +++ b/docs/html/training/notify-user/build-notification.jd @@ -0,0 +1,160 @@ +page.title=Building a Notification +parent.title=Notifying the User +parent.link=index.html + +trainingnavtop=true +next.title=Preserving Navigation when Starting an Activity +next.link=navigation.html + +@jd:body + +
This lesson explains how to create and issue a notification.
+ +The examples in this class are based on the +{@link android.support.v4.app.NotificationCompat.Builder} class. +{@link android.support.v4.app.NotificationCompat.Builder} +is in the Support Library. You should use +{@link android.support.v4.app.NotificationCompat} and its subclasses, +particularly {@link android.support.v4.app.NotificationCompat.Builder}, to +provide the best notification support for a wide range of platforms.
+ +When creating a notification, specify the UI content and actions with a +{@link android.support.v4.app.NotificationCompat.Builder} object. At bare minimum, +a {@link android.support.v4.app.NotificationCompat.Builder Builder} +object must include the following:
+ +For example:
+
+NotificationCompat.Builder mBuilder =
+ new NotificationCompat.Builder(this)
+ .setSmallIcon(R.drawable.notification_icon)
+ .setContentTitle("My notification")
+ .setContentText("Hello World!");
+
+
+Although actions are optional, you should add at least one action to your +notification. An action takes users directly from the notification to an +{@link android.app.Activity} in your application, where they can look at the +event that caused the notification or do further work. Inside a 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.
+ +How you construct the {@link android.app.PendingIntent} depends on what type +of {@link android.app.Activity} you're starting. When you start an {@link +android.app.Activity} from a notification, you must preserve the user's expected +navigation experience. In the snippet below, clicking the notification opens a +new activity that effectively extends the behavior of the notification. In this +case there is no need to create an artificial back stack (see +Preserving Navigation when Starting an Activity for +more information):
+ +Intent resultIntent = new Intent(this, ResultActivity.class);
+...
+// Because clicking the notification opens a new ("special") activity, there's
+// no need to create an artificial back stack.
+PendingIntent resultPendingIntent =
+ PendingIntent.getActivity(
+ this,
+ 0,
+ resultIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+);
+
+
++To associate the {@link android.app.PendingIntent} created in the previous +step with a gesture, call the appropriate method of {@link +android.support.v4.app.NotificationCompat.Builder}. For example, to start an +activity when the user clicks the notification text in the notification drawer, +add the {@link android.app.PendingIntent} by calling {@link +android.support.v4.app.NotificationCompat.Builder#setContentIntent +setContentIntent()}. For example:
+ +PendingIntent resultPendingIntent; +... +mBuilder.setContentIntent(resultPendingIntent);+ +
To issue the notification:
+For example:
+ ++// Sets an ID for the notification +int mNotificationId = 001; +// Gets an instance of the NotificationManager service +NotificationManager mNotifyMgr = + (NotificationManager) getSystemService(NOTIFICATION_SERVICE); +// Builds the notification and issues it. +mNotifyMgr.notify(mNotificationId, builder.build()); ++ diff --git a/docs/html/training/notify-user/display-progress.jd b/docs/html/training/notify-user/display-progress.jd new file mode 100644 index 0000000000000..2b2b3ae7b75d0 --- /dev/null +++ b/docs/html/training/notify-user/display-progress.jd @@ -0,0 +1,182 @@ +page.title=Displaying Progress in a Notification +parent.title=Notifying the User +parent.link=index.html + +trainingnavtop=true +previous.title=Using Expanded Notification Styles +previous.link=expanded.html + +@jd:body + +
+ 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, call + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()}. The + determinate and indeterminate forms are described in the following sections. +
+ +
+ 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.
+ The third argument is a boolean that indicates whether the
+ progress bar is indeterminate (true) or determinate (false).
+ 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();
+
++ The resulting notifications are shown in figure 1. On the left side is a snapshot of the + notification during the operation; on the right side is a snapshot of it after the operation + has finished. +
+
++Figure 1. The progress bar during and after the operation.
+ ++ To display a continuing (indeterminate) activity indicator, add it to your notification with + {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress(0, 0, true)} + and issue the notification. The first two arguments are ignored, and the third argument + declares that the indicator is indeterminate. 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 continuing 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. Notice that the third parameter + in the {@link android.support.v4.app.NotificationCompat.Builder#setProgress setProgress()} + call is set to {@code true} to indicate that the progress bar is + indeterminate: +
++ // Sets an activity indicator for an operation of indeterminate length +mBuilder.setProgress(0, 0, true); +// Issues the notification +mNotifyManager.notify(0, mBuilder.build()); ++
+ The resulting indicator is shown in figure 2: +
+
+Figure 2. An ongoing activity indicator.
diff --git a/docs/html/training/notify-user/expanded.jd b/docs/html/training/notify-user/expanded.jd new file mode 100644 index 0000000000000..a3cc6ad94865a --- /dev/null +++ b/docs/html/training/notify-user/expanded.jd @@ -0,0 +1,167 @@ +page.title=Using Big View Styles +Styles parent.title=Notifying the User +parent.link=index.html + +trainingnavtop=true +next.title=Displaying Progress in a Notification +next.link=display-progress.html + +@jd:body + +Notifications in the notification drawer appear in two main visual styles, +normal view and big view. The big view of a notification only appears when the +notification is expanded. This happens when the notification is at the top of +the drawer, or the user clicks the notification.
+ +Big views were introduced in +Android 4.1, and they're not supported on older devices. This lesson describes +how to incorporate big view notifications into your app while still providing +full functionality via the normal view. See the +Notifications API guide for more discussion of big views.
+ +Here is an example of a normal view:
+ +
+
++ Figure 1. Normal view notification. +
+ + +Here is an example of a big view:
+ +
++ Figure 2. Big view notification. +
+ + +In the sample application shown in this lesson, both the normal view and the +big view give users access to same functionality:
+ +The normal view provides these features through a new activity that launches +when the user clicks the notification. Keep this in mind as you design your notifications—first +provide the functionality in the normal view, since +this is how many users will interact with the notification.
+ +The sample application uses an {@link android.app.IntentService} subclass ({@code PingService}) +to construct and issue the notification.
+ + +In this snippet, the +{@link android.app.IntentService} method +{@link android.app.IntentService#onHandleIntent onHandleIntent()} specifies the new activity +that will be launched if the user +clicks the notification itself. The method +{@link android.support.v4.app.NotificationCompat.Builder#setContentIntent setContentIntent()} +defines a pending intent that should be fired when the user +clicks the notification, thereby launching the activity.
+ +Intent resultIntent = new Intent(this, ResultActivity.class);
+resultIntent.putExtra(CommonConstants.EXTRA_MESSAGE, msg);
+resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+ Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
+// Because clicking the notification launches a new ("special") activity,
+// there's no need to create an artificial back stack.
+PendingIntent resultPendingIntent =
+ PendingIntent.getActivity(
+ this,
+ 0,
+ resultIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT
+);
+
+// This sets the pending intent that should be fired when the user clicks the
+// notification. Clicking the notification launches a new activity.
+builder.setContentIntent(resultPendingIntent);
+
+
+This snippet shows how to set up the buttons that will appear in the big view:
+ ++// Sets up the Snooze and Dismiss action buttons that will appear in the +// big view of the notification. +Intent dismissIntent = new Intent(this, PingService.class); +dismissIntent.setAction(CommonConstants.ACTION_DISMISS); +PendingIntent piDismiss = PendingIntent.getService(this, 0, dismissIntent, 0); + +Intent snoozeIntent = new Intent(this, PingService.class); +snoozeIntent.setAction(CommonConstants.ACTION_SNOOZE); +PendingIntent piSnooze = PendingIntent.getService(this, 0, snoozeIntent, 0); ++ +
This snippet shows how to construct the +{@link android.support.v4.app.NotificationCompat.Builder Builder} object. +It sets the style for the big +view to be "big text," and sets its content to be the reminder message. It uses +{@link android.support.v4.app.NotificationCompat.Builder#addAction addAction()} +to add the Snooze and Dismiss buttons (and +their associated pending intents) that will appear in the notification's +big view:
+ +// Constructs the Builder object. +NotificationCompat.Builder builder = + new NotificationCompat.Builder(this) + .setSmallIcon(R.drawable.ic_stat_notification) + .setContentTitle(getString(R.string.notification)) + .setContentText(getString(R.string.ping)) + .setDefaults(Notification.DEFAULT_ALL) // requires VIBRATE permission + /* + * Sets the big view "big text" style and supplies the + * text (the user's reminder message) that will be displayed + * in the detail area of the expanded notification. + * These calls are ignored by the support library for + * pre-4.1 devices. + */ + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(msg)) + .addAction (R.drawable.ic_stat_dismiss, + getString(R.string.dismiss), piDismiss) + .addAction (R.drawable.ic_stat_snooze, + getString(R.string.snooze), piSnooze); ++ + + diff --git a/docs/html/training/notify-user/index.jd b/docs/html/training/notify-user/index.jd new file mode 100644 index 0000000000000..510f2c427a8ad --- /dev/null +++ b/docs/html/training/notify-user/index.jd @@ -0,0 +1,102 @@ +page.title=Notifying the User +trainingnavtop=true +startpage=true +next.title=Build a Notification +next.link=build-notification.html + + +@jd:body +
NotifyUser.zip
++ A notification is a user interface element that you display outside your app's normal UI to indicate + that an event has occurred. Users can choose to view the notification while using other apps and respond + to it when it's convenient for them. + +
+ ++ The Notifications design guide shows + you how to design effective notifications and when to use them. This class shows you how to + implement the most common notification designs. +
++ 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. +
+ ++ 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, Notification) + NotificationManager.notify(ID, notification)}. 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. +
++ 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: +
++ Part of designing a notification is preserving the user's expected navigation experience. + For a detailed discussion of this topic, see the + Notifications + API guide. + There are two general situations: +
++ To set up a {@link android.app.PendingIntent} that starts a direct entry + {@link android.app.Activity}, follow these steps: +
++<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> ++
+... +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()); ++ +
+ 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(new ComponentName(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 notifyIntent = + PendingIntent.getActivity( + this, + 0, + notifyIntent, + PendingIntent.FLAG_UPDATE_CURRENT +); + +// Puts the PendingIntent into the notification builder +builder.setContentIntent(notifyIntent); +// 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()); ++