Android Notification Click to Broadcast Receiver getting same intent string - java

I have a broadcast receiver which is triggered on a notification click. I'm passing a string in the intent of notification for the broadcast receiver. The values of the string differs everytime however when I am testing my app, I can only see the value I received the first time I clicked the notification. Now every value I'm getting from my notification to the broadcast receiver is same despite passing new values.
My code:
//Creating notification
Intent snoozeIntent = new Intent(getApplicationContext(), ServiceLauncherBroadcast.class);
snoozeIntent.putExtra("order_id", orderId);
//In the broadcast receiver
startWorkManager(intent.getStringExtra("order_id")
//Manifest
<receiver android:name = ".utils.ServiceLauncherBroadcast" />

In your PendingIntent please use this flag:
PendingIntent.FLAG_CANCEL_CURRENT

Related

Android PendingIntent not launching activity after opened from background from notification

I'm using Google FCM to deliver notifications to my app. I am currently sending data notifications and having my android app construct the push notification. I want the user to be able to click on the notification and have it route them to the appropriate fragment/activity.
It is working great except for one flow.
User terminates app -> Receives notification -> Clicks notification -> App launches and data passed correctly to the splash activity from the notification (I'm using a notification activity to broadcast/start intents) -> User receives another notification while app is open -> User clicks notification -> Notification activity, which just previously launched correctly, does not launch.
I'm scratching my head trying to figure out why this could be. My guess is something to do with the contexts being wrong since the app is being launched from the notification, but I've tried to use both "this" and "getApplicationContext()" and neither fixed the issue.
Below is how I construct the notification and pending intent.
Intent notificationIntent = new Intent(this, NotificationActivity.class);
notificationIntent.putExtra(Variables.INTENT_NOTIFICATION_DATA, "dummy_data");
notificationIntent.setAction(Variables.NOTIFICATION_CLICK);
PendingIntent contentIntent = PendingIntent.getActivity(this,
0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, Variables.CHANNEL)
.setContentTitle("New Notification")
.setContentText("Dummy text")
.setSmallIcon(R.drawable.notification_icon)
.setContentIntent(contentIntent)
.setAutoCancel(true)
.setOngoing(false)
.build();
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
mNotificationManager.notify(0, notification);
}

Problem with Receiver which receives Intents from Notification

I have a code that send a broadcast to a broadcast receiver.
Intent intentPrev = new Intent(ACTION_PREV);
PendingIntent pendingIntentPrev = PendingIntent.getBroadcast(this, 0, intentPrev, PendingIntent.FLAG_UPDATE_CURRENT);
LocalBroadcastManager.getInstance(this).sendBroadcast(intentPrev);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, notification);
In another class I have a Receiver:
private BroadcastReceiver NotificationReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("PREVIOUS")){
playPrev();
}
}
};
And in onCreate method I register this receiver:
LocalBroadcastManager.getInstance(this).registerReceiver(NotificationReceiver, new IntentFilter("PREVIOUS"));
The main aim was to reach the following result: when user clicks on button Previous in notification, the previous song will play. But when I run the app and choose the music I can't listen to music, as always the previous plays. So, it seems that there's a perpetual loop somewhere. What's the matter? How to solve this problem if I want to play only one previous song but not all previous songs?
There are two types of broadcasts: system broadcasts and local broadcasts.
Local broadcasts work through LocalBroadcastManager exclusively. If you see anything else tied to "broadcast", 99.99% of the time, that is referring to system broadcasts.
In particular, PendingIntent.getBroadcast() gives you a PendingIntent that will send a system broadcast. That, in turn, means that your receiver needs to be set up to receive a system broadcast, either because:
It is registered in the manifest with a <receiver> element, or
It is registered dynamically by calling registerReceiver() on a Context (not on LocalBroadcastManager)
Note that on Android 8.0+, implicit broadcasts (ones with just an action string) are banned, in effect. If you elect to register your receiver in the manifest, use an Intent that identifies the specific receiver (e.g., new Intent(this, MyReceiverClass.class)). If you elect to register your receiver via registerReceiver()... I think there is a recipe for how to handle that, but I forget the details.

Notification DeleteIntent broken on later versions of Android

