55

I would like to update notification data, but the only way I found is to launch a new one with the same Id.

The problem is that I don't want to raise a new one if the original has beed canceled. Is there a way to tell if a notification is visible or canceled? Or a way to update a notification only if it exists?

Asaf Pinhassi
  • 15,177
  • 12
  • 106
  • 130

6 Answers6

59

If you're app has a minimum API >= 23 can use this method to get active notification:

NotificationManager mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
StatusBarNotification[] notifications = mNotificationManager.getActiveNotifications();
for (StatusBarNotification notification : notifications) {
  if (notification.getId() == 100) {
    // Do something.
  }
}
lasec0203
  • 2,422
  • 1
  • 21
  • 36
Sayed Abolfazl Fatemi
  • 3,678
  • 3
  • 36
  • 48
38

This is how I solved it:

    private boolean isNotificationVisible() {
    Intent notificationIntent = new Intent(context, MainActivity.class);
    PendingIntent test = PendingIntent.getActivity(context, MY_ID, notificationIntent, PendingIntent.FLAG_NO_CREATE);
    return test != null;
}

This is how I generate the notification:

    /**
 * Issues a notification to inform the user that server has sent a message.
 */
private void generateNotification(String text) {

    int icon = R.drawable.notifiaction_icon;
    long when = System.currentTimeMillis();
    NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    Notification notification = new Notification(icon, text, when);
    String title = context.getString(R.string.app_name);
    Intent notificationIntent = new Intent(context, MainActivity.class);

    // set intent so it does not start a new activity
    //notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    PendingIntent intent = PendingIntent.getActivity(context, MY_ID, notificationIntent, 0);
    notification.setLatestEventInfo(context, title, text, intent);

    notification.flags |= Notification.FLAG_AUTO_CANCEL; //PendingIntent.FLAG_ONE_SHOT

    notificationManager.notify(MY_ID, notification);
}
Asaf Pinhassi
  • 15,177
  • 12
  • 106
  • 130
  • there have to be something what is wrong. when I write in my ```onResume()``` method that ```if(isNotificationVisible())``` my notification should be canceled with: ```((NotificationManager) getSystemService(NOTIFICATION_SERVICE)).cancel(MY_ID);``` and after that ```finish(); startActivity(getIntent());``` I get a loop which leads to restart my phone. so this method should be treated with caution.... – maysi Jul 28 '13 at 23:59
  • 10
    Not working for me. This always returns true for me. – Saket Jan 21 '16 at 10:26
  • 1
    Didn't work for me in Android 4.3. The `PendingIntent` stuck around after I dismissed the notification, and even after I killed the entire app. Only restarting the phone got rid of it. Also, `setLatestEventInfo()` no longer seems to exist, so I just used `setContentIntent()` instead. – Sam Dec 03 '16 at 05:01
  • 4
    Just tested this in Android 7.1, and `isNotificationVisible()` always returned `false`. – Sam Dec 03 '16 at 05:06
  • 1
    Not working for me on Android 5.0, test is always null – Ashraf Alshahawy Sep 22 '17 at 09:04
  • A few notes: PendingIntents stick around until explicitly cancelled. Dismissing your notification or cancelling it does not kill the pending intent. A reboot does kill the pending intents. Thus, careful cancelling of PendingIntents is required for this method to be accurate. When checking in isNotificationVisible(), your requestCode (MY_ID above) MUST match the original one used when creating the notification. The intents must be identical too. – Chris Knight Oct 01 '19 at 19:31
3

I think you can use deleteIntent of Notification class.

I remember in one of my application I use use to fire a Broadcast (custom Broadcast) when a notification is cancelled or the Notification tray was cleared.

Vishal Vyas
  • 2,571
  • 1
  • 22
  • 39
3

You can check as follow in Kotlin:

  val mNotificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
    val notifications: Array<StatusBarNotification> = mNotificationManager.activeNotifications

    if(notifications.isNotEmpty())
    {
      //you don't have notifications 
    }
    else
    {
      //you have notifications 
    }
Osama Ibrahim
  • 995
  • 10
  • 13
1

An alternative to the deleteIntent is the following which has proved beneficial in my own app:

Basically, you create an intent with your notification that starts an IntentService (or any other service) and in onHandleIntent you can set a flag indicating whether the notification is active.
You can set this intent to be fired when the user taps the notification (contentIntent) and/or when the user clears it from the list (deleteIntent).

To illustrate it, here is what I do in my own app. When building the notification I set

Intent intent = new Intent(this, CleanupIntentService.class);
Notification n = NotificationCompat.Builder(context).setContentIntent(
        PendingIntent.getActivity(this, 0, intent, 0)).build();

When the notification is tapped, my CleanupIntentService is launched, setting a flag (in the service that created the notification):

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    super.onCreate(); // If removed, onHandleIntent is not called
    return super.onStartCommand(intent, flags, startId);
}


@Override
protected void onHandleIntent(Intent intent) {
    OtherService.setNotificationFlag(false);
}
stemadsen
  • 1,841
  • 2
  • 16
  • 15
1

In my situation, I wanted to check if a Notification was already shown before showing another. And it turns out there's a simple way to do it without listening to when the Notification was deleted or dismissed with .setAutoCancel(true) on NotificationManagerCompat.Builder.

 private val NOTIF_ID = 80085
 private val CHANNEL_ID = "com.package.name.ClassName.WhatNotifycationDoes"  
 private lateinit var mNotificationManagerCompat: NotificationManagerCompat
 private lateinit var mNotificationManager: NotificationManager // this is for creating Notification Channel in newer APIs

override fun onCreate() {
    super.onCreate()

    mNotificationManagerCompat = NotificationManagerCompat.from(this)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
       mNotificationManager = getSystemService(NotificationManager::class.java)

    showNotification()
    startWatching()
}

private fun showNotification() {
        val contentIntent = Intent(this, MainActivity::class.java)
                .apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK }
        val contentPendingIntent = PendingIntent.getActivity(this, 1, contentIntent, 0)

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        val name = getString(R.string.app_name)
        val importance = NotificationManager.IMPORTANCE_HIGH
        val channel = NotificationChannel(CHANNEL_ID, name, importance)
        channel.description = getString(R.string.your_custom_description)
        mNotificationManager.createNotificationChannel(channel)
    }

    val mNewStatusNotificationBuilder = NotificationCompat.from(this)
    mNewStatusNotificationBuilder = NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle(getString(R.string.app_name))
            .setContentText(getString(R.string.simple_text))
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setContentIntent(contentPendingIntent)
            .setAutoCancel(true) // This dismisses the Notification when it is clicked
            .setOnlyAlertOnce(true) //this is very important, it pops up the notification only once. Subsequent notify updates are muted. unless it is loaded again    

    if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP)
        mNewStatusNotificationBuilder.setSmallIcon(R.drawable.ic_notification)

    notification = mNewStatusNotificationBuilder.build()

    mNotificationManagerCompat.notify(NOTIF_ID, notification)
}
EdgeDev
  • 2,376
  • 2
  • 20
  • 37