BroadcastReceiver does not react on notifications created in GmcService - android

Using Xamarin.Android.
I have a BroadcastReceiver:
public class MyBroadcastReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
try
{
string someExtra = intent.Extras.GetString("someExtra", string.Empty);
}
catch (Exception)
{
}
}
}
I use a Google Cloud Messaging Service and create a notification when receive some message. Using a notification builder's SetContentIntent I export some extras to the activity that will operate this notification if user opens it. And it works. But when I initialize my notification builder with SetDeleteIntent inside the GCM Service, the notification does not trigger OnReceive in the BroadcastReceiver if user swipe to dismiss the notification.
When I do all the same inside my activity (not inside the GCM service) OnReceive is triggered on every notification's swipe-to-dismiss event. But it does not work inside the service.
I have even implemented the same CreateNotification method in my activity as in the service. When I call it (to create the notification) from my activity - all works perfect. When I call it from the service using a static pointer to the current instance of the activity - MyActivity.CurrentInstance.CreateNotification(...) - my notification does not react on swipe-to-dismiss event. I even tried to put the CreateNotification's code in RunOnUiThread - no result.
Therefore, notification's swipe-to-dismiss event is triggered only in case if that notification has been created in my activity. But I create notifications when receive messages from GCM. It actually creates notifications even when application is not running.
public void CreateNotification(........) {
//RunOnUiThread(() => {
var notificationBuilder = new Notification.Builder(this);
notificationBuilder.SetContentTitle(title);
notificationBuilder.SetContentText(description);
notificationBuilder.SetSmallIcon(Resource.Drawable.Icon);
var notificationIntent = new Intent(this, typeof(MainActivity));
notificationIntent.PutExtra(.......)
var contentIntent = PendingIntent.GetActivity(Application.Context, 0, notificationIntent, PendingIntentFlags.CancelCurrent);
notificationBuilder.SetContentIntent(contentIntent);
// Actually my headache
const String NOTIFICATION_DELETED_ACTION = "NOTIFICATION_DELETED";
var receiver = new MyBroadcastReceiver();
RegisterReceiver(receiver, new IntentFilter(NOTIFICATION_DELETED_ACTION));
Intent intent = new Intent(NOTIFICATION_DELETED_ACTION);
intent.PutExtra(.......)
var deleteIntent = PendingIntent.GetActivity(Application.Context, 0, intent, PendingIntentFlags.CancelCurrent);
notificationBuilder.SetDeleteIntent(deleteIntent);
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
notificationManager.Notify(1, notificationBuilder.Build());
//});
}
Any ideas how to create a notification (inside the service) that will be able to trigger its swipe-to-dismiss event?

notification's swipe-to-dismiss event is triggered only in case if that notification has been created in my activity
When you When you use SetDeleteIntent(deleteIntent) method, make sure your deleteIntent is initialized by using PendingIntent.GetBroadcast method.
GetBroadcastet means retrieve a PendingIntent that will perform a broadcast, like calling Context.sendBroadcast(). When you use GetActivity method, it means retrieve a PendingIntent that will start a new activity. That's reason that your notification does not trigger OnReceive in the BroadcastReceiver. For more information you could read this document.
Modify your code :
var deleteIntent = PendingIntent.GetActivity(Application.Context, 0, intent, PendingIntentFlags.CancelCurrent);
To :
var deleteIntent = PendingIntent.GetBroadcast(Application.Context, 0, intent, PendingIntentFlags.CancelCurrent);
Then in your GCM Service, your notification's swipe-to-dismiss event will be triggered .

Related

Multiple Notification with dismiss notification action button

I have an app which associates some entities with a unique ID and notifies about the entities to the user, which I'm gonna use notificationID to be the same as entity ID.
I have built a notification with a dismiss action based on the following sample solution exactly without any modification.
So far things are going well until I try to create 2 notifications with different ID using the sample.
A problem arises in that the dismiss button only receives the notificationID of the first notification:
The first notification behaves normally as expected.
But the second notification's getExtra() in BroadcastReceiver takes the notificationID of the FIRST notification instead and cancelling the notification just keeps cancelling the first notification.
My create Notification function, I just call this function twice with different IDs:
void createNoti(int NOTIFICATION_ID){
Intent buttonIntent = new Intent(context, ButtonReceiver.class);
buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, buttonIntent, 0);
NotificationCompat.Builder mb = new NotificationCompat.Builder(getBaseContext());
mb.addAction(R.drawable.ic_Action, "My Action", btPendingIntent);
manager.notify(NOTIFICATION_ID, mb.build());
}
BroadcastReceiver class:
public class ButtonReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("notificationId", 0);
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(notificationId);
}
}
I believe the issue is in passing in 0 into PendingIntent:
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, buttonIntent, 0);
I had the same issue until I started passing in the notification id as the 2nd argument; so instead of passing in 0, pass in the id of the notification:
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), NOTIFICATION_ID, buttonIntent, 0);
After I made that change, I noticed that when clicking on individual notifications (especially notifications in a group) everything worked as intended.

