I have a background Service that triggers events and builds notifications for my app. If clicked, a notification should open the MainActivity, and depending on the info sent, open one of my Fragments within this Activity. For that, the Notification contains a PendingIntent that saves data into the Intent's Bundle.
There are three scenarios for this triggered event:
App in foreground: my service sends a Broadcast and my BroadcastReceiver in the Activity gets the event and handles it. No Notification needed. It works well.
App killed: the PendindIntent reopens my app, and my Activity accesses my info through the Bundle using getIntent().getExtras(). Everything works well.
App in background: the Activity was created already, so the BroadcastReceiver is registered. I click on my Notification, but nothing happens. Neither I receive a broadcast message, nor I can access my Bundle (checking it in onResume with getIntent().getExtras() and it's null).
Any thoughts on how to solve the third case?
Code that creates the Notification:
private void createNotification() {
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setSmallIcon(R.drawable.my_icon);
mBuilder.setContentTitle("My App");
mBuilder.setContentText("Notification message");
Bundle bundle = new Bundle();
bundle.putString(MainActivity.OPEN_FRAGMENT, "myFragment");
Intent resultIntent = new Intent(this, MainActivity.class);
resultIntent.putExtra("myInfo","myInfo");
resultIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
resultIntent.putExtras(bundle);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
mBuilder.setAutoCancel(true);
NotificationManager mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(0, mBuilder.build());
}
Have you tried to change
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
to
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, 0);
Finally, I found the solution!
What happened is that on my cases:
App foreground: Service sends a Broadcast. Activity receives it and handles the event.
App killed: Notification clicked, PendingIntent launched. App reopens and handles the event with the info from Bundle.
App in background: Notification clicked, it sends a PendingIntent, however the Activity is already running so it doesn't override it, which is why nothing happened.
Solution: override the onNewIntent method:
#Override
protected void onNewIntent(Intent intent) { // Receives the PendingIntent
super.onNewIntent(intent);
if (intent.getExtras() != null && intent.getExtras().getString(OPEN_MY_FRAGMENT) != null) {
// TODO something with intent.getExtras().getString("myInfo");
}
}
Related
I have an app which associates some entities with a unique ID and notifies about the entities to the user, which I'm gonna use notificationID to be the same as entity ID.
I have built a notification with a dismiss action based on the following sample solution exactly without any modification.
So far things are going well until I try to create 2 notifications with different ID using the sample.
A problem arises in that the dismiss button only receives the notificationID of the first notification:
The first notification behaves normally as expected.
But the second notification's getExtra() in BroadcastReceiver takes the notificationID of the FIRST notification instead and cancelling the notification just keeps cancelling the first notification.
My create Notification function, I just call this function twice with different IDs:
void createNoti(int NOTIFICATION_ID){
Intent buttonIntent = new Intent(context, ButtonReceiver.class);
buttonIntent.putExtra("notificationId", NOTIFICATION_ID);
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, buttonIntent, 0);
NotificationCompat.Builder mb = new NotificationCompat.Builder(getBaseContext());
mb.addAction(R.drawable.ic_Action, "My Action", btPendingIntent);
manager.notify(NOTIFICATION_ID, mb.build());
}
BroadcastReceiver class:
public class ButtonReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
int notificationId = intent.getIntExtra("notificationId", 0);
NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
manager.cancel(notificationId);
}
}
I believe the issue is in passing in 0 into PendingIntent:
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, buttonIntent, 0);
I had the same issue until I started passing in the notification id as the 2nd argument; so instead of passing in 0, pass in the id of the notification:
PendingIntent btPendingIntent = PendingIntent.getActivity(getApplicationContext(), NOTIFICATION_ID, buttonIntent, 0);
After I made that change, I noticed that when clicking on individual notifications (especially notifications in a group) everything worked as intended.
From the MainAcitivty I call the
startActivityForResult(new Intent(this, ActivityB.class), Constant.something);
My Application is on foreground with the ActivityB and my device receive the firebase's notification. The onMessageReceived is called
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
if (remoteMessage.getNotification() != null) {
openNewActivity(remoteMessage.getNotification().getBody());
}
}
private void openNewActivity(String messageBody) {
Intent resultIntent = new Intent(this, ActivityC.class);
resultIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
Bundle bundle = new Bundle();
bundle.putString(NotificationViewActivity.MESSAGE_EXTRA, messageBody);
resultIntent.putExtras(bundle);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 , resultIntent,
PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.icon)
.setContentTitle("TESTTTTT")
.setContentText(messageBody)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager ) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1000, builder.build());
}
When I click the firebase's notification when my app is on foreground, the activityC appears. However, when I press back button on my device, it returns to the MainActivity instead of returning the ActivtyB. Therefore, the app calls the onCreate of the MainActivity, it seems relaunch my app. Is there any way to prevent it, I want when press back button, the app returns the the MainActivty (want it calls the onStart-> onResume instead of onCreate->onStart->onResume of MainActivity)
However, when I create the new project with the simple activities. It happened like I want but in my project I is not right. Sorry for my language
Sorry, above code is right. My teammate put the wrong code at the onBackPressed in activityC. That code calls the MainActivity and set the intent's flags are android.intent.action.MAIN and android.intent.category.LAUNCHER. It makes the app running wrong like I described above
I am creating notifications with following code:
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setContentTitle(messageBody)
.setAutoCancel(true)
.setSmallIcon(R.drawable.top_icon)
.setContentText(senderName)
.setTicker(senderName+" ")
.setSound(soundUri);
Intent resultIntent = new Intent(this, LoginActivity.class);
resultIntent.putExtra("gcm_username",senderName);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 0, resultIntent, PendingIntent.FLAG_ONE_SHOT);
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(NotificationID.getID(senderName), mBuilder.build());
When user clicks the notification I am catching it with following code in loginActivity:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
gcmUserId= getIntent().getStringExtra("gcm_username");
startAction(gcmUserId);
....
My problem starts here.
Scenario:
1)When app is closed user receives notifications from 2 different users
2)User clicks first notification and app starts then startAction method calls.
3)Then user clicks the second notification
But when user clicks the second notification app has already started so startAction won't be able to call again because it is in the onCreate method.How can catch second notification ?
You can handle it inside onNewIntent(). You would need to override that method inside your activity. The docs say:
This is called for activities that set launchMode to "singleTop" in their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent). In either case, when the activity is re-launched while at the top of the activity stack instead of a new instance of the activity being started, onNewIntent() will be called on the existing instance with the Intent that was used to re-launch it.
I want to be able to have a button that copies the text from a notification to the clipboard. The notification is sent through the google's GCM service.
The first time the notification arrives when I press the "copy" button everything is fine and the text goes into the clipboard by the service that the button sends an intent to. The second time a notification arrives with different text when I press the "copy" button the content of the first notification goes into the clipboard instead of the new one. When I debug the code, it seems that the intent that's calling the service has the new content, but the service that puts it into the clipboard runs with the parameters of the old notification, as if the same session of the service is awaken with the old intent.
Any clue why this is happening?
// Called by the GCM notification handler
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,new Intent(this, MainActivity.class), 0);
Intent notificationIntent = new Intent(this, clipboardService.class);
notificationIntent.putExtra("tool",msg);
PendingIntent serviceIntent = PendingIntent.getService(this, 0, notificationIntent, 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_stat_gcm)
.setContentTitle("Here's your text!")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg)
.addAction(R.drawable.ic_stat_gcm, "Copy", serviceIntent); // <--- The intent will have the right (new) value on the second run
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
This is the service that the notification actions calls to:
public class clipboardService extends IntentService {
public clipboardService() {
super("clipboardService");
}
#Override
protected void onHandleIntent(Intent intent) { //This intent will have the values of the first intent to fire, instead of the updated one.
String msg = (String) intent.getExtras().get("tool");
ClipboardManager clipboard = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
ClipData clip = ClipData.newPlainText("2android",msg);
clipboard.setPrimaryClip(clip);
}
Although it is very late to answer your question, but recently I faced the same issue and Google led to me this unanswered question. So here is my understanding if in future someone dig this up.
This is because PendingIntent uses cached intent extras from previous instance of the intent unless you explicitly tell it not to. There are two ways to do that...
Use FLAG_CANCEL_CURRENT or FLAG_UPDATE_CURRENT (best in your case) as flag while constructing the PendingIntent. The first flag will automatically dismiss the previous PendingIntent and create a completely new one and the second one will only update the extras for the PendingIntent and save the overhead of creating a completely new one.
PendingIntent.getService(this, 0, notificationIntent,
FLAG_CANCEL_CURRENT | FLAG_UPDATE_CURRENT);
Pass an unique requestCode to the PendingIntent constructor everytime. This will generate unique pending intents for everytime so that you can access the extras associated with a particular intent later. I believe this is not required in your case.
PendingIntent.getService(this, UNIQUE_ID, pi, 0);
I have an application which starts a service running on the background. This service periodically issues a constant notification. I would like to be able to press that notification and resume the last activity of the application.
I am creating my notifications as follows:
public static void startNotification(Service service, String message) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(service);
if(prefs.getBoolean("pref_NotificationDisplayed", true)){
// Creates an Ongoing Notification
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(service.getApplicationContext()).setSmallIcon(R.drawable.ic_launcher).setContentTitle("Title").setContentText(message);
Intent toLaunch = new Intent(service.getApplicationContext(),MainActivity.class);
toLaunch.setAction("android.intent.action.MAIN");
toLaunch.addCategory("android.intent.category.LAUNCHER");
PendingIntent intentBack = PendingIntent.getActivity(service.getApplicationContext(), 0,toLaunch, PendingIntent.FLAG_UPDATE_CURRENT);
//PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(intentBack);
NotificationManager mNotificationManager = (NotificationManager) service.getSystemService(Context.NOTIFICATION_SERVICE);
// Send Notification
Notification primaryNotification = mBuilder.build();
primaryNotification.flags = Notification.FLAG_ONGOING_EVENT;
mNotificationManager.notify(10001,primaryNotification);
}
}
I have tried the solutions from here and here with no luck.
Every time I press the notification a new activity is started up rather than resuming the old activity. Is this because I am issuing the activity from a service ? or am I making an obvious error above ?
Thanks for the help.
are you try
toLaunch.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
inyour intent. check above flag i dont have tried...