3

I want to display a notification inside the app that disappears when the notification is tapped without starting an activity.

I use an empty intent and it works:

Intent intent = new Intent();
PendingIntent contentIntent = PendingIntent.getActivity(context, (int)System.currentTimeMillis(), intent, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context, "")
                .setSmallIcon(R.drawable.icon)
                .setContentTitle(title)
                .setContentText(text)
                .setAutoCancel(true)
                .setTicker(text);
                .setContentIntent(contentIntent);

However, there are some crashes:

java.lang.RuntimeException: bad array lengths
    at android.os.Parcel.readIntArray(Parcel.java:789)
    at android.app.INotificationManager$Stub$Proxy.enqueueNotificationWithTag(INotificationManager.java:339)
    at android.app.NotificationManager.notify(NotificationManager.java:139)
    at android.app.NotificationManager.notify(NotificationManager.java:112)
    ...

According to this SO answer the crashes seem to happen because intent is not starting an activity.

A notification can be dismissed by its ID, but I cannot dismiss it when there is no activity to start and call the dismiss method.

How can I dismiss the notification on tap inside the app without using an empty intent?


Update:

According to this SO questions it seems to be an Android issue. The crashes I got reported also happened on Android 4.3.

Update 2:

According to this SO answer it seems to be due to a too large bitmap set with setLargeIcon. So I am reducing the bitmap size now with Glide.

Manuel
  • 14,274
  • 6
  • 57
  • 130

3 Answers3

7

You can create an intent which calls a BroadcastReceiver which then cancels the notification.

Your PendingIntentcan be created like this:

private PendingIntent getCancelNotificationIntent() {
    Intent cancelIntent = new Intent(context, CancelNotification.class);
    return PendingIntent.getBroadcast(context, 0, cancelIntent, PendingIntent.FLAG_UPDATE_CURRENT);
}

The CancelNotification.java class would look similar to this:

public class CancelNotification extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        notificationManager.cancel(NOTIFICATION_ID);
    }
}

EDIT:
NOTIFICATION_ID is a constant you define and pass to the NotificationManager like this:

notificationManager.notify(NOTIFICATION_ID, yourNotificationObject);

NOTE: don't forget to register the receiver in your manifest file like this:

<receiver android:name="com.example.package.CancelNotification" />
oemel09
  • 744
  • 7
  • 15
  • 1
    @IgorGanapolsky It's a constant you define when publishing the notification via `NotificationManager`: `notificationManager.notify(NOTIFICATION_ID, yourNotificationObject);` – oemel09 May 05 '20 at 12:01
  • If someone finds this answer, if you have multiple notifications, your requestCode in PendingIntent should be unique (ex. use id of your notification). – BigBoiVladica Feb 05 '21 at 18:15
3

If you don't want to start an activity when users tap the notification you can build an pending intent which sends a broadcast or start a service.

Here is an example:

PendingIntent.getBroadcast(context, 12, new Intent("any intent action"), PendingIntent.FLAG_UPDATE_CURRENT)
Link182
  • 733
  • 6
  • 15
1

But what prevents your activity to have implementation like this:

@Override
public void onCreate(Bundle savedInstanceState) {}

with additional nodisplay theme in manifest:

android:theme="@android:style/Theme.NoDisplay"

It'd be simply a no-op one.

Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141