I'm building an app that shows a notification with two options "Dim" and "Full" when a BroadcastReceiver is called. Each of this buttons broadcasts an action.
So far everything is possible to do, right?
The problem is that the buttons shown on the notification do not respond to the tap but the whole notification does (if I click on the icon or text instead of the button).
I have this function to build the notification:
private Notification buildReleaseNotification(NotificationManager nManager, Context context) {
Notification.Builder builder = new Builder(context);
builder.addAction(R.drawable.rate_star_big_half_holo_dark, "Dim", buildPendingIntent(context, DIM));
builder.addAction(R.drawable.rate_star_big_on_holo_dark, "Full", buildPendingIntent(context, FULL));
builder.setContentTitle("Car notification");
builder.setContentText("Freed");
builder.setSmallIcon(R.drawable.ic_launcher);
builder.setOngoing(true);
Notification notification = builder.build();
return notification;
}
and it is called when receiving a broadcast:
public void onReceive(Context context, Intent intent) {
NotificationManager nManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification noty = null;
noty = buildReleaseNotification(context);
startService(context, RELEASE);
if (noty != null) {
nManager.notify(ChangeLockService.GLOBAL_TAG, ID, noty);
}
}
------ edit
Just noticed that the following function returns null... So, how can I build a pending intent to perform a broadcast?
private PendingIntent buildPendingIntent(Context context, String action) {
Intent i = new Intent(action);
PendingIntent pi = PendingIntent.getBroadcast(context, ID, i, Intent.FLAG_RECEIVER_REPLACE_PENDING);
return pi;
}
When creating the intent through
PendingIntent pi = PendingIntent.getBroadcast(context, ID, i, Intent.FLAG_RECEIVER_REPLACE_PENDING);
caused it to return null.
According to the documentation, I understood that the flag Intent.FLAG_RECEIVER_REPLACE_PENDING would replace any pending intent that already existed for that button. If I send no flags then everything works fine:
PendingIntent pi = PendingIntent.getBroadcast(context, ID, i, 0);
Related
When users click the icon of my app on the Notification bar, users will be redirected to my app.
Can anyone provide sample code? How to subscribe to the click event, and the redirection.
Update
My application might be using some services that cause the display of icon on Notification bar.
My application is calling SetForeground, not getBroadcast().
Update 2
how can I redirect users to the last Activity rather than the hard-code activity? For example, the last Activity might be different when users navigate to different activity.
Notification click event in xamarin forms
It's a sample from my app, it works. I think you can do somthing similar.
public class AlarmReceiver extends BroadcastReceiver {
public final static String NOTIF_TEXT = AlarmSetActivity.class.getPackage() + ".NOTIF_TEXT";
private String notifText;
#Override
public void onReceive(Context context, Intent intent) {
notifText = intent.getExtras().getString(NOTIF_TEXT);
//().getExtras().getString(NOTE_BODY);
Toast.makeText(context, "Notification from " + R.string.app_name,
Toast.LENGTH_LONG).show();
buildNotification(context);
}
private void buildNotification(Context context) {
NotificationManager notificationManager = (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = "default_channel_id";
String channelDescription = "Default Channel";
Notification.Builder builder = new Notification.Builder(context);
Intent intent = new Intent(context, **EditorActivity.class**);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
intent, 0);
builder.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(context.getString(R.string.notificTitle)).setContentText(notifText)
.setContentInfo(context.getString(R.string.notificInfo)).setTicker(context.getString(R.string.notifTicker))
.setLights(0xFFFF0000, 500, 500)
//.setChannelId(id)
.setContentIntent(pendingIntent).setAutoCancel(true);
Notification notification = builder.build();
//notification.so
notificationManager.notify(2, notification);
}
}
And:
private void setAlarm(Calendar targetCal) {
mTimeTextView.setText(R.string.alarm_on);
mTimeTextView.append(String.valueOf(targetCal.getTime()));
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
intent.putExtra(AlarmReceiver.NOTIF_TEXT,notificationText);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
getApplicationContext(), RQS_TIME, intent, 0);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, targetCal.getTimeInMillis(),
pendingIntent);
}
When my application is launched, it performs an API call and then schedules notifications based on the results. This amounts to around ~10 notifications being scheduled. There seems to be an issue with the timestamp displayed on the actual notification being incorrect.
Since I am creating these notifications and then scheduling an alarm with an AlarmManager, the default time present on the notification will be the time at which the notification is created (System.currentTimeMillis()).
I've tried to use the .setWhen() method on my Notification.Builder to set it to the time I am using to schedule the previously mentioned alarm. This is a little better, however, because notifications are not guaranteed to be delivered at the exact time specified, I often get notifications a few minutes in the past.
Additionally, I tried to manually override the when field on the notification in my BroadcastReceiver, right before .notify() is actually called:
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification_id";
public static String NOTIFICATION = "notification";
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = intent.getParcelableExtra(NOTIFICATION);
notification.when = System.currentTimeMillis();
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
notificationManager.notify(id, notification);
}
}
However, in the above scenario, it seems that .when is ignored.
Frankly, I am simply looking for a way to have the timestamp displayed on the notification be the time at which it is actually displayed.
I would suggest passing in your notification's information as extras then building the notification inside of the BroadcastReceiver. This will build the notification just before it is issued, so it will have the same time your AlarmManager triggers the BroadcastReceiver.
From wherever you're scheduling the notification:
private void scheduleNotification(){
// Create an intent to the broadcast receiver you will send the notification from
Intent notificationIntent = new Intent(this, SendNotification.class);
// Pass your extra information in
notificationIntent.putExtra("notification_extra", "any extra information to pass in");
int requestCode = 1;
// Create a pending intent to handle the broadcast intent
PendingIntent alarmIntent = PendingIntent
.getBroadcast(this, requestCode, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
// Set your notification's trigger time
Calendar alarmStart = Calendar.getInstance();
alarmStart.setTimeInMillis(System.currentTimeMillis());
alarmStart.set(Calendar.HOUR_OF_DAY, 6); // This example is set to approximately 6am
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
// Set the alarm with the pending intent
// be sure to use set, setExact, setRepeating, & setInexactRepeating
// as well as RTC_WAKEUP, ELAPSED_REALTIME_WAKEUP, etc.
// where appropriate
alarmManager.set(AlarmManager.RTC_WAKEUP, alarmStart.getTimeInMillis(), alarmIntent);
}
Then, inside your BroadcastReceiver's onReceive:
String notificationExtra = null;
// Retrieve your extra data
if(intent.hasExtra("notification_extra")){
notificationExtra = intent.getStringExtra("notification_extra");
}
//Build the notification
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
mBuilder.setSmallIcon(notificationIcon)
.setContentTitle(notificationTitle)
.setContentText(notificationMessage)
.setAutoCancel(true); // Use AutoCancel true to dismiss the notification when selected
// Check if notificationExtra has a value
if(notificationExtra != null){
// Use the value to build onto the notification
}
//Define the notification's action
Intent resultIntent = new Intent(context, MainActivity.class); // This example opens MainActivity when clicked
int requestCode = 0;
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
context,
requestCode,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
//Set notification's click behavior
mBuilder.setContentIntent(resultPendingIntent);
// Sets an ID for the notification
int mNotificationId = 1;
// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Builds the notification and issues it.
mNotifyMgr.notify(mNotificationId, mBuilder.build());
I have also been struggling with this for a bit, but your question actually brought me to the best answer. I checked out setWhen() and it seems like now this just works fine (checked with API lvl 30 & 31). As this post is a few years old, maybe this issue was fixed in the meantime. So here's how I did it in Kotlin:
class NotificationPublisher : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val notification = intent.getParcelableExtra<Notification>(NOTIFICATION)
notification?.`when` = System.currentTimeMillis() // overwriting the creation time to show the current trigger time when the notification is shown
val postId = intent.getIntExtra(NOTIFICATION_ID, 0)
notificationManager.notify(postId, notification)
}
Your NotificationPublisher's onReceive() method will be invoked only when scheduled alarm triggers as specified time. When you crate a notification from onReceive() method, it will definitely show the current time. No need to require to use .when or .setWhen() method.
Try this one:
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification_id";
public static String NOTIFICATION = "notification";
public void onReceive(Context context, Intent intent) {
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
// Notification
Notification notification = new Notification.Builder(context)
.setContentTitle("This is notification title")
.setContentText("This is notification text")
.setSmallIcon(R.mipmap.ic_launcher).build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Notification Manager
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager .notify(id, notification);
}
}
If you want to redirect to an activity when click on Notification, then you can use PendingIntent and set it to your Notification.
public class NotificationPublisher extends BroadcastReceiver {
public static String NOTIFICATION_ID = "notification_id";
public static String NOTIFICATION = "notification";
public void onReceive(Context context, Intent intent) {
int id = intent.getIntExtra(NOTIFICATION_ID, 0);
Intent intent = new Intent(context, YourTargetActivity.class);
intent.putExtra("KEY_ID", id); // Pass extra values if needed
PendingIntent pI = PendingIntent.getActivity(context, id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
// Notification
Notification notification = new Notification.Builder(context)
.setContentTitle("This is notification title")
.setContentText("This is notification text")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pI).build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
// Notification Manager
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager .notify(id, notification);
}
}
Hope this will help~
I have been searching for a few hours, but could not find any solution to my problem. Does anyone know how to make heads-up notification buttons call a broadcast? My code:
Alarm Receiver Notification Builder:
NotificationCompat.Builder builder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.alarmicon)
.setContentTitle("Alarm for " + timeString)
.setContentText(MainActivity.alarmLabel.getText().toString())
.setDefaults(Notification.DEFAULT_ALL) // must requires VIBRATE permission
.setPriority(NotificationCompat.PRIORITY_HIGH); //must give priority to High, Max which will considered as heads-up notification
//set intents and pending intents to call service on click of "dismiss" action button of notification
Intent dismissIntent = new Intent(context, notificationButtonAction.class);
dismissIntent.setAction(DISMISS_ACTION);
PendingIntent piDismiss = PendingIntent.getBroadcast(context, 0, dismissIntent, 0);
builder.addAction(R.drawable.alarmoff, "Dismiss", piDismiss);
//set intents and pending intents to call service on click of "snooze" action button of notification
Intent snoozeIntent = new Intent(context, notificationButtonAction.class);
snoozeIntent.setAction(SNOOZE_ACTION);
PendingIntent piSnooze = PendingIntent.getBroadcast(context, 0, snoozeIntent, 0);
builder.addAction(R.drawable.snooze, "Snooze", piSnooze);
// Gets an instance of the NotificationManager service
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
//to post your notification to the notification bar with a id. If a notification with same id already exists, it will get replaced with updated information.
notificationManager.notify(0, builder.build());
notificationButtonAction:
public static class notificationButtonAction extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
System.out.println("notificationButtonAction Started");
String action = intent.getAction();
if (SNOOZE_ACTION.equals(action)) {
stopAlarm();
System.out.println("Alarm Snoozed");
MainActivity ma = new MainActivity();
ma.setAlarm(true);
}
else if (DISMISS_ACTION.equals(action)) {
stopAlarm();
System.out.println("Alarm Dismissed");
}
}
}
My print lines in notificationButtonAction do not print, not even the "notificationButtonAction Started."
I followed the tutorial from Brevity Software (http://www.brevitysoftware.com/blog/how-to-get-heads-up-notifications-in-android/), but their code didn't seem to work.
Any help is appreciated! Thanks!
Turns out, I didn't add the class to the manifest. My code was fine.
I have an notification in my app and this notification has button that was set using addAction()method. But every time that user click in the button of the notification the notification don't auto cancel unless that user clicked explicitly in the notification.
private static void notification(Context context, String title, String text, int id, Intent intent, int priority, boolean withSound) {
PendingIntent pendingIntent = PendingIntent.getActivity(context, Constants.REQUEST_CODE_NOTIFICATION, intent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context);
notificationBuilder.setSmallIcon(R.drawable.ic_stat_notify);
notificationBuilder.setContentTitle(title);
notificationBuilder.setContentText(text);
notificationBuilder.setColor(ContextCompat.getColor(context, R.color.bg_primary));
notificationBuilder.setAutoCancel(true);
notificationBuilder.setContentIntent(pendingIntent);
notificationBuilder.setPriority(priority);
if (Constants.NOTIFICATION_NEW_AD_BALANCE == id)
notificationBuilder.setTicker(text);
if (Constants.NOTIFICATION_DATE_TIME_SETTINGS == id)
notificationBuilder.addAction(0, context.getString(R.string.notification_device_time_settings), pendingIntent).setAutoCancel(true);
notificationBuilder.setStyle(new NotificationCompat.BigTextStyle().bigText(text));
if (withSound) {
Uri alarmSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notificationBuilder.setSound(alarmSound);
notificationBuilder.setVibrate(new long[]{500, 500});
} else {
notificationBuilder.setVibrate(new long[0]);
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(id, notificationBuilder.build());
}
To solve this problem I have to start my notification using the following pending intent:
pendingIntent = PendingIntent.getBroadcast(context, Constants.REQUEST_CODE_NOTIFICATION, intent, PendingIntent.FLAG_CANCEL_CURRENT);
After I have to implement a broadcastreceiver to be triggered when user perform the click on notification button how can you see below:
public class DateTimeSettingsBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
context.startActivity(new Intent(Settings.ACTION_DATE_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
NotificationBuilder.cancel(context, Constants.NOTIFICATION_DATE_TIME_SETTINGS);
}
}
This way the problem of notification not being dismissed after user perform click was solved.
What did you expect from setAutoCancel()? Reading the docs, it says
Setting this flag will make it so the notification is automatically canceled when the user clicks it in the panel.
It sounds like your code is working correctly. I believe you want the previous notification to dismiss when a new one is added? I can't remember for sure, but I think if you use the same id, it will replace the current one. Otherwise, I know you can cancel the notification with it's id:
notificationManager.cancel(id);
I'm using an android notification to alert the user once a service is finished (success or failure), and I want to delete local files once the process is done.
My problem is that in the event of failure - I want to let the user a "retry" option. and if he chooses not to retry and to dismiss the notification I want to delete local files saved for the process purposes (images...).
Is there a way to catch the notification's swipe-to-dismiss event?
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
}
}
A fully flushed out answer (with thanks to Mr. Me for the answer):
1) Create a receiver to handle the swipe-to-dismiss event:
public class NotificationDismissedReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getExtras().getInt("com.my.app.notificationId");
/* Your code to handle the event here */
}
}
2) Add an entry to your manifest:
<receiver
android:name="com.my.app.receiver.NotificationDismissedReceiver"
android:exported="false" >
</receiver>
3) Create the pending intent using a unique id for the pending intent (the notification id is used here) as without this the same extras will be reused for each dismissal event:
private PendingIntent createOnDismissedIntent(Context context, int notificationId) {
Intent intent = new Intent(context, NotificationDismissedReceiver.class);
intent.putExtra("com.my.app.notificationId", notificationId);
PendingIntent pendingIntent =
PendingIntent.getBroadcast(context.getApplicationContext(),
notificationId, intent, 0);
return pendingIntent;
}
4) Build your notification:
Notification notification = new NotificationCompat.Builder(context)
.setContentTitle("My App")
.setContentText("hello world")
.setWhen(notificationTime)
.setDeleteIntent(createOnDismissedIntent(context, notificationId))
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, notification);
Another Idea:
if you create a notification normally you also need the actions one, two or 3 of them. I've created a "NotifyManager" it creates all notifications i need and also receive all Intent calls.
So i can manage all the actions AND also the catch the dismiss event at ONE place.
public class NotifyPerformService extends IntentService {
#Inject NotificationManager notificationManager;
public NotifyPerformService() {
super("NotifyService");
...//some Dagger stuff
}
#Override
public void onHandleIntent(Intent intent) {
notificationManager.performNotifyCall(intent);
}
to create the deleteIntent use this (in the NotificationManager):
private PendingIntent createOnDismissedIntent(Context context) {
Intent intent = new Intent(context, NotifyPerformMailService.class).setAction("ACTION_NOTIFY_DELETED");
PendingIntent pendingIntent = PendingIntent.getService(context, SOME_NOTIFY_DELETED_ID, intent, 0);
return pendingIntent;
}
and THAT i use to set the delete Intent like this (in the NotificationManager):
private NotificationCompat.Builder setNotificationStandardValues(Context context, long when){
String subText = "some string";
NotificationCompat.Builder builder = new NotificationCompat.Builder(context.getApplicationContext());
builder
.setLights(ContextUtils.getResourceColor(R.color.primary) , 1800, 3500) //Set the argb value that you would like the LED on the device to blink, as well as the rate
.setAutoCancel(true) //Setting this flag will make it so the notification is automatically canceled when the user clicks it in the panel.
.setWhen(when) //Set the time that the event occurred. Notifications in the panel are sorted by this time.
.setVibrate(new long[]{1000, 1000}) //Set the vibration pattern to use.
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
.setSmallIcon(R.drawable.ic_white_24dp)
.setGroup(NOTIFY_GROUP)
.setContentInfo(subText)
.setDeleteIntent(createOnDismissedIntent(context))
;
return builder;
}
and finally in the same NotificationManager is the perform function:
public void performNotifyCall(Intent intent) {
String action = intent.getAction();
boolean success = false;
if(action.equals(ACTION_DELETE)) {
success = delete(...);
}
if(action.equals(ACTION_SHOW)) {
success = showDetails(...);
}
if(action.equals("ACTION_NOTIFY_DELETED")) {
success = true;
}
if(success == false){
return;
}
//some cleaning stuff
}