Android Multiple Notifications and with multiple intents - java

I have a fairly simple app that takes the input from a user and then sets it as a notification. The user can create as many notifications as he/she likes. I want the user to click the notification and get taken to a new activity called ResultActivity. ResultActivity in turn reads in the putExtras from the notifications intent and shows it to the user. The code below allows me to do almost everything I wanted, except anytime a notification is pressed, I receive the putExtra of the last created notification.
Intent notificationIntent = new Intent(ctx, MainActivity.class);
PendingIntent contentIntent = PendingIntent.getActivity(ctx, i,notificationIntent,PendingIntent.FLAG_CANCEL_CURRENT);
NotificationManager nm = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
Resources res = ctx.getResources();
NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx);
builder.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(res,R.drawable.ic_launcher))
.setTicker("Remember to " + text.getText())
.setWhen(System.currentTimeMillis()).setAutoCancel(true)
.setContentTitle(text.getText());
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, ResultActivity.class);
String pass = text.getText().toString();
resultIntent.putExtra("title", pass);
resultIntent.putExtra("uid", i);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
new Uri.Builder().scheme("data").appendQueryParameter("text", "my text").build();
builder.setContentIntent(resultPendingIntent);
Notification n = builder.build();
n.flags = Notification.FLAG_NO_CLEAR;
nm.notify(i++, n);
text.setText(null);
Open the application
Type in "One"
Hit ok
Notification is sent
Open the application
Type in "Two"
Hit ok
Notification is sent
Now you have two notifications. One that says "One" and one that says "Two". If you click on the notification "Two" it takes you to a screen that says "Two". Perfect!
If you click on the notification "One" it takes you to a screen that says "Two". BROKEN!
ResultActivity.java
public class ResultActivity extends Activity {
String title = null;
TextView text;
int i=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
text = (TextView) findViewById(R.id.textView1);
title = getIntent().getStringExtra("title");
i = getIntent().getIntExtra("uid", 0);
text.setText(title);
}

I know this was a lot time ago but i feel that the answers have not said anything about the problem in your code.
So the problem is pretty much here
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
So you create a pendingIntent from the stackbuilder whith the flag of update_current. If you look at FLAG_UPDATE_CURRENT it says
/**
* Flag indicating that if the described PendingIntent already exists,
* then keep it but replace its extra data with what is in this new
* Intent. For use with {#link #getActivity}, {#link #getBroadcast}, and
* {#link #getService}. <p>This can be used if you are creating intents where only the
* extras change, and don't care that any entities that received your
* previous PendingIntent will be able to launch it with your new
* extras even if they are not explicitly given to it.
*/
public static final int FLAG_UPDATE_CURRENT = 1<<27;
So what happens in your use case is that you create two identical pendingintents from the stackbuilder and the second intent overrides the first one . Actually you never create a second you just update the extras of the first one.
So unfortunately there is no available flag for your use case , but there is a good hack around it. What you can do is use the setAction of your resultIntent and place a random string or a string that makes sense to your app.
eg. resultIntent.setAction("dummy_action_" + notification.id);
This will make your resultIntent unique enough , so that the pendingIntent will create it rather than updating a previous one.

Set different requestCode helps me create and update current intent.
val pendingIntent = PendingIntent.getActivity(
this,
notificationID,
intent,
PendingIntent.FLAG_UPDATE_CURRENT
)

You create multiple intents that are mixed. I cleaned up the code (but did not test it)
NotificationManager nm = (NotificationManager) ctx
.getSystemService(Context.NOTIFICATION_SERVICE);
Resources res = ctx.getResources();
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, ResultActivity.class);
String pass = text.getText().toString();
resultIntent.setData(new Uri.Builder().scheme("data")
.appendQueryParameter("text", "my text").build());
resultIntent.putExtra("title", pass);
resultIntent.putExtra("uid", i);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(ctx);
builder.setSmallIcon(R.drawable.ic_launcher)
.setLargeIcon(
BitmapFactory.decodeResource(res,
R.drawable.ic_launcher))
.setTicker("Remember to " + text.getText())
.setWhen(System.currentTimeMillis()).setAutoCancel(true)
.setContentTitle(text.getText())
.setContentIntent(resultPendingIntent);
Notification n = builder.build();
n.flags = Notification.FLAG_NO_CLEAR;
nm.notify(i++, n);
text.setText(null);

