My MainActicity starts RefreshService with a Intent which has a boolean extra called isNextWeek.
My RefreshService makes a Notification which starts my MainActivity when the user clicks on it.
this looks like this:
Log.d("Refresh", "RefreshService got: isNextWeek: " + String.valueOf(isNextWeek));
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.putExtra(MainActivity.IS_NEXT_WEEK, isNextWeek);
Log.d("Refresh", "RefreshService put in Intent: isNextWeek: " + String.valueOf(notificationIntent.getBooleanExtra(MainActivity.IS_NEXT_WEEK,false)));
pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
builder = new NotificationCompat.Builder(this).setContentTitle("Title").setContentText("ContentText").setSmallIcon(R.drawable.ic_notification).setContentIntent(pendingIntent);
notification = builder.build();
// Hide the notification after its selected
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(NOTIFICATION_REFRESH, notification);
As you can see the notificationIntent should have the booleanextra IS_NEXT_WEEK with the value of isNextWeek which is put in the PendingIntent.
When I click now this Notification I always get false as value of isNextWeek
This is the way I get the value in the MainActivity:
isNextWeek = getIntent().getBooleanExtra(IS_NEXT_WEEK, false);
Log:
08-04 00:19:32.500 13367-13367/de.MayerhoferSimon.Vertretungsplan D/Refresh: MainActivity sent: isNextWeek: true
08-04 00:19:32.510 13367-13573/de.MayerhoferSimon.Vertretungsplan D/Refresh: RefreshService got: isNextWeek: true
08-04 00:19:32.510 13367-13573/de.MayerhoferSimon.Vertretungsplan D/Refresh: RefreshService put in Intent: isNextWeek: true
08-04 00:19:41.990 13367-13367/de.MayerhoferSimon.Vertretungsplan D/Refresh: MainActivity.onCreate got: isNextWeek: false
When I directly start the MainActivity with an Intent with the ìsNextValue` like this:
Intent i = new Intent(this, MainActivity.class);
i.putExtra(IS_NEXT_WEEK, isNextWeek);
finish();
startActivity(i);
everything works fine and I get true when isNextWeek is true.
What do I make wrong that there is always a false value?
UPDATE
this solves the problem:
https://stackoverflow.com/a/18049676/2180161
Quote:
My suspicion is that, since the only thing changing in the Intent is
the extras, the PendingIntent.getActivity(...) factory method is
simply re-using the old intent as an optimization.
In RefreshService, try:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
See:
http://developer.android.com/reference/android/app/PendingIntent.html#FLAG_CANCEL_CURRENT
UPDATE 2
See answer below why it is better to use PendingIntent.FLAG_UPDATE_CURRENT.
Using PendingIntent.FLAG_CANCEL_CURRENT not a good solution because of inefficient use of memory. Instead use PendingIntent.FLAG_UPDATE_CURRENT.
Use also Intent.FLAG_ACTIVITY_SINGLE_TOP (the activity will not be launched if it is already running at the top of the history stack).
Intent resultIntent = new Intent(this, FragmentPagerSupportActivity.class).
addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
resultIntent.putExtra(FragmentPagerSupportActivity.PAGE_NUMBER_KEY, pageNumber);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
Then:
#Override
protected void onCreate(Bundle savedInstanceState) {
try {
super.onCreate(savedInstanceState);
int startPageNumber;
if ( savedInstanceState != null)
{
startPageNumber = savedInstanceState.getInt(PAGE_NUMBER_KEY);
//so on
It should work now.
If you still have not expected behaviour, try to implement void onNewIntent(Intent intent) event handler, that way you can access the new intent that was called for the activity (which is not the same as just calling getIntent(), this will always return the first Intent that launched your activity.
#Override
protected void onNewIntent(Intent intent) {
int startPageNumber;
if (intent != null) {
startPageNumber = intent.getExtras().getInt(PAGE_NUMBER_KEY);
} else {
startPageNumber = 0;
}
}
I think you need to update the Intent when you receive a new one by overriding onNewIntent(Intent) in your Activity. Add the following to your Activity:
#Override
public void onNewIntent(Intent newIntent) {
this.setIntent(newIntent);
// Now getIntent() returns the updated Intent
isNextWeek = getIntent().getBooleanExtra(IS_NEXT_WEEK, false);
}
Edit:
This is needed only if your Activity has already been started when the intent is received. If your activity is started (and not just resumed) by the intent, then the problem is elsewhere and my suggestion may not fix it.
Following code should work:-
int icon = R.drawable.icon;
String message = "hello";
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
Intent notificationIntent = new Intent(context, MainActivity.class);
notificationIntent.putExtra("isNexWeek", true);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, pIntent);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notificationManager.notify(0, notification);
In MainActivity onCreate:
if (getIntent().getExtras() != null && getIntent().getExtras().containsKey("isNextWeek")) {
boolean isNextWeek = getIntent().getExtras().getBoolean("isNextWeek");
}
So the actual reason is that the PendingIntent will cache the previous intent if the intents only differ in their extras. In my situation no combination of PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_CANCEL_CURRENT solves this as either the old intent will be replaced or the new one will stay the same as the initial one.
You need to ensure that Android cannot cache the Intents behind the PendingIntent. The solution for me is to make them differ in their data attribute.
so in the original posters code you would need to ensure that the data attribute is unique per each combination of extras that you are attaching.
Intent notificationIntent = new Intent(this, MainActivity.class);
notificationIntent.putExtra(MainActivity.IS_NEXT_WEEK, isNextWeek);
notificationIntent.setData(Uri.parse("myapp://nextWeek/" + (isNextWeek ? "1" : "0"))
Alternatively you could probably also just add a uuid to the data uri (however, if you have lots and lots of notifications, it might be nice to cache them
Related
I am sending an Intent from GCMIntentService through PendingIntent. I am inserting some strings inside intent and in PendingIntent, I call an activity which will receive intent. But the data is not what I am sending. Here is the screenshot.
The first Intent shown is what I am sending, and the second is what I am receiving. Here is the code for sending:
Intent intent = new Intent(getBaseContext(),
Group_Chat_MainActivity.class);
intent.putExtra("group_id", group_id);
intent.putExtra("group_title", name);
intent.putExtra("from_push", true);
PendingIntent pendingIntent = PendingIntent.getActivity(
getBaseContext(), 100,
intent, 0);
Notification notification = new NotificationCompat.Builder(
getBaseContext()).setContentTitle("Paisa Swipe")
.setContentText(msg)
.setSmallIcon(R.drawable.home_logo)
.setTicker(ticker)
.setDefaults(Notification.DEFAULT_ALL)
.setWhen(System.currentTimeMillis())
.setContentIntent(pendingIntent)
.setAutoCancel(true).build();
notificationManager.notify(Integer.parseInt(group_id),
notification);
When I click notification, it sends to the Group_Chat_MainActivity class. In that, I use getIntent() to fetch the Intent data:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.chat_activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
getIntent().getStringExtra("group_title")
getIntent().getStringExtra("group_id")
getIntent().getBooleanExtra("from_push",false)
}
Here I am getting different strings then what I sent. Any ideas?
Actually the problem is your PendingIntent requestCode is same all the time i.e 100. Keep it to be a unique for a group for eg. your group_id. Also your context here should be your GCMIntentService context.Try changing this to
PendingIntent pendingIntent = PendingIntent.getActivity(
getBaseContext(), 100,
intent, 0);
this
PendingIntent pendingIntent = PendingIntent.getActivity(
yourContextHere, Integer.parseInt(group_id),
intent, 0);
Make sure your getBaseContext() is not null.
If you use it in Fragmnet try:
inflatedview.getContext();
instead of:
getBaseContext()
and when you want get value from your intent in OnCreate method, try this:
getIntent().getExtras().getString();
instead of:
getIntent().getStringExtra();
hope this help you.
I am trying to send information from notification to invoked activity, while from my activity I got null.
The code for notification is:
private void showNotification() {
Intent resultIntent = new Intent(this, MainActivity.class);
if (D)
Log.d(TAG, "Id: " + Id);
resultIntent.putExtra("ineedid", deviceId);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(MeterActivity.class);
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0,
PendingIntent.FLAG_UPDATE_CURRENT);
// Bundle tmp = resultIntent.getExtras();
// if (tmp == null) {
// Log.d(TAG, "tmp bundle is null");
// } else {
// long id = tmp.getLong("ineedid", -1);
// Log.d(TAG, "tmp id : " + id);
// }
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
BLEMessengerService.this)
.setSmallIcon(R.drawable.ic_action_search)
.setContentTitle("Event tracker")
.setContentText("Events received").setOngoing(true)
.setContentIntent(resultPendingIntent)
.setWhen(System.currentTimeMillis());
int mId = R.string.service_notification_start_service;
mNM.notify(mId, mBuilder.getNotification());
}
Code for get information from intent in main activity;
Bundle extras = getIntent().getExtras();
if (extras != null) {
long deviceID = getIntent().getLongExtra("ineedid",
-1);
if (ID == -1) {
if (D)
Log.i(TAG_D, "Wrong Id received.");
finish();
} else {
device = dataSource.getDeviceByID(deviceID);
if (D)
Log.i(TAG_D, "Get the id.");
}
} else {
if (D)
Log.d(TAG_D, "Bundle is null");
finish();
}
I have verified before the notification get notified, bundle is not null, and it has id in extras.
While, when I tried to fetch it from intent, it's gone. Help.
in PendingIntent use this flag PendingIntent.FLAG_UPDATE_CURRENT it's work for me
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
For me, in addition to setting Intent.FLAG_ACTIVITY_SINGLE_TOP , I had to add a unique action to the intent:
Intent resultIntent = new Intent(caller, NotificationActivity.class);
String xId = getNextUniqueId();
resultIntent.putExtra("x_id", xId);
resultIntent.setAction(xId);
resultIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
.. without the setAction(..), Extras is null on the Intent received by my NotificationActivity.
This post helps explain it: https://stackoverflow.com/a/3128271/2162226
When an activity is launched(when it is first started ) or relaunched(when it's brought to the top of the stack) the getIntent().getExtra() won't give null. But when the activity is present on the top of the stack then on starting that activity with the use of PendingIntent would not relaunch the activity(onCreate() won't get called) instead onResume() would be called. And getIntent().getExtra() would return the value which is associated with the intent that started the activity(which is null).
In order to update the intent do the following steps:
1). Set FLAG_ACTIVITY_SINGLE_TOP and FLAG_ACTIVITY_CLEAR_TOP flags in your intent.
resultIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
2). Override onNewIntent() in the activity where getIntent().getExtra() is called. This method is called by FLAG_ACTIVITY_SINGLE_TOP
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
For more info: See this doc
I just got the answer,
add line: resultIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
NOTICE: if you add it as resultIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
It won't work.
I also tried other flags like, "FLAG_ACTIVITY_NEW_TASK" and "FLAG_ACTIVITY_RESET_TASK_IF_NEEDED". neither works here.
For me, my Samsung device kept removing the extras from the intent and sometimes even crashed the app. Tried all the combinations but the actual reason for this behaviour was not explicitly adding PendingIntent.FLAG_IMMUTABLE flag to the pending intent.
Although, this is a requirement for Android 12 and above.
val pendingIntent = PendingIntent.getActivity(
this, 0,
getIntent(),
PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
I was working in a local notifications plugin for Unity when I encountered the same problem -> I launched the app, scheduled the local notification, sent the app to background, local notification appeared and, when I clicked on it, app was resumed and getIntent().getExtras() was null.
In my case, the problem was I was trying to get the extras at the wrong intent. Try to print the intents with a simple toString, at the creation moment and when you get it, to ensure that the received is what you expect.
Also take a look to the onNewIntent method.
If you are using the implicit intent to build a PendingIntent, you may get this problem.
previous approach with the issue.
val intent = Intent()
intent.action = Intent.ACTION_VIEW
intent.data = Uri.parse("deeplink or applink here")
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
intent.putExtra("key", Parcelable)
PendingIntent.getActivity(context, abs(Random.nextInt()), intent, PendingIntent.FLAG_UPDATE_CURRENT)
based on implicit Intent tried multiple approaches listed above not work for me.
here is the approach solved my problem. change the Intent from implicit one to an explicit one.
// only diff
val intent = Intent(context, YourIntentDestinationActivity::class.java)
// only diff
intent.action = Intent.ACTION_VIEW
intent.data = Uri.parse("deeplink or applink here")
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
intent.putExtra("key", Parcelable)
PendingIntent.getActivity(context, abs(Random.nextInt()), intent, PendingIntent.FLAG_UPDATE_CURRENT)
hope this works for you.
This seem to be a common problem and I went through all the related questions I could find already:
Activity isn't picking up new intent, Why extra data (integer) is not sent in android notification intent?, Notification passes old Intent Extras, Can't put extras for an intent in notification, android pending intent notification problem; but still cannot figure this out.
Problem is the same. I set a notification with a PendingIntent carrying some extra information and I don't get it on the other side.
Here is the code for generating the notification:
Notification notification = new Notification(R.drawable.icon, getResources().getString(R.string.notification_ticker), System.currentTimeMillis());
notification.flags = Notification.FLAG_AUTO_CANCEL | Notification.FLAG_ONLY_ALERT_ONCE;
Intent start_test = new Intent(this, MyActivity.class);
start_test.putExtra("start_test", true);
start_test.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pi = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), start_test, PendingIntent.FLAG_CANCEL_CURRENT);
notification.setLatestEventInfo(this, getResources().getString(R.string.notification_title), getResources().getString(R.string.notification_content, expired), pi);
nm.notify(NOTIFICATION_ID, notification);
And on the other side:
boolean start_test=getIntent().getBooleanExtra("start_test", false);
The bundle is actually not there (getExtras() returns null).
I tried the different flags for PendingIntent.getActivity (FLAG_UPDATE_CURRENT, FLAG_CANCEL_CURRENT, FLAG_ONE_SHOT), none of those helped.
As shown in the code, I use getCurrentMillis to make sure the requestID changes....
Also found that in MyActivity, onCreate and onNewIntent are not getting called. only onResume is. Even though the FLAG_ACTIVITY_NEW_TASK is set... ?
Am I missing something very simple ?
Setting FLAG_ACTIVITY_NEW_TASK for the notification Intent will cause the following:
If the activity is not already running in a task, a new task will be started and the Intent will be delivered to the activity in onCreate()
However, if the activity is already running in a task, that task will be brought to the foreground. That's all. The Intent will not be delivered and onNewIntent() will not be called.
If you want the Intent to actually be delivered you need to specify:
start_test.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
It makes no difference whether the launchMode of the activity is singleTop or not, you still must specify Intent.FLAG_ACTIVITY_SINGLE_TOP in the Intent.
Note: If the activity is already running in a task and the activity is not on top of the activity stack in that task, the task will be brought to the foreground. That's all. The Intent will not be delivered. The only way to make this happen would be to add Intent.FLAG_ACTIVITY_CLEAR_TOP to the other 2 flags, but this may not be what you want to happen (depends on your specific scenario).
See my (still) open issue on Google code at http://code.google.com/p/android/issues/detail?id=17137
I just added the PendingIntent.FLAG_UPDATE_CURRENT flag to my pending intent, and it started working for me (skipped all flags for Intent).
Example Code:
PendingIntent pendIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
If not needed then avoid setting your activity in manifest as a single task. omit this line or change it to singleTop if you can:
android:launchMode="singleTask”
If you must have a single task then in pending intent set flags to :
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK
And PendingIntent.FLAG_CANCEL_CURRENT.
resultIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |Intent.FLAG_ACTIVITY_CLEAR_TASK);
pIntent = PendingIntent.getActivity(context, 0, resultIntent, PendingIntent.FLAG_CANCEL_CURRENT );
If you have a single task - Reset your extras in your activity inside onNewIntent() by setIntent(intent);
protected void onNewIntent(Intent intent) {
setIntent(intent);
...
}
You can send extras in intent following way
PendingIntent contentIntent ;
Intent intent = new Intent(this,TestActivity.class);
intent.putExtra("extra","Test");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(ArticleDetailedActivity.class);
contentIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
To Get Intent extra value in Test Activity class you need to write following code :
Intent intent = getIntent();
String extra = intent.getStringExtra("extra") ;
Simpler approach: the real problem is that the Intent, being to the same target, gets replaced. I've solved this by just created a new service, a "NotificationDismissalService". The only intent going to that service is the setDeleteIntent item. Because it's a unique service, the parameters do not get replaced. The body of NotificationDismissalService (and it would really be one such dismissal service per unique intent type) is a simple implementation of "onStartCommand" that sends an intent to the preferred service (reading/writing the correct parameters). Because that's an actual send of a service, without a pendingintent in between, it works just fine.
When app is not running or is in background and user clicks on Notification in tray, you can get Intent extra and check the keys:
#Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("RC","MainActivity.onCreate() called");
if (getIntent().getExtras() != null){
Bundle extra = getIntent().getExtras();
Log.d("RC", "MainActivity.onCreate() : keys count = " + extra.keySet().size());
for ( String key : extra.keySet()) {
Log.d("RC","MainActivity.onCreate() : key = " + key + " = " + extra.getString(key));
}
}
}
This will show:
D/RC: MainActivity.onCreate() called
D/RC: MainActivity.onCreate() : keys count = 8
D/RC: MainActivity.onCreate() : key = google.delivered_priority = high
D/RC: MainActivity.onCreate() : key = google.sent_time = null
D/RC: MainActivity.onCreate() : key = google.ttl = null
D/RC: MainActivity.onCreate() : key = google.original_priority = high
D/RC: MainActivity.onCreate() : key = from = 631131412302
D/RC: MainActivity.onCreate() : key = google.message_id = 0:1627370460932539%952b1da9952b1da9
D/RC: MainActivity.onCreate() : key = gcm.n.analytics_data = null
D/RC: MainActivity.onCreate() : key = collapse_key = com.reflectcode.demo.cloudmessaging
I have used something like this
Intent myIntent = new Intent(context, DoSomething.class);
PendingIntent pendingIntent = PendingIntent.getActivity(
context,
0,
myIntent,
Intent.FLAG_ACTIVITY_NEW_TASK);
Check out the full example here
I wrote a simple Android App that show a custom Notification like this:
Context context = getApplicationContext();
NotificationManager manager = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification = new Notification( R.drawable.icon, title, System.currentTimeMillis());
Intent notificationIntent = new Intent( context, this.getClass());
notificationIntent.putExtra("com.mysecure.lastpage", "SECURECODE");
PendingIntent pendingIntent = PendingIntent.getActivity( context , 0, notificationIntent, 0);
notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
notification.contentView = new RemoteViews(context.getPackageName(), R.layout.notifypbar);
notification.contentIntent = pendingIntent;
notification.contentView.setTextViewText(R.id.notifypb_status_text, text);
notification.contentView.setProgressBar(R.id.notifypb_status_progress, 100, (int)(100*progress), false);
manager.notify(104, notification);
This piece of code is called ONLY ONCE in my application and it displays a notification with a progress bar (all correctly).
Now, when a user clicks on this notification my application handles the onResume event.
public void onResume()
{
super.onResume();
// TODO: Extras è SEMPRE NULL!!! impossibile!
Intent callingintent = getIntent();
Bundle extras = callingintent.getExtras();
but extras is always NULL!
I've tried any combination of:
notificationIntent.putExtra("com.mysecure.lastpage", "SECURECODE");
or
Bundle extra = new Bundle();
extra.putString(key, value);
notificationIntent.putExtra(extra);
but getIntent().getExtras() returns always NULL.
This is the scenario:
The method getIntent() returns the FIRST intent than launch activity.
So, when the activity is CLOSED (terminated) and the user clicks on the notification, it will run a new instance of the activity and getIntent() works as expected (Extras is not null).
But if the activity is "sleeping" (it is in the background) and the user clicks on the notification, getIntent() always returns the very FIRST intent that started the activity and NOT the notification intent.
So to catch the notification intent while the application is running, simply use this
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
and then override onNewIntent(Intent newintent).
So when an application first runs, getIntent() can be used and when application is resumed from sleeping, onNewIntent works.
Just Write this code above your on top of your Resume() method. This is all it takes. This refreshes intent - I don't really know, but it works.
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
Problem: You are sending the same request code for your pending intens. Change this.
Solution: Set global variable int UNIQUE_INT_PER_CALL =0 and when you create pendingIntent call like below.
PendingIntent contentIntent = PendingIntent.getActivity(context, UNIQUE_INT_PER_CALL, notificationIntent, 0);
UNIQUE_INT_PER_CALL++; // to increment.
Since it seems your activity is already running, I think you need to specify FLAG_UPDATE_CURRENT, otherwise the getIntent() call will return the previous one. See this answer.
Look at Shared Preferences for passing and retrieving persistent key/value pairs.
I can find a way to send parameters to my activity from my notification.
I have a service that creates a notification. When the user clicks on the notification I want to open my main activity with some special parameters. E.g an item id, so my activity can load and present a special item detail view. More specific, I'm downloading a file, and when the file is downloaded I want the notification to have an intent that when clicked it opens my activity in a special mode. I have tried to use putExtra on my intent, but cant seem to extract it, so I think I'm doing it wrong.
Code from my service that creates the Notification:
// construct the Notification object.
final Notification notif = new Notification(R.drawable.icon, tickerText, System.currentTimeMillis());
final RemoteViews contentView = new RemoteViews(context.getPackageName(), R.layout.custom_notification_layout);
contentView.setImageViewResource(R.id.image, R.drawable.icon);
contentView.setTextViewText(R.id.text, tickerText);
contentView.setProgressBar(R.id.progress,100,0, false);
notif.contentView = contentView;
Intent notificationIntent = new Intent(context, Main.class);
notificationIntent.putExtra("item_id", "1001"); // <-- HERE I PUT THE EXTRA VALUE
PendingIntent contentIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
notif.contentIntent = contentIntent;
nm.notify(id, notif);
Code from my Activity that tries to fetch the extra parameter from the notification:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Bundle extras = getIntent().getExtras();
if(extras != null){
Log.i( "dd","Extra:" + extras.getString("item_id") );
}
The extras is always null and I never gets anything into my log.
Btw... the onCreate is only run when my activity starts, if my activity is already started I also want to collect the extras and present my activity according to the item_id I receive.
Any ideas?
Take a look at this guide (creating a notification) and to samples ApiDemos "StatusBarNotifications" and "NotificationDisplay".
For managing if the activity is already running you have two ways:
Add FLAG_ACTIVITY_SINGLE_TOP flag to the Intent when launching the activity, and then in the activity class implement onNewIntent(Intent intent) event handler, that way you can access the new intent that was called for the activity (which is not the same as just calling getIntent(), this will always return the first Intent that launched your activity.
Same as number one, but instead of adding a flag to the Intent you must add "singleTop" in your activity AndroidManifest.xml.
If you use intent extras, remeber to call PendingIntent.getActivity() with the flag PendingIntent.FLAG_UPDATE_CURRENT, otherwise the same extras will be reused for every notification.
I had the similar problem my application displays message notifications.
When there are multiple notifications and clicking each notification it displays that notification detail in a view message activity. I solved the problem of same extra parameters is being received in view message intent.
Here is the code which fixed this.
Code for creating the notification Intent.
Intent notificationIntent = new Intent(getApplicationContext(), viewmessage.class);
notificationIntent.putExtra("NotificationMessage", notificationMessage);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingNotificationIntent = PendingIntent.getActivity(getApplicationContext(),notificationIndex,notificationIntent,PendingIntent.FLAG_UPDATE_CURRENT);
notification.flags |= Notification.FLAG_AUTO_CANCEL;
notification.setLatestEventInfo(getApplicationContext(), notificationTitle, notificationMessage, pendingNotificationIntent);
Code for view Message Activity.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
onNewIntent(getIntent());
}
#Override
public void onNewIntent(Intent intent){
Bundle extras = intent.getExtras();
if(extras != null){
if(extras.containsKey("NotificationMessage"))
{
setContentView(R.layout.viewmain);
// extract the extra-data in the Notification
String msg = extras.getString("NotificationMessage");
txtView = (TextView) findViewById(R.id.txtMessage);
txtView.setText(msg);
}
}
}
Maybe a bit late, but:
instead of this:
public void onNewIntent(Intent intent){
Bundle extras = intent.getExtras();
Log.i( "dbg","onNewIntent");
if(extras != null){
Log.i( "dbg", "Extra6 bool: "+ extras.containsKey("net.dbg.android.fjol"));
Log.i( "dbg", "Extra6 val : "+ extras.getString("net.dbg.android.fjol"));
}
mTabsController.setActiveTab(TabsController.TAB_DOWNLOADS);
}
Use this:
Bundle extras = getIntent().getExtras();
if(extras !=null) {
String value = extras.getString("keyName");
}
Encounter same issue here.
I resolve it by using different request code, use same id as notification, while creating PendingIntent. but still don't know why this should be done.
PendingIntent contentIntent = PendingIntent.getActivity(context, **id**, notificationIntent, 0);
notif.contentIntent = contentIntent;
nm.notify(**id**, notif);
After reading some email-lists and other forums i found that the trick seems to add som unique data to the intent.
like this:
Intent notificationIntent = new Intent(Main.this, Main.class);
notificationIntent.putExtra("sport_id", "sport"+id);
notificationIntent.putExtra("game_url", "gameURL"+id);
notificationIntent.setData((Uri.parse("foobar://"+SystemClock.elapsedRealtime())));
I dont understand why this needs to be done, It got something to do with the intent cant be identified only by its extras...
I tried everything but nothing worked.
eventually came up with following solution.
1- in manifest add for the activity
android:launchMode="singleTop"
2- while making pending intent do the following, use bundle instead of directly using intent.putString() or intent.putInt()
Intent notificationIntent = new Intent(getApplicationContext(), CourseActivity.class);
Bundle bundle = new Bundle();
bundle.putString(Constants.EXAM_ID,String.valueOf(lectureDownloadStatus.getExamId()));
bundle.putInt(Constants.COURSE_ID,(int)lectureDownloadStatus.getCourseId());
bundle.putString(Constants.IMAGE_URL,lectureDownloadStatus.getImageUrl());
notificationIntent.putExtras(bundle);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(getApplicationContext(),
new Random().nextInt(), notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
AndroidManifest.xml
Include launchMode="singleTop"
<activity android:name=".MessagesDetailsActivity"
android:launchMode="singleTop"
android:excludeFromRecents="true"
/>
SMSReceiver.java
Set the flags for the Intent and PendingIntent
Intent intent = new Intent(context, MessagesDetailsActivity.class);
intent.putExtra("smsMsg", smsObject.getMsg());
intent.putExtra("smsAddress", smsObject.getAddress());
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent contentIntent = PendingIntent.getActivity(context, notification_id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
MessageDetailsActivity.java
onResume() - gets called everytime, load the extras.
Intent intent = getIntent();
String extraAddress = intent.getStringExtra("smsAddress");
String extraBody = intent.getStringExtra("smsMsg");
Hope it helps, it was based on other answers here on stackoverflow, but this is the most updated that worked for me.
It's easy,this is my solution using objects!
My POJO
public class Person implements Serializable{
private String name;
private int age;
//get & set
}
Method Notification
Person person = new Person();
person.setName("david hackro");
person.setAge(10);
Intent notificationIntent = new Intent(this, Person.class);
notificationIntent.putExtra("person",person);
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.notification_icon)
.setAutoCancel(true)
.setColor(getResources().getColor(R.color.ColorTipografiaAdeudos))
.setPriority(2)
.setLargeIcon(bm)
.setTicker(fotomulta.getTitle())
.setContentText(fotomulta.getMessage())
.setContentIntent(PendingIntent.getActivity(this, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT))
.setWhen(System.currentTimeMillis())
.setContentTitle(fotomulta.getTicketText())
.setDefaults(Notification.DEFAULT_ALL);
New Activity
private Person person;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_notification_push);
person = (Person) getIntent().getSerializableExtra("person");
}
Good Luck!!
In your notification implementation, use a code like this:
NotificationCompat.Builder nBuilder = new NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID);
...
Intent intent = new Intent(this, ExampleActivity.class);
intent.putExtra("EXTRA_KEY", "value");
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
nBuilder.setContentIntent(pendingIntent);
...
To Get Intent extra values in the ExampleActivity, use the following code:
...
Intent intent = getIntent();
if(intent!=null) {
String extraKey = intent.getStringExtra("EXTRA_KEY");
}
...
VERY IMPORTANT NOTE: the Intent::putExtra() method is an Overloaded one. To get the extra key, you need to use Intent::get[Type]Extra() method.
Note: NOTIFICATION_ID and NOTIFICATION_CHANNEL_ID are an constants declared in ExampleActivity
After doing some search i got solution from android developer guide
PendingIntent contentIntent ;
Intent intent = new Intent(this,TestActivity.class);
intent.putExtra("extra","Test");
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(ArticleDetailedActivity.class);
contentIntent = stackBuilder.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
To Get Intent extra value in Test Activity class you need to write following code :
Intent intent = getIntent();
String extra = intent.getStringExtra("extra") ;
Please use as PendingIntent while showing notification than it will be resolved.
PendingIntent intent = PendingIntent.getActivity(this, 0,
notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Add PendingIntent.FLAG_UPDATE_CURRENT as last field.
G'day,
I too can say that I tried everything mentioned in these posts and a few more from elsewhere.
The #1 problem for me was that the new Intent always had a null bundle.
My issue was in focusing too much on the details of "have I included .this or .that".
My solution was in taking a step back from the detail and looking at the overall structure of the notification. When I did that I managed to place the key parts of the code in the correct sequence.
So, if you're having similar issues check for:
1. Intent notificationIntent = new Intent(MainActivity.this, NotificationActivity.class);
2a. Bundle bundle = new Bundle();
//I like specifying the data type much better. eg bundle.putInt
2b. notificationIntent.putExtras(bundle);
3. PendingIntent contentIntent = PendingIntent.getActivity(MainActivity.this, WIZARD_NOTIFICATION_ID, notificationIntent,
PendingIntent.FLAG_UPDATE_CURRENT);
notificationIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
4. NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
5. NotificationCompat.Builder nBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_notify)
.setContentTitle(title)
.setContentText(content)
.setContentIntent(contentIntent)
.setDefaults(Notification.DEFAULT_SOUND | Notification.DEFAULT_VIBRATE)
.setAutoCancel(false)//false is standard. true == automatically removes the notification when the user taps it.
.setColor(getResources().getColor(R.color.colorPrimary))
.setCategory(Notification.CATEGORY_REMINDER)
.setPriority(Notification.PRIORITY_HIGH)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC);
notificationManager.notify(WIZARD_NOTIFICATION_ID, nBuilder.build());
With this sequence I get a valid bundle.
If you use
android:taskAffinity="myApp.widget.notify.activity"
android:excludeFromRecents="true"
in your AndroidManifest.xml file for the Activity to launch, you have to use the following in your intent:
Intent notificationClick = new Intent(context, NotifyActivity.class);
Bundle bdl = new Bundle();
bdl.putSerializable(NotifyActivity.Bundle_myItem, myItem);
notificationClick.putExtras(bdl);
notificationClick.setData(Uri.parse(notificationClick.toUri(Intent.URI_INTENT_SCHEME) + myItem.getId()));
notificationClick.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK); // schließt tasks der app und startet einen seperaten neuen
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
stackBuilder.addParentStack(NotifyActivity.class);
stackBuilder.addNextIntent(notificationClick);
PendingIntent notificationPendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(notificationPendingIntent);
Important is to set unique data e.g. using an unique id like:
notificationClick.setData(Uri.parse(notificationClick.toUri(Intent.URI_INTENT_SCHEME) + myItem.getId()));