I've found a lot of Stack Overflow posts about this issue but they all use the now deprecated Notification methods instead of using the Notification.Builder class.
I'm successfully creating status bar notifications, but when clicked nothing happens. A warning in LogCat shows up:
Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy#412d6df0
Here is the code I'm using to build my Notification:
public class LunchNotificationBuilder {
private Notification notification;
public LunchNotificationBuilder(Lunch lunch, Context context) {
Builder builder = new Builder(context);
Calendar reminderTime = (Calendar)lunch.getReminderTime().clone();
builder.setWhen(reminderTime.getTimeInMillis());
builder.setTicker("Reminder for " + lunch.getTitle());
builder.setContentTitle("LunchBunch Notification");
builder.setContentText("Upcoming lunch at " + lunch.getTitle());
builder.setSmallIcon(R.drawable.ic_launcher);
Intent intent = new Intent(context, InviteDetails.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
builder.setContentIntent(PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_ONE_SHOT));
this.notification = builder.getNotification();
}
public Notification getNotification() {
return this.notification;
}
}
The Lunch class is just a data structure I created, don't worry about that.
The Context being passed in is Application.getApplicationContext().
I'm setting the Intent.FLAG_ACTIVITY_NEW_TASK flag as suggested by the documentation, and the PendingIntent has the PendingIntent.FLAG_ONE_SHOT flag.
Another note: The activity I'm trying to launch (InviteDetails) works just fine when I explicitly call startActivity elsewhere in the code. Something about this PendingIntent business isn't working.
Turns out I don't know how to use Android. I was clicking the status bar at the top, not dragging down to see the full notification before clicking. my code was working. doh!
Related
I have reviewed a lot of information on this issue, but no one can solved it.
On android 7.0 devices,when using NotificationManager to send more than 5 messages, all messages will be collapsed.
Please click on the image to see the message is collapsed.
When I click on this collapsed notification bar message, my app will be rebooted into the login activity even if my app is logged in and running in the foreground.This is terrible.If I click on a single notification bar message, then it will enter the activity normally.
How to set the notification bar message to not collapse or when I click on the collapsed notification bar message, do not restart the app.
this is my code:
Intent notifyIntent;
PendingIntent appIntent;
notifyIntent = new Intent(context, TestActivity.class);
notifyIntent.putExtra("content", contentJson);
appIntent = PendingIntent.getActivity(context,
noticeId, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "program").setAutoCancel(true)
.setSmallIcon(iconId)
.setContentTitle(notifyTitle)
.setDefaults(Notification.DEFAULT_ALL)
.setNumber(noticeId)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setGroupSummary(false)
.setContentIntent(appIntent);
builder.setVisibility(Notification.VISIBILITY_PUBLIC);
builder.setColorized(true);
Notification myNoti = builder.build();
myNoti.flags = NotificationCompat.FLAG_INSISTENT | Notification.FLAG_AUTO_CANCEL;
if (noticeId > 40) {
noticeId = 0;
notificationManager.cancelAll();
}
notificationManager.notify(noticeId, myNoti);
I set TestActivity
android:launchMode="singleTop"
I found the problem, not what I thought. App is not restarted.Only LoginActivity was recreated once and placed on the top of the stack.I am worried that other people have the same thoughts as me and think that the APP has been restarted,So I won’t change this question.I hope to help people who have this problem.I will put the solution below.
When you click on the collapsed notification bar message, assume your LoginAtivity has been recreated.You need to write the following code in the onCreate of LoginActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!isTaskRoot()) {
finish();
return;
}
setContentView(R.layout.activity_main_menu);
}
isTaskRoot() will detect if this class is at the root of the stack.If not, then finish.
Note that if you have logic in onDestory, use isTaskToot() to determine,for example:
#Override
protected void onDestroy(){
super.onDestroy();
if (isTaskRoot()) {
//your code
}
}
I have hooked up to Google Cloud Messaging and am displaying a notification when I receive something.
I want to "maximize" my app when the user clicks on the notification. I.e. show the latest activity related to my app. Or, if the app has not started, I want to start it's main activity.
It is imperative that I do not create a new instance of the last activity if the app is already open.
How can I achieve this?
I have seen a lot of similar questions, but all the answers seem to want to specify the activity class, which I don't know, since I don't know which activity was last shown.
Is there a solution to this seemingly simple task?
My code looks something like this at the moment:
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.icon)
.setContentTitle("foo")
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(PendingIntent.getActivity(getApplicationContext(), 0, new Intent(), 0));
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
But it is not working.
When your opening an Activity while Notification is clicked just open the following Activity. i.e. your PendingIntent will open following Activity
Please read all the comments written in Activity so that you will know why this has been created
public class NotificationHandlerActivity extends AppCompatActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//deep linking - resuming app code
if (isTaskRoot()) {
// This Activity is the only Activity, so
// the app wasn't running. So start the app from the
// beginning (redirect to MainActivity)
} else {
// App was already running, so just finish, which will drop the user
// in to the activity that was at the top of the task stack
Intent intent = getIntent();
Uri data = intent.getData();
//you can put your extra's if any
finish();
}
}
}
I have a problem with notification on Android (Xamarin).
My scenario is this:
I have a class handling (inheriting GcmServiceBase) the message and creating the Notification object.
In this class I override OnMessage method in this way:
protected override void OnMessage(Context context, Intent intent)
{
if (intent != null || intent.Extras != null)
{
string messageText = intent.Extras.GetString("message");
string messageTitle = intent.Extras.GetString("title");
Intent app_launch_intent = new Intent(context, typeof(Project.WaitForm));
if (App.Instance == null)
{
Console.WriteLine("GCM: Notification received while application not running...");
app_launch_intent.AddFlags(ActivityFlags.ClearTop);
app_launch_intent.AddFlags(ActivityFlags.SingleTop);
}
else if ((App.Instance != null) && (App.Instance.mainActivity.IsInBackground))
{
App.Instance.Logger.Write("GCM: Notification received while application in background...", LogType.Default, LogLevel.Info);
app_launch_intent = new Intent(context, App.Instance.mainActivity.GetType());
}
else
{
App.Instance.Logger.Write("GCM: Notification received while application in foreground...", LogType.Default, LogLevel.Info);
app_launch_intent = new Intent(context, App.Instance.mainActivity.GetType());
app_launch_intent.AddFlags(ActivityFlags.SingleTop);
}
app_launch_intent.PutExtras(intent.Extras);
app_launch_intent.PutExtra("isNotify", true);
PendingIntent pendingIntent = PendingIntent.GetActivity(this, PushService.notificationId, app_launch_intent, PendingIntentFlags.OneShot);
createNotification(context, app_launch_intent, pendingIntent, messageTitle, messageText);
if (App.Instance == null)
{
Console.WriteLine("GCM: Notification object correctly created.");
}
else
{
App.Instance.Logger.Write("GCM: Notification object correctly created.", LogType.Default, LogLevel.Info);
}
}
}
public void createNotification(Context context, Intent result_intent, PendingIntent pendingIntent, string title, string desc)
{
NotificationManager notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
Notification.Builder builder = new Notification.Builder(this)
.SetContentIntent(pendingIntent)
.SetAutoCancel(true)
.SetContentTitle(title)
.SetContentText(desc)
.SetSmallIcon(Resource.Drawable.notify_icon_transparent)
.SetLargeIcon(PushService.IconAgenda)
.SetTicker(title);
Notification notification = builder.Build();
PushService.notificationId += 1;
notificationManager.Notify(PushService.notificationId, notification);
}
as you can see, when message is received I test if application object exists then I create Intent and notification object (App.Instance is a singleton holding informations about the app itself. mainActivity is the current activity shown on screen).
In this way when notification is clicked, last activity on the top of the stack (current on-screen activity if app is in foreground or last on-screen activity before app went in background) will come
up and something in it will take care about notification itself, called by OnNewIntent.
Everything is working fine except for a thing:
Let's say I have 3 Activity called A, B, C.
I start the app and then I receive 2 different notifications when current activity on screen is A.
Both will be displayed in the top bar without problems.
I click on the first of them and it asks me to open another activity (catched in OnNewEvent of current activity and due to notification type), so I say "yes" and I will have a transition to activity C.
Once reached activity C and after done some work, I click on the other notification.
Clicking on it I will be carried to activity A and then notification will be handled.
I know this "problem" is because at notify creation I use the App.Instance.mainActivity.GetType() to create intent that will be use to create PendingIntent and that at that time was activity A for both.
So my question is:
How can I handle second notify click in last activity on screen (so in activity C) instead of activity A?
(I add Xamarin tag just because code above is in C# and not in Java so it may sound strange to a native Android developer)
I want to dismiss the notification action buttons (not the whole notification) when clicking on those action buttons. (Lets say: a download notification with stop action button. When click on stop, dismiss stop button and change contentText to 'Download canceled')
The only thing it comes to my mind is to cancel notification and notify another one with the same id, but this seems to be an ugly workaround...
So, is there any way to remove action buttons from notifications?
(i think there is no need to put any code, but I will if its necessary...)
If you are using the NotificationCompat.Builder from the v4 Support Library, you can simply access the builder's action collection directly (Unfortunately no public mutators are provided).
The following will do the trick (Of course you must update re-notify):
NotificationCompat.Builder notifBuilder = NotificationCompat.Builder(context);
...
notifBuilder.mActions.clear();
I am using following workaround:
NotificationCompat.Builder builder = //existing instance of builder
//...
try {
//Use reflection clean up old actions
Field f = builder.getClass().getDeclaredField("mActions");
f.setAccessible(true);
f.set(builder, new ArrayList<NotificationCompat.Action>());
} catch (NoSuchFieldException e) {
// no field
} catch (IllegalAccessException e) {
// wrong types
}
from here: https://code.google.com/p/android/issues/detail?id=68063
Note:
Proguard may break the button clearing in obfuscated build. Fix is to add the following two lines in proguard-rules.pro
-keep class androidx.core.app.NotificationCompat { *; }
-keep class androidx.core.app.NotificationCompat$* { *; }
I had the same problem and found a solution for this.
I created another builder and added two "empty" actions like this:
builder.addAction(0, null, null);
builder.addAction(0, null, null);
(one for each button I had, so if you have three, call it three times).
Then when calling Notify, it removes the buttons.
Even though the accepted answer works, as per documentation, the designed way to do this is by using NotificationCompat.Extender class. For example in Kotlin:
private val clearActionsNotificationExtender = NotificationCompat.Extender { builder ->
builder.mActions.clear()
builder
}
private val notificationBuilder by lazy {
NotificationCompat.Builder(context)
.addAction(R.drawable.ic_play_arrow, "Play", playPendingIntent)
}
private fun updateNotification(){
notificationBuilder
.extend(clearActionsNotificationExtender) // this will remove the play action
.addAction(R.drawable.ic_pause, "Pause", pausePendingIntent)
}
NotificationCompat.Builder notifBuilder = NotificationCompat.Builder(context);
remove Whole Action Button :
builder.mActions.clear();
for remove special action button :
builder.mActions.remove(index);
finally :
notificationManager.notify(notificationID, builder.build());
Android provides the notification area for alerting users about the events that have occurred. It also provides a notification drawer that user can pull down to see more detailed information about the notification.
Notification Drawer consists of
View (contains tittle,detail,small icon)
Action ( any action which may occur in case the user clicks the notification drawer view)
To set up a notification so it can be updated, issue it with a notification ID by calling NotificationManager.notify(ID, notification). To update this notification once you've issued it, update or create a NotificationCompat.Builder object, build a Notification object from it, and issue the Notification with the same ID you used previously.
mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Sets an ID for the notification, so it can be updated
int notifyID = 1;
mNotifyBuilder = new NotificationCompat.Builder(this)
.setContentTitle("New Message")
.setContentText("You are downloading some image.")
.setSmallIcon(R.drawable.ic_stop)
numMessages = 0;
// Start of a loop that processes data and then notifies the user
...
mNotifyBuilder.setContentText("Download canceled")
.setNumber(++numMessages);
// Because the ID remains unchanged, the existing notification is
// updated.
mNotificationManager.notify(
notifyID,
mNotifyBuilder.build());
...
I have an application with two buttons. One button that "closes" the application and one that begins the algorithm. When I click "begin" it "hides" the application and displays a notification in the notification bar. I need to be able to execute/call a method when the notification is clicked/pressed. There are a few answers for this sort of question, but they are incredibly vague and one only points to a link to the doc on BroadcastReceiver.
If you are going to leave a url to the BroadcastReceiver doc and say "read this page," please don't reply to this question. If you are going to explain how I could use BroadcastReceiver to execute a method (from within the same class that displayed the notification), please show me some code for how this could be done.
My algorithm: press a button, display notification, click notification, call a method (don't display activity). That's it.
If it's not possible, just let me know. If it is, please show me what you would do to make it possible. Something this simple shouldn't have been overlooked by the developers of the android sdk.
After several iterations of trial and error, I finally found a fairly straightforward and clean way to run an arbitrary method when a notification's action is clicked. In my solution, there is one class (I'll call it NotificationUtils) that creates the notification and also contains an IntentService static inner class that will run when actions on the notification are clicked. Here is my NotificationUtils class, followed by the necessary changes to AndroidManifest.xml:
public class NotificationUtils {
public static final int NOTIFICATION_ID = 1;
public static final String ACTION_1 = "action_1";
public static void displayNotification(Context context) {
Intent action1Intent = new Intent(context, NotificationActionService.class)
.setAction(ACTION_1);
PendingIntent action1PendingIntent = PendingIntent.getService(context, 0,
action1Intent, PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Sample Notification")
.setContentText("Notification text goes here")
.addAction(new NotificationCompat.Action(R.drawable.ic_launcher,
"Action 1", action1PendingIntent));
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
}
public static class NotificationActionService extends IntentService {
public NotificationActionService() {
super(NotificationActionService.class.getSimpleName());
}
#Override
protected void onHandleIntent(Intent intent) {
String action = intent.getAction();
DebugUtils.log("Received notification action: " + action);
if (ACTION_1.equals(action)) {
// TODO: handle action 1.
// If you want to cancel the notification: NotificationManagerCompat.from(this).cancel(NOTIFICATION_ID);
}
}
}
Now just implement your actions in onHandleIntent and add the NotificationActionService to your manifest within the <application> tags:
<service android:name=".NotificationUtils$NotificationActionService" />
Summary:
Create a class that will create the notification.
Inside that class, add a IntentService inner classes (make sure it is static or you will get a cryptic error!) that can run any method based on the action that was clicked.
Declare the IntentService class in your manifest.
On Notification click we can't get any fire event or any click listener. When we add notification in notification bar, we can set a pending intent, which fires an intent (activity/service/broadcast) upon notification click.
I have a workound solution for you, if you really don't want to display your activity then the activity which is going to start with pending intent send a broad cast from there to your parent activity and just finish the pending activity and then once broadcast receiver receives in parent activity call whatever method you want inside the receiver. For your reference..
// This is what you are going to set a pending intent which will start once
// notification is clicked. Hopes you know how to add notification bar.
Intent notificationIntent = new Intent(this, dummy_activity.class);
notificationIntent.setAction("android.intent.action.MAIN");
notificationIntent.addCategory("android.intent.category.LAUNCHER");
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT |
Notification.FLAG_AUTO_CANCEL);
// Now, once this dummy activity starts send a broad cast to your parent activity and finish the pending activity
//(remember you need to register your broadcast action here to receive).
BroadcastReceiver call_method = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String action_name = intent.getAction();
if (action_name.equals("call_method")) {
// call your method here and do what ever you want.
}
};
};
registerReceiver(call_method, new IntentFilter("call_method"));
}
}