В Android 4.1 появилась возможность добавлять кнопки в уведомление.

Для этого используется метод addAction

Intent deleteIntent = new Intent(this, MyService.class);
deleteIntent.setAction("ru.startandroid.notifications.action_delete");
PendingIntent deletePendingIntent = PendingIntent.getService(this, 0, deleteIntent, 0);

NotificationCompat.Builder builder =
       new NotificationCompat.Builder(this)
               .setSmallIcon(R.mipmap.ic_launcher)
               .setContentTitle("Title")
               .setContentText("Notification text")
               .addAction(android.R.drawable.ic_delete, "Delete", deletePendingIntent);

Сначала создаем PendingIntent, который будет вызван по нажатию на кнопку. Затем передаем его в метод addAction, а вместе с ним иконку и текст для кнопки.

 

При раскрытии уведомления будет отображена кнопка.

 

По нажатию на кнопку уведомление само не закроется. Если вам необходимо его закрыть, используйте cancel в обработчике нажатия.

Вы можете добавить до трех Action кнопок. Кнопки не должны дублировать действие, которое происходит по нажатию на уведомление.

На последних версиях Android почему-то не отображается иконка кнопки, только текст.

 

 

 

Reply

Начиная с API 24 появилась возможность добавить в уведомление строку ввода. Это может быть удобно, например, в чат-приложениях. Пользователь сможет ответить на сообщение прямо из уведомления.

 

Рассмотрим пример реализации:

// id
int itemId = ...;

// Intent
Intent intent = new Intent(this, MyService.class);
intent.setAction(ACTION_REPLY);
intent.putExtra(EXTRA_ITEM_ID, itemId);

// PendingIntent
PendingIntent replyPendingIntent =
       PendingIntent.getService(getApplicationContext(),
               itemId, intent, PendingIntent.FLAG_UPDATE_CURRENT);

// RemoteInput
RemoteInput remoteInput = new RemoteInput.Builder(EXTRA_TEXT_REPLY)
       .setLabel("Type message")
       .build();

// Action
NotificationCompat.Action action =
       new NotificationCompat.Action.Builder(android.R.drawable.ic_menu_send,
               "Reply", replyPendingIntent)
               .addRemoteInput(remoteInput)
               .build();

// Notification builder
NotificationCompat.Builder builder =
       new NotificationCompat.Builder(this)
               .setSmallIcon(R.mipmap.ic_launcher)
               .setContentTitle("Title")
               .setContentText("Notification text")
               .addAction(action);

// Notification
Notification notification = builder.build();

// Show notification
NotificationManager notificationManager =
       (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(itemId, notification);

Разбираем код по порядку.

У нас есть некий itemId. Это может быть, например, id чата, в который пришло новое сообщение.

Создаем Intent и PendingIntent. Тут ничего нового. Мы будем вызывать сервис MyService и передавать ему itemId. В PendingIntent используем itemId в качестве requestCode.

Далее создаем RemoteInput. Здесь настраиваем все, что касается поля ввода, которое будет отображено в уведомлении. В конструкторе билдера необходимо указать ключ, который мы в дальнейшем будем использовать, чтобы из Bundle достать текст, который введет пользователь. В метод setLabel можно передать текст, который будет использован как hint (подсказка) в поле ввода.

Создаем Action кнопку с помощью билдера. Передаем туда стандартный набор: иконку, текст и PendingIntent. А в метод addRemoteInput передаем ранее созданный RemoteInput. Это будет Action кнопка Reply, по нажатию на которую будет появляться строка ввода.

Далее используем созданный Action в билдере уведомления, создаем уведомление и отображаем его.

В методе notify используем itemId. Соответственно, зная id чата, мы всегда сможем обновить или удалить уведомление.

 

Обратите внимание, что PendingIntent, который мы создаем и используем в Action кнопке Reply, будет использован не по нажатию на уведомление, и даже не по нажатию на Reply. Он будет использован, когда пользователь нажмет на кнопку отправки текста.

В этом примере, кстати, по нажатию на уведомление, ничего не произодет, т.к. в билдере уведомления я не использовал метод setContentIntent, чтобы не усложнять пример.

 

Запускаем

В уведомлении создается Action кнопка Reply. Она открывает строку ввода. 

По нажатию на кнопку отправки текста система запускает MyService, который мы указывали в PedningIntent, и отображает прогрессбар. Но он будет крутиться бесконечно, пока мы программно не обновим или не удалим уведомление.

 

Давайте посмотрим, как в MyService мы можем получить введенный пользователем текст и убрать прогрессбар из уведомления:

if (ACTION_REPLY.equals(intent.getAction())) {

   // Get reply text
   CharSequence replyText = null;
   Bundle results = RemoteInput.getResultsFromIntent(intent);
   if (results != null) {
       replyText = results.getCharSequence(EXTRA_TEXT_REPLY);
   }

   // Get itemId
   int itemId = intent.getIntExtra(EXTRA_ITEM_ID, 0);

   // Perform operations with replyText and itemId
   ...

   // Create new notification
   Notification repliedNotification =
           new NotificationCompat.Builder(getBaseContext())
                   .setSmallIcon(R.mipmap.ic_launcher)
                   .setContentText("Replied")
                   .build();

   // Update notification
   NotificationManager mNotificationManager =
           (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
   mNotificationManager.notify(itemId, repliedNotification);

}

Методом RemoteInput.getResultsFromIntent достаем Bundle из Intent. Из этого Bundle можем достать текст, который вводил пользователь в уведомлении. Для этого используем ключ EXTRA_TEXT_REPLY (который ранее использовали в билдере RemoteInput).

Далее из Intent достаем itemId.

Теперь у нас есть id чата и текст, который ввел пользователь. Можем сохранить его в БД, отправить на сервер или сделать еще что-то. Это зависит от логики приложения.

Далее нам необходимо разобраться с уведомлением. Напомню, что после отправки текста оно отображает прогрессбар. В этом примере мы создаем простое уведомление с текстом Replied и заменяем им (используя тот же itemId в методе notify) то уведомление, из которого был отправлен текст.

 

Пробуем еще раз отправить текст из уведомления

На этот раз мы в обработчике обновили уведомление и прогрессбар пропал.

 

Что вы будете делать с уведомлением после отправки текста - это ваше решение. Например, вы можете просто удалить его. Либо, если вы в уведомлении отображаете последние сообщения чата, вы можете обновить это уведомление с учетом нового сообщения и снова сделать там кнопку Reply.


Присоединяйтесь к нам в Telegram:

- в канале StartAndroid публикуются ссылки на новые статьи с сайта startandroid.ru и интересные материалы с хабра, medium.com и т.п.

- в чатах решаем возникающие вопросы и проблемы по различным темам: Android, Compose, Kotlin, RxJava, Dagger, Тестирование, Performance 

- ну и если просто хочется поговорить с коллегами по разработке, то есть чат Флудильня




Language

Автор сайта

Дмитрий Виноградов

Подробнее можно посмотреть или почитать.

Никакие другие люди не имеют к этому сайту никакого отношения и просто занимаются плагиатом.

Социальные сети

 

В канале я публикую ссылки на интересные и полезные статьи по Android

В чате можно обсудить вопросы и проблемы, возникающие при разработке



Группа ВКонтакте



Поддержка проекта

Яндекс
410011180491924

WebMoney
R248743991365
Z551306702056

Paypal