Android BroadcastReceiver firing with delay upon notification action click - android

I am trying to run a Retry routine upon notification action click, for this, I have created a BroadcastReceiver and also registered it in the AndroidManifest file.
While creating the notification with action I am using PendingIntent and setting that pending intent with the notification action.
When the app is running or in the background (not removed from the recent apps list) then the broadcast receiver is received instantly upon clicking the notification action. But after killing the app (removing it from the recent app list) the broadcast receiver takes some to fire.
Below are the code snippets for different components.
AndroidManifest file
<receiver android:name=".Receiver.RetryStatusBroadcastReceiver" android:enabled="true" android:exported="false"/>
Broadcast receiver
public class RetryStatusBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
}
}
Notification firing code
Intent retryIntent = new Intent(this, RetryStatusBroadcastReceiver.class);
PendingIntent retryPendingIntent = PendingIntent.getBroadcast(this.getApplicationContext(), uniqueId + 1, retryIntent, 0);
NotificationCompat.Action retryAction = new NotificationCompat.Action(R.drawable.ic_retry, "Retry", retryPendingIntent);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, getString(R.string.background_syncing_notification_channel_id))
.setSmallIcon(R.drawable.app_logo)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_ALL)
.setContentTitle(notificationTitle)
.setContentText(notificationMessage)
.setStyle(new NotificationCompat.BigTextStyle().bigText(notificationMessage))
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.addAction(retryAction);
Intent intent = new Intent(this, HomeActivity.class);
PendingIntent activityPendingIntent = PendingIntent.getActivity(this, uniqueId, intent, PendingIntent.FLAG_ONE_SHOT);
notificationBuilder.setContentIntent(activityPendingIntent);
notificationBuilder.setAutoCancel(true);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (notificationManager != null) {
notificationManager.notify(uniqueId, notificationBuilder.build());
}
I have also tried extending my BroadcastReceiver from WakefulBroadcastReceiver but the result is the same.
I have also tried removing android:enabled and android:exported tags but nothing seems to work here.

Related

How to create a notification when my app receive a broadcast message

My app simply receives a broadcast from another app. I am new to broadcast receiver so I am facing problems.
I want that when my app receive a broadcast message then in the notification panel a notification appears.
I tried a lot but find nothing on the internet.
I tried youtube videos and StackOverflow but I found nothing.
public class MyReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "EBR triggered", Toast.LENGTH_LONG).show();
// The following code doesn't work. I copy this from StackOverflow//
PendingIntent pendingIntent = PendingIntent.getActivity(context, 1, intent, 0);
Notification.Builder builder = new Notification.Builder(context);
builder.setAutoCancel(false);
builder.setTicker("Ticker text");
builder.setContentTitle("Content of Notification");
builder.setContentText("You have a new message");
builder.setSmallIcon(R.mipmap.ic_launcher);
builder.setContentIntent(pendingIntent);
builder.setOngoing(true);
builder.setSubText("This is subtext...");
builder.setNumber(100);
builder.build();
// add as notification
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(0, builder.build());
}
}
No errors and I was expected that there will be a notification icon appears when broadcast receives but nothing happened.
Here is a simple example of broadcast receiving.
App 1 (sender)
Intent intent = new Intent("MY_NOTIFICATION");
intent.setComponent(
new ComponentName("com.example.stackoverflow", "com.example.stackoverflow.MyReceiver")
);
intent.putExtra("data","Notice me senpai!");
sendBroadcast(intent);
App 2 (receiver)
AndroidManifest.xml:
...
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="MY_NOTIFICATION"/>
</intent-filter>
</receiver>
MyReceiver.java:
public void onReceive(Context context, Intent intent) {
String data = intent.getStringExtra("data");
Toast.makeText(context, data, Toast.LENGTH_LONG).show();
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
NotificationChannel channel = new NotificationChannel("CHANNEL_ID", "name", NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("description");
notificationManager.createNotificationChannel(channel);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "CHANNEL_ID")
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("textTitle")
.setContentText(data)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
notificationManager.notify(1, builder.build());
}
Please note that there are Broacast limitations since Android 8. So you need to to provide the explicit class for handling i.e setComponent param along with action

Heads-up Notification Buttons Not Executing

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.

calling a method in service after click on notification

