I have defined a service that issues notifications when an event occurs. I add the notification id as an extra in the intent so that, when the user opens the app through the notification, i can retrieve the id in the activity and cancel the specific notification.
The problem is that, if there are multiple notifications visible in the drawer at any time, all of them end up with the same Extra value. This is because of the FLAG_UPDATE_CURRENT behaviour. It will update the extras of any existing matching Intents with the new Extra. So now i cannot retrieve the correct notification id to cancel it.
Is there a way to work around this so that the previous Intents retain their Extra value.
According to the doc :
public static final int FLAG_UPDATE_CURRENT
Added in API level 3
Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent.
Service onStartCommand() :
int notificationId = getId();
Intent contentIntent = new Intent(this,MainActivity.class);
contentIntent.putExtra(MainActivity.KEY_NOTIFICATION_ID, notificationId);
PendingIntent contentPendingIntent = PendingIntent.getActivity(this, REQUEST_CODE_OPEN_APP, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(MyApplication.getContext())
.setContentTitle("title")
.setContentText("text")
.setSmallIcon(R.drawable.icon)
.setContentIntent(contentPendingIntent);
notificationManager.notify(notificationId,notificationBuilder.build());
In the Activity's onCreate() :
Bundle bundle = getIntent().getExtras();
if(bundle != null){
int notificationId = bundle.getInt(KEY_NOTIFICATION_ID);
if(notificationId != 0){
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(notificationId);
}
}
One workaround is to have a unique request code for every PendingIntent. You can reuse the notification id itself. We can set an action for the intent as well, so that the activity can recognize the intent. So change the code to :
Service onStartCommand() :
public static final String ACTION_NOTIFIED = "ACTION_NOTIFIED"; //added
int notificationId = getId();
Intent contentIntent = new Intent(this,MainActivity.class);
contentIntent.putExtra(MainActivity.KEY_NOTIFICATION_ID, notificationId);
contentIntent.setAction(ACTION_NOTIFIED);//added
PendingIntent contentPendingIntent = PendingIntent.getActivity(this, notificationId, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT);//changed
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(MyApplication.getContext())
.setContentTitle("title")
.setContentText("text")
.setSmallIcon(R.drawable.icon)
.setContentIntent(contentPendingIntent);
notificationManager.notify(notificationId,notificationBuilder.build());
In the Activity's onCreate() :
if(getIntent().getAction().equals(AppService.ACTION_NOTIFIED)){//added
Bundle bundle = getIntent().getExtras();
if(bundle != null){
int notificationId = bundle.getInt(KEY_NOTIFICATION_ID);
if(notificationId != 0){
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(notificationId);
}
}
}//added
Related
I am trying to make notification with remove button, notifications are stored in SQLite DB and after the press, I want to remove "record" by id. Firstly I get a notification, store it to db , store unique id and pass it to a method which creates a notification. It gets fine in the method.
public static String CUSTOM_ACTION = "com.example.app.Services.REMOVE";
Intent snoozeIntent = new Intent(this, MyBroadcastReceiver.class);
snoozeIntent.setAction(CUSTOM_ACTION);
snoozeIntent.putExtra("NOT_WORKING", String.valueOf(id));
PendingIntent snoozePendingIntent =
PendingIntent.getBroadcast(this, 0, snoozeIntent, 0);
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT);
String channelId = getString(R.string.default_notification_channel_id);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setDefaults(Notification.DEFAULT_ALL)
.setSmallIcon(R.drawable.ic_stat_bell)
.setContentTitle("Loggly")
.setContentText(messageBody)
.setAutoCancel(true)
.setContentIntent(pendingIntent)
.addAction(R.drawable.ic_delete_forever_black_24dp, "Remove", snoozePendingIntent);
then I have a broadcast receiver for handling data from notification. Here is how it looks in my manifest file.
<receiver android:name=".MyBroadcastReceiver" android:exported="false">
<intent-filter>
<action android:name="com.example.app.Services.REMOVE"/>
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</receiver>
And here is the broadcast receiver the value which I got from extras is always null ... I have been trying to find a solution, but with no result.
public class MyBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Bundle extras = intent.getExtras();
String id;
if (extras != null) {
id = extras.getString("NOT_WORKING");
String ns = Context.NOTIFICATION_SERVICE;
NotificationManager notificationManager = (NotificationManager) context.getSystemService(ns);
if (notificationManager != null) {
notificationManager.cancel(0);
}
Intent inten = new Intent(context, RemoveService.class);
inten.putExtra("NOT_WORKING", id);
context.startService(inten);
}
}
}
Finally, I am starting intent service, which should delete the "record" from the database, but when the broadcast receiver does not receive id it can't do anything.
I just created a sample notification on my side and the problem is the way you are creating the pendingIntent. Just add the proper flag to the pendingIntent parameter and it will work fine.
PendingIntent snoozePendingIntent = PendingIntent.getBroadcast(this, 0, snoozeIntent, PendingIntent.FLAG_UPDATE_CURRENT);
You can use FLAG_ONE_SHOT as well. If it satisfies your use case. You can go through different flags which can be used in PendingIntent
I have working notifications(with service) on my app and it works ok when the app is in onPause, but when I close the app, the notification text/title is null and the notification appear, but with no title/body.
Here is the Notification builder code:
public int onStartCommand(Intent intent, int flag, int startId)
{
super.onStartCommand(intent , flag, startId);
String titleS = Utils.Title;
String bodyS = Utils.Body;
Context context = this.getApplicationContext();
notificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
Intent mIntent = new Intent(this, MainActivity.class);
pendingIntent = PendingIntent.getActivity(context, 0, mIntent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentTitle(titleS);
builder.setContentText(bodyS);
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
return START_NOT_STICKY;
}
It is obvious that the titleS and bodyS is null when the app is closed and that is why the notification appear without any information.
My question is what is the correct way to save/display this data into notification when my app is closed ?
I set my alarmintent putExtra (forgot completly about this)
alarmIntent.putExtra("title" , Title);
alarmIntent.putExtra("body" , Body);
And then in my Broadcast reciever, onReceive I get those String with:
String titleS = intent.getStringExtra("title");
String bodyS = intent.getStringExtra("body");
It`s working fine now.
I've searched for about hour to find some solution how to send extras to activity when user clicks in notification box but everything I've found didn't work for me.
I need to pass event ID to activity where I show user info about this event.
I've used setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), setAction("Action"), PendingIntent.FLAG_UPDATE_CURRENT and combination of all of these solution but neither didn't work.
That's my code:
Notification.Builder notiBuilder = new Notification.Builder(context);
notiBuilder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.logo));
notiBuilder.setSmallIcon(R.drawable.logo);
notiBuilder.setContentTitle(context.getString(R.string.eventNitificationTitle));
notiBuilder.setContentText(obj.getString("nazwa") + " " + obj.getString("data"));
Intent eventIntenet = new Intent(context, EventActivity.class);
eventIntenet.setAction("Action_"+id);
eventIntenet.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
eventIntenet.putExtra("eventID", id);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, eventIntenet, PendingIntent.FLAG_UPDATE_CURRENT);
eventIntenet = null;
notiBuilder.setContentIntent(pIntent);
pIntent = null;
NotificationManager notiManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
notiManager.notify(Integer.parseInt(id), notiBuilder.build());
} else {
notiManager.notify(Integer.parseInt(id), notiBuilder.getNotification());
}
And way to get my Int:
this.eventID = getIntent().getIntExtra("eventID", -1);
Everytime when I click in notification, I'm moving to activity but getExtra returns -1.
You can try something along these lines:
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(ChatService.this).setSmallIcon(R.drawable.app_icon)
.setContentTitle(senderName)
.setContentText("Notification Text Here");
mBuilder.setAutoCancel(true);
Intent resultIntent = new Intent(MyService.this, TargetActivity.class);
resultIntent.putExtra("eventID", id);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(MyService.this);
stackBuilder.addParentStack(TargetActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(id, mBuilder.build());
If your app is already running and your EventActivity is already on the top of the stack, this code:
this.eventID = getIntent().getIntExtra("eventID", -1);
will always use the Intent that EventActivity was started with the first time.
You should override onNewIntent() and get the "extra" from the Intent that is passed as an argument to that method.
For my push notifications, I am sending some data which I will then choose which fragment I want to open. I am trying to do this by adding an Intent Extra to the Pending Intent but whenever I try to use this extra in the next Activity, it returns NULL.
I have read here I need to change the PendingActivity flag, but I have changed it a few times and made no difference. I must be making a silly mistake somewhere.
private void sendNotification(String title, String msg, String fragment) {
mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.logo_m_white)
// .setLargeIcon(((BitmapDrawable) getResources().getDrawable(R.drawable.icon_filled_m)).getBitmap())
.setContentTitle(title)
.setContentText(msg)
.setSound(Uri.EMPTY)
.setPriority(1)
.setLights(Color.RED, 300, 5000)
.setAutoCancel(true);
Intent intent = new Intent(this, LoginActivity.class);
intent.putExtra("fragment", fragment);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(this,0,intent,PendingIntent.FLAG_CANCEL_CURRENT);
mBuilder.setContentIntent(pi);
mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
}
fetch extras in your LoginActivity using intent extras as
Intent intent = getIntent() ;
if(intent != null){
String fragment = intent.getStringExtra("fragment"); //if 'fragment' type is String (see other methods for appropriate type)
}
I have implemented push notifications for my android app .I am able to show multiple notification in notification bar but only one notification work at a time.If I click on any notification it will start the intended activity and that particular notification will disappear from notification bar but other notification for same app will become dead.Nothing happens when I click on rest of the notification.My code for handling notification is following:
private void sendNotification(String msg, String msgId, int notificationId,
int type) {
// SharedPreferences prefs = getSharedPreferences(
// Utility.PREFS_NAME, MODE_PRIVATE);
mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = null;
Bundle bundle = new Bundle();
if (type == 1) {
intent = new Intent(this, Activity_Received.class);
// bundle.putString("greeting", msg);
bundle.putString(Utility.KEY_MESSAGE_DELIVERY_ID, msgId);
} else if (type == 2) {
intent = new Intent(this, Activity_Birth.class);
} else {
return;
}
bundle.putBoolean(Utility.KEY_IS_NOTIFICATION, true);
intent.putExtras(bundle);
PendingIntent contentIntent;
// The stack builder object will contain an artificial back stack
// for
// the
// started Activity.
// This ensures that navigating backward from the Activity leads out
// of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
if (type == 1) {
stackBuilder.addParentStack(Activity_Received.class);
} else {
stackBuilder.addParentStack(Activity_Birth.class);
}
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(intent);
contentIntent = stackBuilder
.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT
| PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("WishnGreet")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg)
.setAutoCancel(true)
.setSound(
RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(notificationId, mBuilder.build());
}
Please advise what do I need to change in above code so that I can click on every notification that I receive for my application and start the intended activity.
Pass a different notificationId for each different notification you want to have in the method: sendNotification(String msg, String msgId, int notificationId, int type)
I have wrote the following method which is working in case of multiple notifications.
private void pushNotification(String msg, String msgId, int notificationId,
int type) {
mNotificationManager = (NotificationManager) this
.getSystemService(Context.NOTIFICATION_SERVICE);
Bundle bundle = new Bundle();
bundle.putString(Utility.KEY_MESSAGE_DELIVERY_ID, msgId);
bundle.putBoolean(Utility.KEY_IS_NOTIFICATION, true);
Intent intent = new Intent(this, Activity_ReceivedGreeting.class);
intent.putExtras(bundle);
PendingIntent contentIntent = PendingIntent.getActivity(
getApplicationContext(), notificationId, intent,
PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("WishnGreet")
.setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
.setContentText(msg)
.setAutoCancel(true)
.setSound(
RingtoneManager
.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION));
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(notificationId, mBuilder.build());
}
The key was to remove the FLAGS on pending intent.