Use some random requestCode to seperate two notifications
PendingIntent pendingIntent = PendingIntent.getActivity(context, CommonTools.getRandomNumber(1, 100),
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
public int getRandomNumber(int min, int max) {
// min (inclusive) and max (exclusive)
Random r = new Random();
return r.nextInt(max - min) + min;
}

Just set your pending request code to System.currentTimeMillis().toInt(). It worked.
val pendingNotificationIntent: PendingIntent = PendingIntent.getBroadcast(
this,
System.currentTimeMillis().toInt(),
notificationIntent,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)

Related

Canceling Notififcations Android Java

I started working with Notifications and to improve user expirirence I added button to notification "MARK AS READ", so when it is pressed - message will hide;
I had a few problems, in database each message has "read" field which is boolean, in method onDataChange() I loop and check if any of messages have this field as false if they have I call makeNotification(), looks fine, where is problem??? - e.x. I have 2 notifications, I cancel one(the app goes to database and change field to true, so now onDataChange() will be called), but another isn't cancelled and because onDataChange() was called now I have same notification appeared twice.....
I tried to fix this by building array of messages that are read and already displayed, not the best solution I think, but even previous problem was somehow solved this is a wierd one.
When notitifcation appears in notification list it has button "MARK AS READ", when I press it notififcation hides, but only if I start from the highest to the lower ones, so if I press second notification first foldes, if I press third first folds..
In onCreate() counter is set to 1;
public void makeNotification()
{
Intent activityIntent = new Intent(this, Notifications.class);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(), 0, activityIntent, 0);
Intent broadcastIntent = new Intent(getApplicationContext(), NotifUpdater.class);
broadcastIntent.putExtra("seconds", message.getSeconds());
broadcastIntent.putExtra("id", String.valueOf(counter));
PendingIntent actionIntent = PendingIntent.getBroadcast(this, 0,
broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, App.CHANNEL_ID)
.setVibrate(new long[]{100, 0, 100})
.setSmallIcon(R.drawable.ic_shield)
.setContentTitle(message.getTime() + " | " + message.getClient())
.setContentText(message.getMessage())
.setContentIntent(contentIntent)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.addAction(0, "MARK AS READ", actionIntent)
.build();
notificationManager.notify(counter, notification);
counter += 1;
}
// Broadcast which is triggered by pressing button
public class NotifUpdater extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
FirebaseDatabase database = FirebaseDatabase.getInstance();
String seconds = intent.getStringExtra("seconds");
int id = Integer.parseInt(intent.getStringExtra("id"));
database.getReference("latest").child(seconds).child("read").setValue(true);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(context.NOTIFICATION_SERVICE);
notificationManager.cancel(id);
}
}
You should have : FLAG_CANCEL_CURRENT
like :
PendingIntent actionIntent = PendingIntent.getBroadcast(this, NOTIFICATION_ID, buttonIntent, PendingIntent.FLAG_CANCEL_CURRENT);
not FLAG_UPDATE_CURRENT
Regarding your first issue, I'd just set an indicator for each notification, "wasShown" or something of the sort that is only set to true once you have showed the notification and when ever you are iterating your notifications, only show those who has "wasShown" set to false.
Regarding your 2nd problem, I'm not familiar with FirebaseDatabase but it sounds like its an ID problem. Did you make sure the ID you are getting from the intent is the right one?

Notification PendingIntent hard bug (or really simple one)

