Notifications (android developers)
Notifications
https://developer.android.com/guide/topics/ui/notifiers/notifications
Set the notification content
- setSmallIcon() : 작은 아이콘 (필수)
- setContentTitle() : 제목
- setContentText() : 내용
- setPriority() : 안드로이드 7.1 이하 (안드로이드 8.0 이상은 channel importance 사용)
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setContentTitle(textTitle) .setContentText(textContent) .setPriority(NotificationCompat.PRIORITY_DEFAULT);
- 채널 ID 는 안드로이드 8.0 (API 26) 부터 필수. 그 이하는 무시된다.
- 내용은 1줄만 가능하다. 2줄 이상 쓰려면 setStyle() 이용.
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("My notification") .setContentText("Much longer text that cannot fit one line...") .setStyle(new NotificationCompat.BigTextStyle() .bigText("Much longer text that cannot fit one line...")) .setPriority(NotificationCompat.PRIORITY_DEFAULT);
Create a channel and set the importance
- 안드로이드 8.0 (오레오) 부터 notification 을 사용하려면 notification 채널을 등록해야한다.
private void createNotificationChannel() { // Create the NotificationChannel, but only on API 26+ because // the NotificationChannel class is new and not in the support library if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = getString(R.string.channel_name); String description = getString(R.string.channel_description); int importance = NotificationManager.IMPORTANCE_DEFAULT; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance); channel.setDescription(description); // Register the channel with the system; you can't change the importance // or other notification behaviors after this NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } }
notification importance levels (안드로이드 8.0 이상)
- IMPORTANCE_HIGH : Makes a sound and appears as a heads-up notification
- IMPORTANCE_DEFAULT : Makes a sound
- IMPORTANCE_LOW : No sound
- IMPORTANCE_MIN : No sound and does not appear in the status bar
https://developer.android.com/training/notify-user/channels#importance
Set the notification’s tap action
// Create an explicit intent for an Activity in your app Intent intent = new Intent(this, AlertDetails.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) // Set the intent that will fire when the user taps the notification .setContentIntent(pendingIntent) .setAutoCancel(true);
Show the notification
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); // notificationId is a unique int for each notification that you must define notificationManager.notify(notificationId, builder.build());
Add action buttons
Intent snoozeIntent = new Intent(this, MyBroadcastReceiver.class); snoozeIntent.setAction(ACTION_SNOOZE); snoozeIntent.putExtra(EXTRA_NOTIFICATION_ID, 0); PendingIntent snoozePendingIntent = PendingIntent.getBroadcast(this, 0, snoozeIntent, 0); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .addAction(R.drawable.ic_snooze, getString(R.string.snooze), snoozePendingIntent);
Add a direct reply action
// Key for the string that's delivered in the action's intent. private static final String KEY_TEXT_REPLY = "key_text_reply"; String replyLabel = getResources().getString(R.string.reply_label); RemoteInput remoteInput = new RemoteInput.Builder(KEY_TEXT_REPLY) .setLabel(replyLabel) .build();
// Build a PendingIntent for the reply action to trigger. Intent intent = new Intent(this, MyBroadcastReceiver.class); PendingIntent replyPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), conversation.getConversationId(), intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Create the reply action and add the remote input. NotificationCompat.Action action = new NotificationCompat.Action.Builder(R.drawable.ic_reply_icon, getString(R.string.label), replyPendingIntent) .addRemoteInput(remoteInput) .build();
// Build the notification and add the action. Notification newMessageNotification = new Notification.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_message) .setContentTitle(getString(R.string.title)) .setContentText(getString(R.string.content)) .addAction(action) .build(); // Issue the notification. NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(notificationId, newMessageNotification);
Retrieve user input from the reply
// in BroadcastReceiver private CharSequence getMessageText(Intent intent) { Bundle remoteInput = RemoteInput.getResultsFromIntent(intent); if (remoteInput != null) { return remoteInput.getCharSequence(KEY_TEXT_REPLY); } return null; }
// Build a new notification, which informs the user that the system // handled their interaction with the previous notification. Notification repliedNotification = new Notification.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.ic_message) .setContentText(getString(R.string.replied)) .build(); // Issue the new notification. NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(notificationId, repliedNotification);
setRemoteInputHistory(CharSequence[]) // notification 아래에 히스토리로 표시됨
setOngoing(true) // notification 고정
setSubText(CharSequence) // N버전 이상은 헤더 부분에 추가. 그 이하 버전은 하단에 추가
.setTicker(CharSequence) // accessibility services
.setOnlyAlertOnce(true) // 이미 표시된 notification 이 있다면 소리, 진동, ticker 을 안 냄
Add a progress bar
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID); builder.setContentTitle("Picture Download") .setContentText("Download in progress") .setSmallIcon(R.drawable.ic_notification) .setPriority(NotificationCompat.PRIORITY_LOW); // Issue the initial notification with zero progress int PROGRESS_MAX = 100; int PROGRESS_CURRENT = 0; builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false); // false 는 determinate notificationManager.notify(notificationId, builder.build()); // Do the job here that tracks the progress. // Usually, this should be in a // worker thread // To show progress, update PROGRESS_CURRENT and update the notification with: // builder.setProgress(PROGRESS_MAX, PROGRESS_CURRENT, false); // notificationManager.notify(notificationId, builder.build()); // When done, update the notification one more time to remove the progress bar builder.setContentText("Download complete") .setProgress(0,0,false); notificationManager.notify(notificationId, builder.build());
Set a system-wide category
// CATEGORY_ALARM, CATEGORY_REMINDER, CATEGORY_EVENT, or CATEGORY_CALL NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setCategory(NotificationCompat.CATEGORY_MESSAGE);
Show an urgent message
// Android 10 (API level 29) or higher, you must request the USE_FULL_SCREEN_INTENT permission Intent fullScreenIntent = new Intent(this, ImportantActivity.class); PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT); NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setContentTitle("My notification") .setContentText("Hello World!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setFullScreenIntent(fullScreenPendingIntent, true);
Set lock screen visibility
setVisibility()
VISIBILITY_PUBLIC shows the notification’s full content.
VISIBILITY_SECRET doesn’t show any part of this notification on the lock screen.
VISIBILITY_PRIVATE shows basic information, such as the notification’s icon and the content title, but hides the notification’s full content.
Update a notification
NotificationManagerCompat.notify()
이전에 만든 같은 ID 로 호출
1초 안에 너무 많은 notification 이 발생하면 시스템이 일부를 버릴 수 있다.
Remove a notification
setAutoCancel()
cancel()
cancelAll()
setTimeoutAfter()
Use MessagingStyle
Notification notification = new Notification.Builder(this, CHANNEL_ID) .setStyle(new NotificationCompat.MessagingStyle("Me") .setConversationTitle("Team lunch") .addMessage("Hi", timestamp1, null) // Pass in null for user. .addMessage("What's up?", timestamp2, "Coworker") .addMessage("Not much", timestamp3, null) .addMessage("How about lunch?", timestamp4, "Coworker")) .build();
Create an Expandable Notification
Add a large image
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.new_post) .setContentTitle(imageTitle) .setContentText(imageDescription) .setStyle(new NotificationCompat.BigPictureStyle() .bigPicture(myBitmap)) .build();
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.new_post) .setContentTitle(imageTitle) .setContentText(imageDescription) .setLargeIcon(myBitmap) .setStyle(new NotificationCompat.BigPictureStyle() .bigPicture(myBitmap) .bigLargeIcon(null)) .build();
Add a large block of text
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.new_mail) .setContentTitle(emailObject.getSenderName()) .setContentText(emailObject.getSubject()) .setLargeIcon(emailObject.getSenderAvatar()) .setStyle(new NotificationCompat.BigTextStyle() .bigText(emailObject.getSubjectAndSnippet())) .build();
Create an inbox-style notification
Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.new_mail) .setContentTitle("5 New mails from " + sender.toString()) .setContentText(subject) .setLargeIcon(aBitmap) .setStyle(new NotificationCompat.InboxStyle() .addLine(messageSnippet1) .addLine(messageSnippet2)) .build();
Show a conversation in a notification
NotificationCompat.MessagingStyle.Message message1 = new NotificationCompat.MessagingStyle.Message(messages[0].getText(), messages[0].getTime(), messages[0].getSender()); NotificationCompat.MessagingStyle.Message message2 = new NotificationCompat.MessagingStyle.Message(messages[1].getText(), messages[1].getTime(), messages[1].getSender()); Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.new_message) .setStyle(new NotificationCompat.MessagingStyle(resources.getString(R.string.reply_name)) .addMessage(message1) .addMessage(message2)) .build();
Create a notification with media controls
NotificationCompat.MessagingStyle.Message message1 = new NotificationCompat.MessagingStyle.Message(messages[0].getText(), messages[0].getTime(), messages[0].getSender()); NotificationCompat.MessagingStyle.Message message2 = new NotificationCompat.MessagingStyle.Message(messages[1].getText(), messages[1].getTime(), messages[1].getSender()); Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.new_message) .setStyle(new NotificationCompat.MessagingStyle(resources.getString(R.string.reply_name)) .addMessage(message1) .addMessage(message2)) .build();
MediaSessionCompat mediaSession = new MediaSessionCompat(getApplicationContext(), "session tag"); Notification notification = new NotificationCompat.Builder(context, CHANNEL_ID) // Show controls on lock screen even when user hides sensitive content. .setVisibility(NotificationCompat.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 androidx.media.app.NotificationCompat.MediaStyle() .setShowActionsInCompactView(0, 1, 2) // 0, 1, 2 세 개의 버튼 표시 .setMediaSession(mediaSession.getSessionToken())) .setContentTitle("Wonderful music") .setContentText("My Awesome Band") .setLargeIcon(albumArtBitmap) .build();
implementation "androidx.media:media:1.1.0"
Display time-sensitive notifications
// Android 10 (API level 29) or higher., you must request the USE_FULL_SCREEN_INTENT permission
Create a high-priority notification
Intent fullScreenIntent = new Intent(this, MainActivity.class);
PendingIntent fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, "default")
.setSmallIcon(R.drawable.ic_launcher_foreground)
.setContentTitle("Incoming call")
.setContentText("(919) 555-1234")
.setAutoCancel(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setFullScreenIntent(fullScreenPendingIntent, true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(1, notificationBuilder.build());
Display the notification to the user
// Provide a unique integer for the "notificationId" of each notification. startForeground(notificationId, notification);
Start an Activity from a Notification
Regular activity
This is an activity that exists as a part of your app’s normal UX flow. So when the user arrives in the activity from the notification, the new task should include a complete back stack, allowing them to press Back and navigate up the app hierarchy.
Special activity
The user only sees this activity if it’s started from a notification. In a sense, this activity extends the notification UI by providing information that would be hard to display in the notification itself. So this activity does not need a back stack.
Set up a regular activity PendingIntent
<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> <!-- MainActivity is the parent for ResultActivity --> <activity android:name=".ResultActivity" android:parentActivityName=".MainActivity" /> ... </activity>
Build a PendingIntent with a back stack
// Create an Intent for the activity you want to start Intent resultIntent = new Intent(this, ResultActivity.class); // Create the TaskStackBuilder and add the intent, which inflates the back stack TaskStackBuilder stackBuilder = TaskStackBuilder.create(this); stackBuilder.addNextIntentWithParentStack(resultIntent); // Get the PendingIntent containing the entire back stack PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID); builder.setContentIntent(resultPendingIntent); ... NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(NOTIFICATION_ID, builder.build());
Set up a special activity PendingIntent
<activity android:name=".ResultActivity" android:launchMode="singleTask" android:taskAffinity="" android:excludeFromRecents="true"> </activity>
Intent notifyIntent = new Intent(this, ResultActivity.class); // Set the Activity to start in a new, empty task notifyIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); // Create the PendingIntent PendingIntent notifyPendingIntent = PendingIntent.getActivity( this, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT );
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID); builder.setContentIntent(notifyPendingIntent); ... NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(NOTIFICATION_ID, builder.build());
Create a Group of Notifications
String GROUP_KEY_WORK_EMAIL = "com.android.example.WORK_EMAIL"; Notification newMessageNotification = new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID) .setSmallIcon(R.drawable.new_mail) .setContentTitle(emailObject.getSenderName()) .setContentText(emailObject.getSubject()) .setLargeIcon(emailObject.getSenderAvatar()) .setGroup(GROUP_KEY_WORK_EMAIL) .build();
//use constant ID for notification used as group summary int SUMMARY_ID = 0; String GROUP_KEY_WORK_EMAIL = "com.android.example.WORK_EMAIL"; Notification newMessageNotification1 = new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notify_email_status) .setContentTitle(emailObject1.getSummary()) .setContentText("You will not believe...") .setGroup(GROUP_KEY_WORK_EMAIL) .build(); Notification newMessageNotification2 = new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_notify_email_status) .setContentTitle(emailObject2.getSummary()) .setContentText("Please join us to celebrate the...") .setGroup(GROUP_KEY_WORK_EMAIL) .build(); Notification summaryNotification = new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID) .setContentTitle(emailObject.getSummary()) //set content text to support devices running API level < 24 .setContentText("Two new messages") .setSmallIcon(R.drawable.ic_notify_summary_status) //build summary info into InboxStyle template .setStyle(new NotificationCompat.InboxStyle() .addLine("Alex Faarborg Check this out") .addLine("Jeff Chang Launch Party") .setBigContentTitle("2 new messages") .setSummaryText("janedoe@example.com")) //specify which group this notification belongs to .setGroup(GROUP_KEY_WORK_EMAIL) //set this notification as the summary for the group .setGroupSummary(true) // GroupSummary 알람 밑으로 개별 알람들이 들어간다. .build(); NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this); notificationManager.notify(emailNotificationId1, newMessageNotification1); // 1 notificationManager.notify(emailNotificationId2, newMessageNotification2); // 2 notificationManager.notify(SUMMARY_ID, summaryNotification); // 3 (그룹 알람은 다르게)
https://www.journaldev.com/19382/android-bundled-notifications
Create and Manage Notification Channels
Create a notification channel
private void createNotificationChannel() { // Create the NotificationChannel, but only on API 26+ because // the NotificationChannel class is new and not in the support library if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = getString(R.string.channel_name); String description = getString(R.string.channel_description); int importance = NotificationManager.IMPORTANCE_DEFAULT; NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance); channel.setDescription(description); // Register the channel with the system; you can't change the importance // or other notification behaviors after this NotificationManager notificationManager = getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(channel); } }
Open the notification channel settings
Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); intent.putExtra(Settings.EXTRA_CHANNEL_ID, myNotificationChannel.getId()); startActivity(intent);
Delete a notification channel
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); // The id of the channel. String id = "my_channel_01"; notificationManager.deleteNotificationChannel(id);
채널 얻기
NotificationChannel channel1 = notificationManager.getNotificationChannel()
Create a notification channel group
// The id of the group. String groupId = "my_group_01"; // The user-visible name of the group. CharSequence groupName = getString(R.string.group_name); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); mNotificationManager.createNotificationChannelGroup(new NotificationChannelGroup(groupId, groupName));
| User-visible importance level | Importance (Android 8.0 and higher) | Priority (Android 7.1 and lower) |
|---|---|---|
| Urgent Makes a sound and appears as a heads-up notification |
IMPORTANCE_ |
PRIORITY_ or PRIORITY_ |
| High Makes a sound |
IMPORTANCE_ |
PRIORITY_ |
| Medium No sound |
IMPORTANCE_ |
PRIORITY_ |
| Low No sound and does not appear in the status bar |
IMPORTANCE_ |
PRIORITY_ |
Modify a Notification Badge
Disable badging
String id = "my_channel_01"; CharSequence name = getString(R.string.channel_name); String description = getString(R.string.channel_description); int importance = NotificationManager.IMPORTANCE_LOW; NotificationChannel mChannel = new NotificationChannel(id, name, importance); mChannel.setDescription(description); mChannel.setShowBadge(false); NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); notificationManager.createNotificationChannel(mChannel);
Set custom notification count
Notification notification = new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID) .setContentTitle("New Messages") .setContentText("You've received 3 new messages.") .setSmallIcon(R.drawable.ic_notify_status) .setNumber(messageCount) .build();
Modify a notification’s long-press menu icon
Notification notification = new NotificationCompat.Builder(MainActivity.this, CHANNEL_ID) .setContentTitle("New Messages") .setContentText("You've received 3 new messages.") .setSmallIcon(R.drawable.ic_notify_status) .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL) .build();
Create a Custom Notification Layout
Create custom layout for the content area
// Get the layouts to use in the custom notification RemoteViews notificationLayout = new RemoteViews(getPackageName(), R.layout.notification_small); RemoteViews notificationLayoutExpanded = new RemoteViews(getPackageName(), R.layout.notification_large); // Apply the layouts to the notification Notification customNotification = new NotificationCompat.Builder(context, CHANNEL_ID) .setSmallIcon(R.drawable.notification_icon) .setStyle(new NotificationCompat.DecoratedCustomViewStyle()) .setCustomContentView(notificationLayout) .setCustomBigContentView(notificationLayoutExpanded) // 태블릿 화면 (선택사항) .build();
// 버전이 다른 기기들의 호환성을 위해서
<TextView android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_weight="1" android:text="@string/notification_title" android:id="@+id/notification_title" style="@style/TextAppearance.Compat.Notification.Title" />