Android stop Service using (Pending) Intent

I have the method
private Notification getNotification() {
Activity currentActivity = MyApplication.getApplication().getCurrentActivity();
Intent i = new Intent(currentActivity, SpeechActivationService.class);
i.putExtra(ACTIVATION_STOP_INTENT_KEY, true);
PendingIntent resultPendingIntent = PendingIntent.getActivity(currentActivity, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action action = new NotificationCompat.Action(R.drawable.ic_mic_off, "Deactivate", resultPendingIntent);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_mic)
.setTicker("TickerSample")
.setWhen(System.currentTimeMillis())
.setContentTitle("My App Voice Control")
.setContentText("Voice Control is Activated")
.addAction(action)
.build();
return notification;
}
It is supposed to make a notification which stays active for as long as the service is active. The notification has a DEACTIVATE Button, which can send an Intent, wrapped in a Pending Intent (whatever the difference is?!). It seems Intents are the only form of Action a notification can take for handling Button clicks, so I can't just do
stopService(new Intent(this, SpeechActivationService.class));
on that DEACTIVATE. But with my code onStartCommand() in SpeechActivationService never gets called when I click on DEACTIVATE. And Services don't inherit an onNewIntent() method. So what method gets called when I send this intent by pressing DEACTIVATE?
So what method gets called when I send this intent by pressing DEACTIVATE?
Nothing will. You are attempting to use a getActivity() PendingIntent with an Intent that points to a service. This will not work, and you should be getting messages in LogCat to that effect.
If you change getActivity() to getService(), then onStartCommand() of your service should be called.
Pending intents is ment to be used for controlling stuff outide of your app (system features use those). For stopping service create BroadcastReceiver, which will receive pending intent (PendingIntent.getBroadcast()), which, in turn, will stop your Service

Make a server call when GCM notification Dismiss from notification Tray

I have to make a server call when i dismiss the notification (simply slide it) from my android application, Which event i have to call or what i have to include when in am building the notification ?
I think Notification.deleteIntent is what you are looking for. The doc says:
The intent to execute when the notification is explicitly dismissed by the user, either with the "Clear All" button or by swiping it away individually. This probably shouldn't be launching an activity since several of those will be sent at the same time.
DeleteIntent:
DeleteIntent is a PendingIntent object that can be associated with a notification and gets fired when the notification gets deleted, ether by :
User specific action
User Delete all the notifications.
You can set the Pending Intent to a broadcast Receiver and then perform any action you want.
Intent intent = new Intent(this, MyBroadcastReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), 0, intent, 0);
Builder builder = new Notification.Builder(this):
..... code for your notification
builder.setDeleteIntent(pendingIntent);
MyBroadcastReceiver
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
.... code to handle cancel
}
}

Send broadcast on notification click

I have an application which is basically a webview and GCM notifications. I want to achieve the following thing: If the user is in the app and receives a notification, when he clicks the notification I want the webview to load the url provided in the notification.
I'm trying to accomplish this by using broadcast receiver but it doesn't work.
I dynamically register the receiver in the MainActivity:
private void registerNotificationReceiver() {
final IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_LOAD_URL_FROM_NOTIFICATION);
Log.i(TAG, "registerNotificationReceiver()");
this.receiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "notification received");
}
};
super.registerReceiver(this.receiver, filter);
}
And in the GCM Listener I'm using PendingIntent.getBroadast():
final Intent broadcastIntent = new Intent(MainActivity.ACTION_LOAD_URL_FROM_NOTIFICATION);
PendingIntent intent = PendingIntent.getBroadcast(getApplicationContext(), 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(intent);
notification = notificationBuilder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, notification);
I don't understand why onReceive in the MainActivity class is not called. The message "notification received" is not displayed.
Can you help me? Thank you :)
I cannot find right now the reason but there's a security reason. Latest Android versions won't allow you to trigger a listener from "kind-of" remote process without it being explicit.
The intent you broadcast MUST be explicit for it to work. Explicit means that you have to explicitly call the component that will handle the intent (the receiver). So this receiver must be declared in its own class and in the manifest as a <receiver>.
Follow this guy's example in the section Explicit Broadcast Intents http://codetheory.in/android-broadcast-receivers/
and thy will be done.