I'm trying to debug this for ages now and I just can't seem to find the problem:
I have a broadcast receiver, which receives the broadcast successfully.
The notification has two actions ("buttons"):
firstIntent = null;
secondIntent = null;
firstPendingIntent = null; //first "button" to join with the first intent
secondPendingIntent = null; //second "button" to join with the second intent
if(boolean){
//relevant
firstIntent = new Intent(getBaseContext(), NotificationFunctions.class).putExtra("action", "do_this");
secondIntent = new Intent(getBaseContext(), NotificationFunctions.class).putExtra("action", "do_that");
}else{
firstIntent = new Intent(getBaseContext(), NotificationFunctions.class).putExtra("action", "do_another_this");
secondIntent = new Intent(getBaseContext(), NotificationFunctions.class).putExtra("action", "do_another_that");
}
firstPendingIntent = PendingIntent.getBroadcast(getBaseContext(), 0, firstIntent, PendingIntent.FLAG_UPDATE_CURRENT);
secondPendingIntent = PendingIntent.getBroadcast(getBaseContext(), 0, secondIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notification = new NotificationCompat.Builder(getApplicationContext())
.setContentTitle(notification_title)
.setContentText(notification_text)
.setTicker("Notification!")
.setWhen(System.currentTimeMillis())
.setDefaults(Notification.DEFAULT_SOUND)
.addAction(R.drawable.abc_cab_background_top_holo_light, first_option, firstPendingIntent)
.addAction(R.drawable.abc_cab_background_top_holo_dark, second_option, secondPendingIntent)
.setAutoCancel(true)
.setSmallIcon(R.drawable.ic_stat_name)
.build();
Whenever I debug in the broadcastReceiver, for some reason, action from extras always logs "do_that", even if I click the first or second button of the notification. Any reason for this? I cant really seem to understand why.
public class NotificationFunctions extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
boolean feedback;
String action = intent.getExtras().getString("action");
Log.wtf("...", action); //logs do_that
}}
Any reason for this?
Because firstPendingIntent == secondPendingIntent.
If there already is a PendingIntent matching your request, getBroadcast() returns the existing PendingIntent. FLAG_UPDATE_CURRENT says to replace the extras in the Intent wrapped inside the PendingIntent.
In one of your two getBroadcast() calls, replace 0 with some other number, to get distinct PendingIntent objects.
Also, I recommend that you replace getBaseContext() and getApplicationContext() with this. Only use getBaseContext() and getApplicationContext() when you know precisely why you are using them.

Notification resume app instead of restart

I've read multiple questions and answers surrounding this issue, however I cannot get any of them to work for me.
I have a notification that on click I would like to bring the application to the front and resume rather than close and restart.
This is my notification code
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("example")
.setContentText("example");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(MainActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
stackBuilder.getPendingIntent(
0,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int mId = 0;
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());
And in my manifest file I have
android:launchMode="singleTop"
Can anyone see what is going wrong? I get no errors, although the notification refuses to resume the app and instead restarts it.
Fixed by using this:
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Sound Asleep")
.setContentText("Click to play and stop sounds");
// Creates an explicit intent for an Activity in your app
final Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
// Adds the back stack for the Intent (but not the Intent itself)
PendingIntent resultPendingIntent = PendingIntent.getActivity(this,0,notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int mId = 0;
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());
}
In Manifest
android:launchMode="singleTop"
I had some similar issue recently change your intent flags with this flags:
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
Edit: and remove that launchmode from your manifest.
hope it help
Use below code, may it will help
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Sound Asleep")
.setContentText("Click to play and stop sounds");
// Creates an explicit intent for an Activity in your app
final Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.setAction(Intent.ACTION_MAIN);
notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER);
// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
// Adds the back stack for the Intent (but not the Intent itself)
PendingIntent resultPendingIntent = PendingIntent.getActivity(this,0,notificationIntent,PendingIntent.FLAG_ACTIVITY_REORDER_TO_FRONT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
int mId = 0;
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());