i have a notification which i'm calling from a service. I want to call the service again on notification click. But the notification click is not able to get inside the method.
Intent intent = new Intent(this, MyService.class).setAction(ACTION_1);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0,intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.food)
.setContentTitle("notification")
.setContentText("near by you!");
NotificationManager mNotificationManager =(NotificationManager) getSystemService(Service.NOTIFICATION_SERVICE);
Method that i want to call is
if (ACTION_1.equals(resultPendingIntent)) {
getRecommendation();
}
mBuilder.setContentIntent(resultPendingIntent);
mNotificationManager.notify(id, mBuilder.build());
i have tried following link but not able to resolve my problem.
How to execute a method by clicking a notification
You can specify a Broadcast in your Service and launch that via a PendingIntent in your notification.
Intent stopIntent = new Intent("my.awersome.string.name");
PendingIntent stopPi = PendingIntent.getBroadcast(this, 4, stopIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Then, in your notification builder:
NotificationCompat.Builder builder;
builder = new NotificationCompat.Builder(context)
...
.setContentIntent(stopPi);
In your Service you can setup a BroadcastReceiver as:
private final BroadcastReceiver myReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// Code to run
}
};
You register this receiver in your Service (possibly in onStartCommand()) only using:
registerReceiver(myReceiver, new IntentFilter("my.awersome.string.name"));
Your Service MUST be running for this to work.
Better option is to try How to execute a method by clicking a notification ..but be careful because of the static class

Android: Notifications, PendingIntent, and actions

I have a question related to creating notifications in Android with an attached action. My goal is to have an action that won't re-open my app but will simply perform some logic as specified by a class in my app. Here is my code to create said notification.
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Intent notificationIntent = new Intent(context, RetryReceiver.class);
final PendingIntent retryIntent = PendingIntent.getBroadcast(context, notificationId, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
final NotificationCompat.Builder mNotifyBuilder = new NotificationCompat.Builder(context)
.setContentTitle(title)
.setTicker(ticker)
.setContentText(message)
.setSmallIcon(R.drawable.notifcation_sprout_leaf)
.setLargeIcon(largeIcon)
.setAutoCancel(true);
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN) {
mNotifyBuilder.addAction(R.drawable.refresh_action_bar, "Retry", retryIntent);
}
// Creates an explicit intent for an Activity in your app
Intent mainIntent = new Intent(context, MainActivity.class);
// The TaskStackBuilder needs multiple intents in case there are multiple failures in succession
// Thus default it to have a MainActivity intent it can fall back on
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntent(mainIntent);
stackBuilder.addNextIntent(composeIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT);
mNotifyBuilder.setContentIntent(resultPendingIntent);
// Because the ID remains unchanged, the existing notification is updated.
notificationManager.notify(notificationId, mNotifyBuilder.build());
Here is my class to receive the broadcast:
public class RetryReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
final Bundle bundle = intent.getExtras();
// do shit
}
}
I have also registered the receiver in the AndroidManifest.xml as such:
<receiver
android:name=".RetryReceiver"
android:enabled="true"
android:exported="true" >
</receiver>
For some reason, the code in my receiver is never being fired, anyone have any suggestions?
You need to call setContentIntent(retryIntent) on your mNotifyBuilder - it is not set automatically.
Attribute android:exported="true" is to alow the broadcast receiver receive messages from sources outside its application.
The absence of any filters means that it can be invoked only by Intent objects that specify its exact class name. This implies that the receiver is intended only for application internal use.
So android:exported should be declared as android:exported="false" or not declared because it defaults to false in that case.
As I can't see no other problem with your code. Please try with android:exported="false"
See Receiver Android documentation

How to dismiss notification after action has been clicked

