I am reading a tutorial on pending intent and how it is used with notification manager.
In that page, the following code is mentioned :
Intent intent = new Intent(this, NotificationReceiverActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(this, 0, intent, 0);
Notification noti = new Notification.Builder(this)
.setContentTitle("New mail from " + "test#gmail.com")
.setContentText("Subject").setSmallIcon(R.drawable.icon)
.setContentIntent(pIntent)
.addAction(R.drawable.icon, "Call", pIntent)
.addAction(R.drawable.icon, "More", pIntent)
.addAction(R.drawable.icon, "And more", pIntent).build();
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// hide the notification after its selected
noti.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, noti);
I want to ask why the notification manager needs to be provided a pending intent (why does it need my app's identity to send an intent) ?
Why can't it be just given an intent ?
Edit : Please don't answer with the definition of pending intent. I know what a pending intent is. What I am interested in finding is why can't the notification just use a normal intent with some API like startActivity().
An Intent requires a context. If your application is not running then there is no context. Using a PendingIntent allows the system to invoke an intent with your application's permissions (context).
From http://www.simplecodestuffs.com/what-is-pending-intent-in-android/:
The reason it’s needed is
because an Intent must be created and launched from a valid Context in
your application, but there are certain cases where one is not
available at the time you want to run the action because you are
technically outside the application’s context (the two common examples
are launching an Activity from a Notification or a BroadcastReceiver.
Also see this StackOverflow answer.
Related
When app receives message from GCM, it shows notification.
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_event_white_24dp)
.setContentTitle("TheBriefPost")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
When I click on notification, app opens activity but not restarting. What is the problem? How to solve it?
The answer should be related to the flags of the Intent/Pending Intent
According to PendingIntent in Official Docs
In the Pending Intent you sent a flag PendingIntent.FLAG_UPDATE_CURRENT
Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this
new Intent.
I guess in your case you need to use PendingIntent.FLAG_CANCEL_CURRENT
Flag indicating that if the described PendingIntent already exists, the current one should be canceled before generating a new one.
Accodring to Activity in Official Docs
In the Activity you set the flag Intent.FLAG_ACTIVITY_SINGLE_TOP
If set, the activity will not be launched if it is already running at the top of the history stack.
I guess here you need to use Intent.FLAG_ACTIVITY_CLEAR_TASK
If set in an Intent passed to Context.startActivity(), this flag will cause any existing task that would be associated with the activity to be cleared before the activity is started.
app opens activity but not restarting
It should not be restarted. FLAG_ACTIVITY_SINGLE_TOP is "If set, the activity will not be launched if it is already running at the top of the history stack."
Why you want it restarted? To handle intent data? If so, implement onNewIntent() in your activity.
Please have a look at my Pending Intent code.
notificationIntent.putExtra("is_from_notification", true);
notificationIntent.putExtra("push_message_id", push_message_id);
notificationIntent.putExtra("open_target", open_target);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent contentIntent = PendingIntent.getActivity(context,notifyID, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification noti = new NotificationCompat.Builder(context)
.setSmallIcon(icon_small)
.setTicker(message)
.setLargeIcon(largeIcon)
.setWhen(System.currentTimeMillis())
.setContentTitle(title)
.setContentText(message)
.setContentIntent(contentIntent)
.setAutoCancel(true).build();
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notifyID, noti);
My Problem is that, where and how should I clear this pending intent. It stays as far as app is in recent tasks.
Just call notificationManager.cancel(notifyId);
Or
call notificationManager.cancelAll();
Hope , it helps.
To clear a pendingIntent use:
Edit:
PendingIntent.getActivity(context,notifyID, contentIntent, PendingIntent.FLAG_UPDATE_CURRENT).cancel();
Place this line somewhere in your code, where u want to cancel the pendingintent.
Note: The intent must have the same name and ID as your pendingIntent, in your case: notifyID and contentIntent
Note: A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.
cancel() - Cancel a currently active PendingIntent. Only the original application owning a PendingIntent can cancel it.
Should help u out
My Android application receives push notification with some text messages.If I tap a push it redirects me to desired activity with latest push message (intent message) but I want to show my desired activity with corresponding push messages.
For example If I receives 10 push notifications and I tap 3rd notification, my code redirects me to the specified activity with 10th push notification's message, but I want to show 3rd intent push notification's message.
I know PendingIntent.FLAG_UPDATE_CURRENT replace the intent message, how can I redirect with corresponding message instead last message?
I have tried the following:
Intent intent = new Intent(this, TestActivity2.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra("uid", uid);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,
intent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
getApplicationContext());
Notification notification = mBuilder
.setSmallIcon(R.drawable.ic_launcher)
.setTicker(textMsg)
.setWhen(0)
.setAutoCancel(true)
.setContentTitle(textMsg)
.setStyle(
new NotificationCompat.BigTextStyle().bigText(textMsg))
.setContentIntent(resultPendingIntent).setContentText(textMsg)
.build();
NotificationManager notificationManager = (NotificationManager) getApplicationContext()
.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify((int) System.currentTimeMillis(),
notification);
Use FLAG_ONE_SHOT instead and change the second parameter in getActivity which is set to 0. This answer will make it clear.
You should Change the pendingIntend's content for Different Messages.
Here is the snippet from PendingIntent document.
"A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it."
In simple words...try passing different id(Something like currentEpochTime) for each pendingIntent.
What is the difference between those two?
I want to use the startForeground method and cannot use it with NotificationManager..
Thanks
A Notification is a class that represents either a persistent icon that goes in the status bar and is accessible through the launcher, turning on or flashing LEDs on the device, or alerting the user by flashing the backlight, playing a sound, or vibrating.
The Notification Manager is the class that allows you to add notifications to the system,
startForeground is a method of the Serivce class. For example inside your Service class you can have something like this.
Intent notificationIntent = new Intent(this, ActivityMain.class);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_stat_play)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher))
.setTicker(getString(R.string.app_name))
.setWhen(System.currentTimeMillis())
.setOngoing(true)
.setContentTitle(getString(R.string.app_name))
.setContentText(someText);
Notification notification = builder.build();
startForeground(1, notification);
A Notification is a description of what you want to occur to alert the user about something -- what icon goes in the status bar, what ringtone to play, etc.
NotificationManager is a system service that can show a Notification.
I want to use the startForeground methode and cannot use it with NotificationManager
Correct. Create a Notification using Notification.Builder (or NotificationCompat.Builder). See this project for an example of using startForeground().
I have made an app that sets notifications in the drop-down status bar of Android phones. However, there is a bug in my code (sometimes the notifications are set, sometimes they are not). I want to be able TO CHECK (in the code) IF THE NOTIFICATION IS VISIBLE TO THE USER. (i.e. can the user see the notification in the status bar?).
How can I do this? (Thanks in advance).
Sample code is greatly appreciated.
I want to be able TO CHECK (in the code) IF THE NOTIFICATION IS VISIBLE TO THE USER. (i.e. can the user see
the notification in the status bar?).
How can I do this?
You can't, sorry. Update: Now possible with Android 4.3+ http://developer.android.com/reference/android/service/notification/NotificationListenerService.html#getActiveNotifications()
However, you can always simply cancel() it -- canceling a Notification that is not on-screen is perfectly fine. Conversely, you can always safely call notify() again for the same Notification, and it too will not cause a problem if the Notification is already on-screen.
EDIT:
NotificationManager.getActiveNotifications() was added in API 23 if you don't want to use the NotificationListenerService
Just to put all together. This is how it works
To build a notification,
Notification n = new Notification.Builder(MyService.this)
.setContentTitle("Notification Title")
.setContentText("Notification Message")
.setSmallIcon(R.drawable.myicon).build();
To make a notification sound call setSound() of Notification,
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Notification n = new Notification.Builder(MyService.this)
.setContentTitle("Notification Title")
.setContentText("Notification Message")
.setSound(alarmSound)
.setSmallIcon(R.drawable.myicon).build();
To cancel the notification after user selected and launched the receiver Intent, call setAutoCancel(),
Notification n = new Notification.Builder(MyService.this)
.setContentTitle("Notification Title")
.setContentText("Notification Message")
.setSound(alarmSound)
.setAutoCancel(true)
.setSmallIcon(R.drawable.myicon).build();
To make sound/vibrate only once for a particular notification use Notification.FLAG_ONLY_ALERT_ONCE. With this flag, your notification will make sound only once till it gets cancelled and you can call notify() as many times as you want with the notification id. Note that if you call cancel() or if user cancelled the notification or auto cancelled, notify() call will make the notification sound again.
n.flags |= Notification.FLAG_ONLY_ALERT_ONCE; // Dont vibrate or make notification sound
Finally to put the notification on notification panel,
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(notification_id, n);
Note that notification_id here is important if you want to use the notification effectively.( to keep single sound/vibration for a notification or to cancel a specific notification).
To cancel a particular notification,
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.cancel(notification_id);
You can cancel() a notification even if it doesn't exist or you can call notify() as many times as you want with the same id. Note that calling notify with different id will create new notifications.
So, regardless of whether the notification exist or not, if you call notify() again with the correct notification_id with the Notification.FLAG_ONLY_ALERT_ONCE flag set, you can keep your notification alive without disturbing the user with repeated sounds.
You need to set an id for each notification you make.
so you make a notification ..
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, notId + selectedPosition, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, rightNow.getTimeInMillis() - offset, pendingIntent);
Notification notification = new Notification(R.drawable.icon, "TVGuide Υπενθύμιση", System.currentTimeMillis());
NotificationManager manger = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
notification.setLatestEventInfo(context, "Κανάλι: " + b.getString("channel"), "Εκπομπή: " + showname, pendingIntent);
manger.notify(notId, notification);
to clear it..
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,notId, intent, 0);
pendingIntent.cancel();
and to check if active..( existAlarm returns null if no pending intent available)
public PendingIntent existAlarm(int id) {
Intent intent = new Intent(this, alarmreceiver.class);
intent.setAction(Intent.ACTION_VIEW);
PendingIntent test = PendingIntent.getBroadcast(this, id + selectedPosition, intent, PendingIntent.FLAG_NO_CREATE);
return test;
}
So everything comes down to initialize an ID for each notification and how you make it unique.
A new method is introduced to the NotificationManager class in API 23:
public StatusBarNotification[] getActiveNotifications()
There exists a flag for that.
Notification notification = new Notification(icon, tickerText, when);
notification.flags |= Notification.FLAG_ONLY_ALERT_ONCE;
FLAG_ONLY_ALERT_ONCE:
...should be set if you want the sound and/or vibration play each time the notification is sent, even if it has not been canceled before that.
Although, the notification will blink when it is sent again, but there won't be any sound or vibration.
It's possible now to check notifications outstanding in android 4.3 upwards
See here:
http://developer.android.com/reference/android/service/notification/NotificationListenerService.html#getActiveNotifications()
It seems that from Android M (API 23) it is possible to get your process like that, without using NotificationListenerService nor requiring additional permissions:
notificationManager.getActiveNotifications()
As of Android Marshmallow (API 23), you can recover a list of active notifications posted by your app. This NotificationManager method is getActiveNotifications(). More info here: https://developer.android.com/reference/android/app/NotificationManager.html#getActiveNotifications()