In our OneBusAway Android app ( open source on Github ), we need to receive notifications when a user rejects a reminder notification, so we donโt send another reminder for the same event (how long their bus takes).
We do this by listening to the Intent in our application registered as DeleteIntent using Notification . When the user rejects the notification (either by unscrewing it or by clicking the clear button in the notification window), our application should receive this Intent .
From testing, it seems that with the current version on Google Play (and the current main branch on Github ), DeleteIntent is never accepted in our application in the following versions of Android:
- Android 4.4.3
- Android 4.4.4
However, the same DOES code works (i.e., the Intent registered as DeleteIntent received by the application):
- Android 2.3.3
- Android 2.3.6
- Android 4.1.1
- Android 4.1.2
I looked at the following SO posts regarding DeleteIntent and none of these solutions work in Android 4.4.3 and 4.4.4:
The current working branch of the wizard uses the Service to listen to Intent. However, based on some of the posts above, I made some of the code to fit the working examples that BroadcastReceiver uses to listen to Intent.
Code using BroadcastReceiver is in the following Github branch:
https://github.com/CUTR-at-USF/onebusaway-android/tree/issue104-RepeatingReminders
Below are the snippets for my current version (which still works on Android 4.1.2 and lower, but not 4.4.3 or 4.4.4), as well as links to the Github source:
Create Notification
https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/java/com/joulespersecond/seattlebusbot/tripservice/NotifierTask.java#L131
private Notification createNotification(Uri alertUri) { //Log.d(TAG, "Creating notification for alert: " + alertUri); Intent deleteIntent = new Intent(mContext, AlarmReceiver.class); deleteIntent.setAction(TripService.ACTION_CANCEL); deleteIntent.setData(alertUri); return new NotificationCompat.Builder(mContext) .setSmallIcon(R.drawable.ic_stat_notification) .setDefaults(Notification.DEFAULT_ALL) .setOnlyAlertOnce(true) .setDeleteIntent(PendingIntent.getBroadcast(mContext, 0, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT)) .setAutoCancel(true) .build(); }
The name and other information of the dynamic notification are set a few lines later (and reset later if the notification remains unmanageable):
@SuppressWarnings("deprecation") private void setLatestInfo(Notification notification, String stopId, String routeId, long timeDiff) { final String title = mContext.getString(R.string.app_name); final PendingIntent intent = PendingIntent.getActivity(mContext, 0, new ArrivalsListActivity.Builder(mContext, stopId).getIntent(), PendingIntent.FLAG_UPDATE_CURRENT); notification.setLatestEventInfo(mContext, title, getNotifyText(routeId, timeDiff), intent); }
TripService contains constants for the action:
public static final String ACTION_CANCEL = "com.joulespersecond.seattlebusbot.action.CANCEL";
Alarmreceiver
https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/java/com/joulespersecond/seattlebusbot/AlarmReceiver.java
public class AlarmReceiver extends BroadcastReceiver { private static final String TAG = "AlarmReceiver"; @Override public void onReceive(Context context, Intent intent) { Log.d(TAG, "In onReceive with intent action " + intent.getAction()); ... } }
AndroidManifest
https://github.com/CUTR-at-USF/onebusaway-android/blob/issue104-RepeatingReminders/onebusaway-android/src/main/AndroidManifest.xml
<receiver android:name=".AlarmReceiver"> <intent-filter> <action android:name="com.joulespersecond.seattlebusbot.action.SCHEDULE" /> <action android:name="com.joulespersecond.seattlebusbot.action.POLL" /> <action android:name="com.joulespersecond.seattlebusbot.action.CANCEL" /> </intent-filter> </receiver>
With the above, on Android 4.4.3 / 4.4.4, AlarmReceiver never sees the intent when the user rejects the notification.
I also tried to add a MIME type, as indicated in Custom Actions, using implicit intentions between applications , but this does not work on Android 4.4.3 / 4.4. 4:
Intent deleteIntent = new Intent(mContext, AlarmReceiver.class); deleteIntent.setAction(TripService.ACTION_CANCEL); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { deleteIntent.setDataAndTypeAndNormalize(alertUri, TripService.REMINDER_MIME_TYPE); } else { deleteIntent.setDataAndType(alertUri, TripService.REMINDER_MIME_TYPE); } return new NotificationCompat.Builder(mContext) .setSmallIcon(R.drawable.ic_stat_notification) .setDefaults(Notification.DEFAULT_ALL) .setOnlyAlertOnce(true) .setDeleteIntent(PendingIntent.getBroadcast(mContext, 0, deleteIntent, 0))
REMINDER_MIME_TYPE is application/vnd.com.joulespersecond.seattlebusbot.reminder
Demonstrate using the MIME type:
<receiver android:name=".AlarmReceiver"> <intent-filter> <action android:name="com.joulespersecond.seattlebusbot.action.SCHEDULE" /> <action android:name="com.joulespersecond.seattlebusbot.action.POLL" /> <action android:name="com.joulespersecond.seattlebusbot.action.CANCEL" /> <data android:mimeType="application/vnd.com.joulespersecond.seattlebusbot.reminder" /> </intent-filter> </receiver>
I also tried not using the support library (i.e. using Notification.Builder instead of NotificationCompat.Builder ), but that didn't change anything.
Any ideas why this is not working on Android 4.4.3 / 4.4.4?
See the Github issue for this issue for more information.
EDIT
I also reproduced this problem in a small Github project "DeleteIntentDemo":
https://github.com/barbeau/DeleteIntentDemo
Instructions for reproducing are provided in the README for this project.
EDIT 2
This is due to an Android bug in Notification.setLatestEventInfo() - I reported it here: https://code.google.com/p/android/issues/detail?id=73720
Check out @CommonsWare's answer for a workaround.
EDIT 3
My AOSP patch to fix this problem is now merged, so this problem will not appear for legacy applications in future versions of Android: https://code.google.com/p/android/issues/detail?id=73720#c4
However, the AOSP stream above emphasizes that you no longer need to use Notification.setLatestEventInfo() - use Notification.Builder instead to create a new notification.