Since API level 16 (Jelly Bean), there is the possibility to add actions to a notification with
builder.addAction(iconId, title, intent);
But when I add an action to a notification and the action is pressed, the notification is not going to be dismissed.
When the notification itself is being clicked, it can be dismissed with
notification.flags = Notification.FLAG_AUTO_CANCEL;
or
builder.setAutoCancel(true);
But obviously, this has nothing to with the actions associated to the notification.
Any hints? Or is this not part of the API yet? I did not find anything.
When you called notify on the notification manager you gave it an id - that is the unique id you can use to access it later (this is from the notification manager:
notify(int id, Notification notification)
To cancel, you would call:
cancel(int id)
with the same id. So, basically, you need to keep track of the id or possibly put the id into a Bundle you add to the Intent inside the PendingIntent?
Found this to be an issue when using Lollipop's Heads Up Display notification. See design guidelines. Here's the complete(ish) code to implement.
Until now, having a 'Dismiss' button was less important, but now it's more in your face.
Building the Notification
int notificationId = new Random().nextInt(); // just use a counter in some util class...
PendingIntent dismissIntent = NotificationActivity.getDismissIntent(notificationId, context);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setPriority(NotificationCompat.PRIORITY_MAX) //HIGH, MAX, FULL_SCREEN and setDefaults(Notification.DEFAULT_ALL) will make it a Heads Up Display Style
.setDefaults(Notification.DEFAULT_ALL) // also requires VIBRATE permission
.setSmallIcon(R.drawable.ic_action_refresh) // Required!
.setContentTitle("Message from test")
.setContentText("message")
.setAutoCancel(true)
.addAction(R.drawable.ic_action_cancel, "Dismiss", dismissIntent)
.addAction(R.drawable.ic_action_boom, "Action!", someOtherPendingIntent);
// Gets an instance of the NotificationManager service
NotificationManager notifyMgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Builds the notification and issues it.
notifyMgr.notify(notificationId, builder.build());
NotificationActivity
public class NotificationActivity extends Activity {
public static final String NOTIFICATION_ID = "NOTIFICATION_ID";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
manager.cancel(getIntent().getIntExtra(NOTIFICATION_ID, -1));
finish(); // since finish() is called in onCreate(), onDestroy() will be called immediately
}
public static PendingIntent getDismissIntent(int notificationId, Context context) {
Intent intent = new Intent(context, NotificationActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
intent.putExtra(NOTIFICATION_ID, notificationId);
PendingIntent dismissIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
return dismissIntent;
}
}
AndroidManifest.xml (attributes required to prevent SystemUI from focusing to a back stack)
<activity
android:name=".NotificationActivity"
android:taskAffinity=""
android:excludeFromRecents="true">
</activity>
I found that when you use the action buttons in expanded notifications, you have to write extra code and you are more constrained.
You have to manually cancel your notification when the user clicks an action button. The notification is only cancelled automatically for the default action.
Also if you start a broadcast receiver from the button, the notification drawer doesn't close.
I ended up creating a new NotificationActivity to address these issues. This intermediary activity without any UI cancels the notification and then starts the activity I really wanted to start from the notification.
I've posted sample code in a related post Clicking Android Notification Actions does not close Notification drawer.
In new APIs don't forget about TAG:
notify(String tag, int id, Notification notification)
and correspondingly
cancel(String tag, int id)
instead of:
cancel(int id)
https://developer.android.com/reference/android/app/NotificationManager
In my opinion using a BroadcastReceiver is a cleaner way to cancel a Notification:
In AndroidManifest.xml:
<receiver
android:name=.NotificationCancelReceiver" >
<intent-filter android:priority="999" >
<action android:name="com.example.cancel" />
</intent-filter>
</receiver>
In java File:
Intent cancel = new Intent("com.example.cancel");
PendingIntent cancelP = PendingIntent.getBroadcast(context, 0, cancel, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Action actions[] = new NotificationCompat.Action[1];
NotificationCancelReceiver
public class NotificationCancelReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
//Cancel your ongoing Notification
};
}
You will need to run the following code after your intent is fired to remove the notification.
NotificationManagerCompat.from(this).cancel(null, notificationId);
NB: notificationId is the same id passed to run your notification
You can always cancel() the Notification from whatever is being invoked by the action (e.g., in onCreate() of the activity tied to the PendingIntent you supply to addAction()).
Just put this line :
builder.setAutoCancel(true);
And the full code is :
NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setSmallIcon(android.R.drawable.ic_dialog_alert);
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.co.in/"));
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
builder.setContentIntent(pendingIntent);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.misti_ic));
builder.setContentTitle("Notifications Title");
builder.setContentText("Your notification content here.");
builder.setSubText("Tap to view the website.");
Toast.makeText(getApplicationContext(), "The notification has been created!!", Toast.LENGTH_LONG).show();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
builder.setAutoCancel(true);
// Will display the notification in the notification bar
notificationManager.notify(1, builder.build());
Just for conclusion:
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
Intent intent = new Intent(context, MyNotificationReceiver.class);
intent.putExtra("Notification_ID", 2022);
PendingIntent pendingIntent = PendingIntent.getBroadcast(
context,
0,
intent,
...);
Notification notification = new NotificationCompat.Builder(...)
...
.addAction(0, "Button", pendingIntent)
.build();
notificationManager.notify(2022, notification);
and for dismiss the notification, you have two options:
approach 1: (in MyNotificationReceiver)
NotificationManager manager = (NotificationManager)
context.getSystemService(NOTIFICATION_SERVICE);
manager.cancel(intent.getIntExtra("Notification_ID", -1));
approach 2: (in MyNotificationReceiver)
NotificationManagerCompat manager = NotificationManagerCompat.from(context);
manager.cancel(intent.getIntExtra("Notification_ID", -1));
and finally in manifest:
<receiver android:name=".MyNotificationReceiver" />
builder.setAutoCancel(true);
Tested on Android 9 also.

Categories

Resources