Dismiss Ongoing Android Notification Via Action Button Without Opening App - android

I have an app that has an ongoing notification to help with memorization. I want to be able to dismiss this notification with one of the action button, but I don't want to open the app when the button is hit. I would prefer to use the built-in notification action buttons and not create a RemoteViews object to populate the notification. I saw one post mention using a BroadcastReceiver on this button which is received in my app, and though his tutorial was quite unhelpful, it sounds like this is headed in the right direction.
Intent resultIntent = new Intent(getBaseContext(), Dashboard.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(getBaseContext());
stackBuilder.addParentStack(Dashboard.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
Intent cancel = new Intent(getBaseContext(), CancelNotification.class);
stackBuilder.addParentStack(Dashboard.class);
stackBuilder.addNextIntent(cancel);
PendingIntent pendingCancel =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
NotificationCompat.Builder mb = new NotificationCompat.Builder(getBaseContext());
mb.setSmallIcon(R.drawable.cross_icon);
mb.setContentTitle(ref);
mb.setContentText(ver);
mb.setPriority(NotificationCompat.PRIORITY_LOW);
mb.setOngoing(true);
mb.setStyle(new NotificationCompat.BigTextStyle().bigText(ver));
mb.setContentIntent(resultPendingIntent);
mb.addAction(R.drawable.ic_cancel_dark, "Dismiss", pendingCancel);
manager.notify(1, mb.build());

Start with this:
int final NOTIFICATION_ID = 1;
//Create an Intent for the BroadcastReceiver
Intent buttonIntent = new Intent(context, ButtonReceiver.class);
buttonIntent.putExtra("notificationId",NOTIFICATION_ID);
//Create the PendingIntent
PendingIntent btPendingIntent = PendingIntent.getBroadcast(context, 0, buttonIntent,0);
//Pass this PendingIntent to addAction method of Intent Builder
NotificationCompat.Builder mb = new NotificationCompat.Builder(getBaseContext());
.....
.....
.....
mb.addAction(R.drawable.ic_Action, "My Action", btPendingIntent);
manager.notify(NOTIFICATION_ID, mb.build());
Create the BroadcastReceiver:
public class ButtonReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("notificationId", 0);
// Do what you want were.
..............
..............
// if you want cancel notification
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(notificationId);
}
}
If you donĀ“t want show any activity when user click on notification, define the intent passed in setContentIntent in this way:
PendingIntent resultPendingIntent = PendingIntent.getActivity(context, 0, new Intent(), 0);
......
......
mb.setContentIntent(resultPendingIntent);
To close notification tray when clicked, call setAutoCancel() with true when building the notification: mb.setAutoCancel(true);