I Have a notification in the status bar code, but AIDE is marking two things as wrong

I need to make a Status Bar Notification and I got this code from research, but it doesn't seem to be working out when I placed the code into MainActivity.java with AIDE
NotificationManager
mNotificationManager = (NotificationManager)
getSytemService(Context.N);
Notification notification = new notification(R.drawble.ic_launcher,
"Notification Test", System.currentT;
Context context = getApplicationContext();
CharSequence contentTitle = "My notification Title";
CharSequence contentText ="This is the message";
Intent notificationIntent = new Intent(this, MainActivity.class);
The errors seem to be at Line 3 with the (Context.N) where the N has the error message: Unknown member 'N' of 'android.content.Context'. The other error message is on the fifth line where it reads System.currentT with the error message of Unknown member 'currentT' of 'java.lang.Sytem'.
Context.N should be Context.NOTIFICATION_SERVICE.
System.currentT should be System.currentTimeMillis().
It seems that you are copying the code from somewhere but got the code truncated?
Here's a sample method for generating notifications.
This is based on Android's doc: Building a Notification. For more details (e.g. how to display a progress bar or an extended view), please read the docs.
private static void generateNotification(Context context, String messageTitle, String messageText)
{
// Get notification manager.
final NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Setup notification builder.
final NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(messageTitle)
.setContentText(messageText)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL);
// Create intent.
final Intent resultIntent = new Intent(context, MainActivity.class);
// Setup task stack builder.
final TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(context);
taskStackBuilder.addParentStack(MainActivity.class);
taskStackBuilder.addNextIntent(resultIntent);
// Create pending intent.
final PendingIntent resultPendingIntent = taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
// Update notification builder.
notificationBuilder.setContentIntent(resultPendingIntent);
// Post notification.
notificationManager.notify(0, notificationBuilder.build());
}
The NotificationCompat.Builder class requires Android's version 4 Support Library.

notification opening a new window no matter what in Java Android

I want to launch a notification. When I click on it, it opens a NEW window of the app.
Here's my code:
public class Noficitation extends Activity {
NotificationManager nm;
static final int uniqueID = 1394885;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
nm = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent= new Intent (Intent.ACTION_MAIN);
intent.setClass(getApplicationContext(), SchoolBlichActivity.class);
PendingIntent pi=PendingIntent.getActivity(this, 0, intent, 0);
String body = " body";
String title = "title!";
Notification n =new Notification(R.drawable.table, body, System.currentTimeMillis());
n.setLatestEventInfo(this, title, body, pi);
n.defaults = Notification.DEFAULT_ALL;
n.flags = Notification.FLAG_AUTO_CANCEL;
nm.notify(uniqueID,n);
finish();
}
by the way, if i add nm.cancel(uniqueID) before the finish(), it creates the notification and immediately deletes it...
Thanks for the help :D
You might want to just add a notification in the notification bar, and when the user clicks it, it will launch the actual Activity. This way the user won't be interrupted in whatever he's doing.
Create the status bar notification like this:
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.notification_icon, "Hello", System.currentTimeMillis());
Intent notificationIntent = new Intent(this, myclass.class);
notification.setLatestEventInfo(getApplicationContext(), "My notification", "Hello world!", notificationIntent, PendingIntent.getActivity(this, 0, notificationIntent, 0));
mNotificationManager.notify(1, notification);
http://developer.android.com/guide/topics/ui/notifiers/notifications.html
Are you just trying to open a notification window in a current activity? Because if you are I dont think you need to launch it with an intent. You normally only use intents to launch new services or activities in your app unless youve built a custom view and activity/service which is to take place within the notification box. I see you have it set up in its own class which is fine but I think the way your doing it by default would open an entire new view.
If you need to launch a notification during a process or something like a button click you dont need to have the intent there.....or at least I never did :) What exactly are you trying to achieve with the notification.

Categories