How to detect if a notification has been dismissed?

Is there any way in Android to detect when a user swipes a notification to the left and deletes it? I'm using an alarmmanager to set a repeating alert and I need my repeating alert to stop when the notification is cancelled by the user. Here's my code:
Setting the repeating alert:
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, c.getTimeInMillis(), repeatFrequency, displayIntent);
My notification code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Get the notification ID.
int notifID = getIntent().getExtras().getInt("Reminder_Primary_Key");
//Get the name of the reminder.
String reminderName = getIntent().getExtras().getString("Reminder_Name");
//PendingIntent stores the Activity that should be launched when the user taps the notification.
Intent i = new Intent(this, ViewLocalRemindersDetail.class);
i.putExtra("NotifID", notifID);
i.putExtra("notification_tap", true);
//Add FLAG_ACTIVITY_NEW_TASK to stop the intent from being launched when the notification is triggered.
PendingIntent displayIntent = PendingIntent.getActivity(this, notifID, i, Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.flag_red_large, reminderName, System.currentTimeMillis());
CharSequence from = "Here's your reminder:";
CharSequence message = reminderName;
notif.setLatestEventInfo(this, from, message, displayIntent);
//Pause for 100ms, vibrate for 250ms, pause for 100ms, and vibrate for 500ms.
notif.defaults |= Notification.DEFAULT_SOUND;
notif.vibrate = new long[] { 100, 250, 100, 500 };
nm.notify(notifID, notif);
//Destroy the activity/notification.
finish();
}
I know I need to call alarmManager.cancel(displayIntent) in order to cancel my repeating alarm. However, I don't understand where to put this code. I need to cancel the repeating alert ONLY when the user has tapped on the notification or dismissed it. Thanks for your help!
I believe that Notification.deleteIntent is what you are looking for. The doc says:
The intent to execute when the notification is explicitly dismissed by the user, either with the "Clear All" button or by swiping it away individually. This probably shouldn't be launching an activity since several of those will be sent at the same time.
To all those future people out there -- you can register a broadcast receiver to listen for notification delete inents.
Create a new broadcast receiver:
public class NotificationBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null || !action.equals(Config.NotificationDeleteAction)) {
return;
}
// Do some sweet stuff
int x = 1;
}
}
Register the broadcast receiver within your application class:
"If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for most implicit broadcasts (broadcasts that do not target your app specifically)."
Android Documentation.
registerReceiver(
new NotificationBroadcastReceiver(),
new IntentFilter(Config.NotificationDeleteAction)
);
You probably noticed the static variable Config.NotificationDeleteAction. This is a unique string identifier for your notification. It typically follows the following {namespace}{actionName} convention:
you.application.namespace.NOTIFICATION_DELETE
Set the delete intent on your notification builder:
notificationBuilder
...
.setDeleteIntent(createDeleteIntent())
...
Where, createDeleteIntent is the following method:
private PendingIntent createDeleteIntent() {
Intent intent = new Intent();
intent.setAction(Config.NotificationDeleteAction);
return PendingIntent.getBroadcast(
context,
0,
intent,
PendingIntent.FLAG_ONE_SHOT
);
}
Your registered broadcast receiver should receive the intent when your notification is dismissed.
You can also use an Activity PendingIntent, which may be simpler to implement if you have an Activity that can handle the dismissal, because you don't have to create and configure a broadcast receiver.
public static final String DELETE_TAG = "DELETE_TAG";
private PendingIntent createDeleteIntent(Context context) {
Intent intent = new Intent(context, MyActivity.class);
intent.putExtra(DELETE_TAG, true);
return PendingIntent.getActivity(
context,
0,
intent,
PendingIntent.FLAG_ONE_SHOT
);
}
MyActivity would receive the intent in its onCreate(), and in this example, could look for the DELETE_TAG extra to recognize it.

Categories

Resources