The accepted solution is not working in Android 8.1 and onwards.
Follow the same steps as in the accepted answer, but update this line:
//Create the PendingIntent
PendingIntent btPendingIntent = PendingIntent.getBroadcast(context, 0, buttonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
See also PendingIntent.FLAG_UPDATE_CURRENT

I have tried using answer from #ramaral , but it is not working as the notificationId at the onReceive method always -1. I have found the solution for this problem by configuring
from
PendingIntent.getBroadcast(context, 0, approvedIntent, 0)
to
PendingIntent.getBroadcast(
context,
notificationId,
approvedIntent,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
Here is an example that you can follow.
override fun onMessageReceived(remoteMessage: RemoteMessage) {
super.onMessageReceived(remoteMessage)
val notificationId = Random.nextInt()
//Making Approve Intent for Button Action
val approvedIntent = Intent(context,
BroadcastReceiverOuting::class.java).apply {
action = ActionOuting.ACTION_APPROVED.name
putExtra(
Constant.NOTIFICATION_ID,
notificationUid
) //Compulsory to dismiss this notification
putExtra(Constant.STUDENT_IC, studentIc)
putExtra(Constant.OUTING_ID, outingId)
}
val approvedPendingIntent: PendingIntent =
PendingIntent.getBroadcast(
context,
notificationUid,
approvedIntent,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
)
val notification: Notification =
notificationCompatBuilder
.setStyle(bigTextStyle)
.setContentTitle(title)
.setContentText(description)
.setSmallIcon(R.drawable.ic_logo_128)
.setContentIntent(notifyPendingIntent)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setAutoCancel(true)
.addAction(
R.drawable.ic_baseline_approve_check_24,
context.getString(R.string.approve),
approvedPendingIntent
)
.build()
NotificationManagerCompat.from(context.applicationContext).apply {
notify(notificationUid, notification)
}
}
And then at the BroadcastReceiverOuting
override fun onReceive(context: Context?, intent: Intent?) {
if (intent != null && intent.action != null) {
val notificationUid = intent.getIntExtra(Constant.NOTIFICATION_ID, -1)
val studentIC = intent.getStringExtra(Constant.STUDENT_IC)!!
val outingID = intent.getStringExtra(Constant.OUTING_ID)!!
//Do something...
//To dismiss the notification
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.cancel(notificationUid)
}
}
Lastly, don't forget the AndroidManifest.xml .
<receiver
android:name=".utils.BroadcastReceiverOuting"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>

Related

Notification do nothing when clicked

So I would like to create a notification that, when clicked, will open my MainActivity and do something according to the extras I've put in the intent.
Right now, the notification works perfectly, but once I click it, nothing happens. I've search a little bit and have done some modification to my code :
I have added android:launchMode="singleTop" to my activity in the manifest.
I have put the code to execute in my MainActivity in the onNewIntent method :
#Override
protected void onNewIntent(Intent intent){
System.out.println("Entering onNewIntent!!!!!!!");
if(getIntent().getExtras() != null) {
url = getIntent().getExtras().getString("url");
System.out.println("URL in Main Activity : " + url);
if (url != null && url != "") {
saveFile(url);
dezipFile();
}
}
}
But nothing changed, I've put some System.out to see if it even reach the beginning of the onNewIntent... But nothing is shown on the console.
Here is the code where I create the notification :
private void createNotification () {
Intent downloadIntent = new Intent(getApplicationContext(), MainActivity.class);
downloadIntent.putExtra("url", url);
downloadIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent downloadPendingIntent = PendingIntent.getService(getApplicationContext(), 0, downloadIntent, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), "Notif")
.setSmallIcon(R.drawable.icon_notif)
.setContentTitle(getApplicationContext().getString(R.string.notif_title))
.setContentText(getApplicationContext().getString(R.string.notif_content))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(downloadPendingIntent)
.setAutoCancel(true);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("notification_download", "Dowload BD infos", NotificationManager.IMPORTANCE_DEFAULT);
NotificationManager manager = (NotificationManager) getApplicationContext().getSystemService(NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);
builder.setChannelId("notification_download");
}
NotificationManagerCompat notification = NotificationManagerCompat.from(getApplicationContext());
notification.notify(1, builder.build());
}
If anybody knows what I did wrong, it will be really appreciated!
Add this:
NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), "Notif")
.setSmallIcon(R.drawable.icon_notif)
.setContentTitle(getApplicationContext().getString(R.string.notif_title))
.setContentText(getApplicationContext().getString(R.string.notif_content))
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(downloadPendingIntent)
.setAutoCancel(true);
Intent mIntent = new Intent(context, YourActivity.class);
mIntent.setFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addNextIntent(mIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
builder.setContentIntent(resultPendingIntent);
You can set the activity launched when user clicks on a notification as follows:
Intent resultIntent = new Intent(this, targetActivityClass);
Intent backIntent = new Intent(this, backActivityClass);
Intent[] intentArray = new Intent[]{backIntent, resultIntent};
PendingIntent resultPendingIntent = PendingIntent.getActivities(this, 0, intentArray,
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, channelId);
builder.setContentIntent(resultPendingIntent);
This code also sets the activity launched when user clicks the back button after clicking the notification.

BroadcastReceiver does not get data from notification button

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

notification buttons (.addaction) not launching activity

I'm attempting to make a notification that has two buttons which do two different things by running two different activities. The notification and its buttons appear on the notification bar fine, however pressing on either of the buttons fails to launch the designated activity.
Here is the code:
private void addNotification() {
int requestID = (int) System.currentTimeMillis();
NotificationCompat.Builder builder = (android.support.v7.app.NotificationCompat.Builder) new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ibutton)
.setContentTitle("Timer running..")
.setContentText(timerString);
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(this, requestID, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(contentIntent);
//Add buttons to notification
//First make the intent
Intent pauseIntent = new Intent(this, pauseActivity.class);
//Wrap it in pending intent to trigger later
PendingIntent pausePendingIntent = PendingIntent.getActivity(this, requestID, pauseIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//Then add the action to your notification
builder.addAction(R.drawable.pause, "Pause", pausePendingIntent);
//Same again for stop button
Intent stopIntent = new Intent(this, stopActivity.class);
PendingIntent stopPendingIntent = PendingIntent.getActivity(this, requestID, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.addAction(R.drawable.stop, "Stop", stopPendingIntent);
// Add as notification
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int mNotificationId = 001;
notificationManager.notify(mNotificationId, builder.build());
}
EDIT: An example of one of the activities I am trying to launch:
public class stopActivity {
public stopActivity() {
MainActivity.stopped = true;
}
}
If there is any easier way of simply changing the value of a variable in MainActivity from the button in the notification bar then I am also keen to hear that but as far as I can tell the only option is to launch a new activity
EDIT: An example of one of the activities I am trying to launch:
public class stopActivity { public stopActivity() {
MainActivity.stopped = true; } }
This is not an Activity. An Activity extends Activity!
This is just a POJO class and you cannot start it by putting it in a PendingIntent the way you are doing.
You would be better off by just using an Intent for MainActivity with an "extra" to change a value in it. Here's an example:
Intent pauseIntent = new Intent(this, MainActivity.class);
pauseIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
pauseIntent.putExtra("pause", true);
PendingIntent pausePendingIntent = PendingIntent.getActivity(this, requestID, pauseIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//Then add the action to your notification
builder.addAction(R.drawable.pause, "Pause", pausePendingIntent);
Then, in MainActivity.onNewIntent():
if (intent.hasExtra("pause")) {
this.paused = true; // whatever you want to do when "pause" is pressed
}

Android notifications via service

I have a notifications system working that a service is scheculing then and the notifications are working fine.
I have some notifications that require user input/action.
Here is the code where I build my notification:
public int onStartCommand(Intent intent, int flag, int startId)
{
super.onStartCommand(intent , flag, startId);
Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
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_UPDATE_CURRENT);
Notification builder = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN ) {
builder = new Notification.Builder(this)
.setContentTitle(Utils.Title)
.setContentText(Utils.Body)
.setSmallIcon(R.drawable.ic_launcher)
.addAction(0, Utils.button1Value, pendingIntent)
.addAction(0, Utils.button2Value, pendingIntent)
.setSound(uri)
.setContentIntent(pendingIntent)
.build();
}
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(Utils.NotificationID, builder);
return START_STICKY;
My question is: How do I get what button in the notification user clicked? In other words, how can I create some sort of button listener for those 2 actions in the notification?
Also, how can I stack my notifications so they don`t appear all separated? I have read on Google API that I need to use .setGroup, but that is not working. Can anyone share some example of notification stacking ?
********** Added *************
final static String GROUP_KEY = "myGroup"; // added String to identify the group
public int onStartCommand(Intent intent, int flag, int startId)
{
super.onStartCommand(intent , flag, startId);
Uri uri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
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_UPDATE_CURRENT);
Notification builder = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN ) {
builder = new Notification.Builder(this)
.setContentTitle(Utils.Title)
.setContentText(Utils.Body)
.setSmallIcon(R.drawable.ic_launcher)
.setGroup(GROUP_KEY) // added group for Stacking
.addAction(0, Utils.button1Value, pendingIntent)
.addAction(0, Utils.button2Value, pendingIntent)
.setSound(uri)
.setContentIntent(pendingIntent)
.build();
}
notificationManager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(0, builder); // ID is always the same because the notifications are all stacking into one, tried with unique ID not working either
return START_STICKY;
For button listener problem:
Notification action will trigger that pendingIntent, so just put your custom intent into it. Each text should have a different pendingIntent so that you can distinguish it.
public int onStartCommand(Intent intent, int flag, int startId) {
//......
Intent mIntent1 = new Intent(this, MainActivity.class);
mIntent1.setAction("clickAc1");
PendingIntent pendingIntent1 = PendingIntent.getActivity(context, 0, mIntent1, PendingIntent.FLAG_UPDATE_CURRENT);
Intent mIntent2 = new Intent(this, MainActivity.class);
mIntent2.setAction("clickAc2");
PendingIntent pendingIntent2 = PendingIntent.getActivity(context, 0, mIntent2, PendingIntent.FLAG_UPDATE_CURRENT);
Intent it = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, it, PendingIntent.FLAG_UPDATE_CURRENT);
Notification builder = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN) {
builder = new Notification.Builder(this)
.setContentTitle("Title")
.setContentText("Text")
.setSmallIcon(R.drawable.your_logo)
.addAction(0, "ac1", pendingIntent1)
.addAction(0, "ac2", pendingIntent2)
.setSound(uri)
.setContentIntent(pendingIntent)
.build();
}
and when user click the text ac1, then you can handle it in MainActivity(or other context you want.
//MainActivity
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
Log.d("probe","onNewIntent:"+intent.getAction());
//response your click event by case intent.getAction(),
//it will be `clickAc1` or `clickAc2`, the string you write down in intent.setAction
}
If you use custom RemoteViews, you can follow this:
Intent intent = new Intent("Your Custom intent string, like com.yourpackage.ClickButtonXXX");
pendingIntent = PendingIntent.getService(getApplicationContext(),
yourRequestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT);
mRemoteViews.setOnClickPendingIntent(R.id.yourViewId, pendingIntent);
then your can response it with override Service.onStartCommand(Intent intent, int flags, int startId), case intent.getAction(); to distinguish different button.
Stacking messages:
I found this in this notification history article:
.setGroup(GROUP_KEY_MESSAGES) // added group for Stacking
.setGroupSummary(true)
.setContentTitle(count+" new notes")
.setStyle(new NotificationCompat.BigTextStyle().setSummaryText(count+" more"))
.build();
count++;
If you use Notification, change NotificationCompat.BigTextStyle() to Notification.BigTextStyle().
I think this may be what you want.
The roll-up notification cheats a little bit.

How to clear or close notification from notification bar click on close button in android

I use below code how to achieve my motto, I want to close or clear notification from notification bar click on close button
Intent moreNewsIntent = new Intent(this, MainActivity.class);
PendingIntent pIntent = PendingIntent.getActivity(AppService.this, 0, moreNewsIntent, 0);
// expanded view of the notification.
/* Intent close = new Intent(this, AppService.class);
close.setAction(CommonConstants.ACTION_DISMISS);
PendingIntent piDismiss = PendingIntent.getService(this, 0, close, 0);*/
int notificationId = new Random().nextInt(); // just use a counter in some util class...
PendingIntent dismissIntent = NotificationActivity.getDismissIntent(notificationId, AppService.this);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.app_name))
.setTicker("News Notification")
.setContentText(getString(R.string.lbl_notification_title_news))
.setDefaults(Notification.DEFAULT_SOUND| Notification.DEFAULT_VIBRATE)
.setLights(0xff00ff00, 300, 100)
.setStyle(new NotificationCompat.BigTextStyle().bigText(title))
.setContentIntent(pIntent)
.addAction (R.drawable.news_negative,getString(R.string.btn_more_nes), pIntent)
.addAction (R.drawable.close,getString(R.string.btn_close), dismissIntent)
.setAutoCancel(true);
NotificationActivity.java
public class NotificationActivity extends Activity {
public static final String NOTIFICATION_ID = "001";
#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
<activity android:name=".NotificationActivity" android:taskAffinity="" android:excludeFromRecents="true">
Thanx in advance help would be greatly appreciated
Call cancel() with the same id you initialized the notification with.
If you are asking how to get a PendingIntent to do a cancel() call, it looks like you were on the right track with PendingIntent.getService(). A better approach would probably be to use PendingIntent.getBroadcast(), register a receiver in the manifest, and do the call from there.

Categories

Resources