In our app OneBusAway Android (open-source on Github), we need to be notified when the user dismisses a particular reminder notification, so we don't post another reminder notification for the same event (how long until their bus arrives).
We're doing this by listening for an Intent in our app, registered as the DeleteIntent with the Notification. When the user dismisses the notification (either by swiping it away, or tapping the clear button in the notification window), our app should receive that Intent.
From testing, it seems that with the current version on Google Play (and the current master branch on Github), the DeleteIntent is never received in our application in the following versions of Android:
Android 4.4.3
Android 4.4.4
However, the exact same code DOES work (i.e., the Intent registered as the DeleteIntent is received by the app) on:
Android 2.3.3
Android 2.3.6
Android 4.1.1
Android 4.1.2
I've looked at the following SO posts that deal with DeleteIntent, and none of the solutions listed work on Android 4.4.3 and 4.4.4:
Notification Auto-Cancel does not call DeleteIntent
Android - DeleteIntent, how to use?
Notification deleteIntent does not work
https://stackoverflow.com/questions/24218626/how-to-detect-notification-cancel-event-in-android-not-deleteintent
https://stackoverflow.com/questions/22769523/why-my-deleteintent-is-not-working-on-my-notification
Android deleteIntent not working? What's wrong with my code?
Custom actions using implicit intents between applications
The current working master branch uses a Service to listen for the Intent. However, based on some of the above posts, I did tweak some of the code to be more in line with working examples that use a BroadcastReceiver to listen for the Intent.
The code using the BroadcastReceiver is in the following Github branch:
https://github.com/CUTR-at-USF/onebusaway-android/tree/issue104-RepeatingReminders
Below are excerpts for what my current version looks like (that still works on Android 4.1.2 and lower, but not 4.4.3 or 4.4.4), along with links to Github source:
Creating the 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();
}
Title and other dynamic notification info are set a few lines later (and reset later, if the notification remains undismissed):
#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 the 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">
<!-- These action names must match the constants in TripService -->
<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, the AlarmReceiver never sees the Intent when the user dismisses the notification.
I also tried adding a MIME type, as specified in Custom actions using implicit intents between applications, but that didn't work on Android 4.4.3/4.4.4 either:
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))
//.setLights(0xFF00FF00, 1000, 1000)
//.setVibrate(VIBRATE_PATTERN)
.build();
REMINDER_MIME_TYPE is application/vnd.com.joulespersecond.seattlebusbot.reminder
Manifest for using the MIME type:
<receiver android:name=".AlarmReceiver">
<!-- These action names must match the constants in TripService -->
<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 either.
Any ideas why this isn't working on Android 4.4.3/4.4.4?
More info is shown in the Github issue for this problem.
EDIT
I've also replicated this issue in a small Github project "DeleteIntentDemo":
https://github.com/barbeau/DeleteIntentDemo
Instructions to reproduce are in the README for this project.
EDIT 2
This appears to be due to a bug in Android in Notification.setLatestEventInfo() - I've reported it here:
https://code.google.com/p/android/issues/detail?id=73720
Please see #CommonsWare's answer for the workaround.
EDIT 3
My AOSP patch to fix this issue has now been merged so this problem won't appear for legacy apps in future releases of Android:
https://code.google.com/p/android/issues/detail?id=73720#c4
However, in the above AOSP thread is it emphasized that one should no longer be using Notification.setLatestEventInfo() - instead, use Notification.Builder to create a new Notification.
In your sample project, if you remove the following line, the deleteIntent works on a Nexus 4 running 4.4.4:
setLatestInfo(getActivity(), notification, routeId);
I suspect that this call is wiping out your deleteIntent. It may work to re-apply your deleteIntent to the Notification as part of your setLatestInfo() processing.
You must have a different problem because I'm able to receive the deleteintent in several 4.3 and 4.4 emulators.
I wanted to test your "simple" project but it uses Android Studio, so I made my own simpler test.
Steps to reproduce:
-Create an Activity and set the launch mode to singleInstance in the manifest.
-In the handler of a button or menu item, launch a notification:
Intent deleteIntent = new Intent(this, MainActivity.class);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(android.R.drawable.ic_dialog_alert)
.setOnlyAlertOnce(true)
.setContentTitle("Notification delete intent test")
.setContentText("Please dismiss this notification by swipping or deleting it. A Toast will be shown if the deletion intent works.")
.setDeleteIntent(PendingIntent.getActivity(this, 0, deleteIntent, 0))
.setAutoCancel(true)
.build();
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
nm.notify((int)System.currentTimeMillis(), notification);
-Override onNewIntent to show a toast or log a message when the notification is cancelled:
#Override
public void onNewIntent(Intent intent){
Toast.makeText(this, "Notification deleted!", Toast.LENGTH_LONG).show();
}
To dismiss the notification either swipe or press the clear button. It wont work pressing over it because autocancel is not considered an explicit user action and hence the delete intent wont be delivered.

Passing data from android activity to broadcast receiver on device boot up

I always get bundle value null when I pass data from activity to broadcast receiver.
My receiver will start on boot up.
This is the code in my activity class
Intent intent= new Intent();
intent.setAction("android.intent.action.BOOT_COMPLETED");
intent.putExtra("test", "test");
sendBroadcast(intent);
This is the code in my receiver class:
String testValue = intent.getStringExtra("test");
Your code in activity will never be called upon booting up. System invokes onReceive() with its own intent. You can check this by putting some logs in activity code - this log will not be printed in logcat.

AlertDialog not shown after clicking Notification

I am triying to do the following:
My app has an AsyncTask that eventually creates an AlertDialog to request the user to isert a code. This can happend when the app is in the foreground, so I launch a notification to inform the user and my idea is that once he clicks the notification, the main activity with the AlertDialog is shown.
Nevertheless what is happening is that once the user clicks on the notification, just the activity where the AlertDialog is supposed to be is shown and I get a WindowLeaked exception probably caused by the Dialog.
There is the code that I am using to launch the notification (from the method onProgressUpdate of the AsyncTask):
public void launch_notification(){
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(context.getString(R.string.opening_request_notification_title))
.setContentText(context.getString(R.string.opening_request_notification_text));
/* The intent must be created with an specific content and then frozen to be used
later using a pending intent.
*/
Intent notificationIntent = new Intent(context, Main.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notificationBuilder.setContentIntent(pendingIntent);
notificationBuilder.setAutoCancel(true);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
Any idea will be welcome.
Thanks a lot :)
Better to create a separate Activity(example DialogActivity) and in your manifest set for DialogActivity.
Your notification creation seems fine and you invoke the method from onProgressUpdate which is also fine.
So there must be something wrong with your activity and the way it handles the dialog.
If you could provide your Main class we could know for sure, but what I guess is happening that in your AsyncTask you show some sort of dialog, perhaps a progress dialog.
If that is the case then when you get the notification (on progress update) and you click it you start Main activity again, so you end up creating another instance of main activity, and hence the leaking window.
Try adding the flag FLAG_ACTIVITY_CLEAR_TOP.
As the API states:
If set, and the activity being launched is already running in the current task, then instead of launching a new instance of that activity, all of the other activities on top of it will be closed and this Intent will be delivered to the (now on top) old activity as a new Intent.
Hope that this will help you out.

Categories