I am developing an app with a minimum SDK of 15 and target SDK of 29. The app has a series of activities (a list, a detail, a list, a detail, etc.) that the user can navigate through as they deep-dive into their database of information. In the fourth activity, the user has the option of setting an alarm as a reminder.
Currently, the alarm is set and fires off on the given day. However, when you click on the notification, the taskStack is not formed correctly because the extras are not included for the top level of the intent.
To create the notification, I have the following code in CourseDetailActivity:
if(canSetAlarm(when)) {
String notificationIdString = notificationIdPrefix + courseId;
int notificationId = Integer.parseInt(notificationIdString);
long notificationWhen = getNotificationTime(when);
PendingIntent pendingIntentForContent = createPendingIntentForThisCourse(courseId);
Intent intent = new Intent(CourseDetailActivity.this, MyReceiver.class);
intent.putExtra(NOTIFICATION_CHANNEL_ID_KEY, getString(R.string.course_tracker_notification_channel_id));
intent.putExtra(NOTIFICATION_ID, notificationId);
intent.putExtra(NOTIFICATION_TITLE_KEY, title);
intent.putExtra(NOTIFICATION_TEXT_KEY, message);
intent.putExtra(NOTIFICATION_PENDING_INTENT_KEY, pendingIntentForContent);
PendingIntent pendingIntentForBroadcast = PendingIntent
.getBroadcast(this, notificationId, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, notificationWhen, pendingIntentForBroadcast);
} else {
showToast("Alarms cannot be set for today or dates in the past.");
}
}```
This utilizes the helper method below, also in CourseDetailActivity:
``` private PendingIntent createPendingIntentForThisCourse(int courseId) {
int termId = getIntent().getExtras().getInt(TERM_ID_KEY);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
Intent mainIntent = new Intent(getApplicationContext(), MainActivity.class);
stackBuilder.addNextIntent(mainIntent);
Intent termDetailIntent = new Intent(getApplicationContext(), TermDetailActivity.class);
termDetailIntent.putExtra(TERM_ID_KEY, termId);
stackBuilder.addNextIntent(termDetailIntent);
Intent courseListIntent = new Intent(getApplicationContext(), CourseListActivity.class);
courseListIntent.putExtra(TERM_ID_KEY, termId);
stackBuilder.addNextIntent(courseListIntent);
Intent courseDetailIntent = new Intent(getApplicationContext(), CourseDetailActivity.class);
courseDetailIntent.putExtra(TERM_ID_KEY, termId);
courseDetailIntent.putExtra(COURSE_ID_KEY, courseId);
courseDetailIntent.setAction("foo_action");
stackBuilder.addNextIntent(courseDetailIntent);
PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(courseId, PendingIntent.FLAG_UPDATE_CURRENT);
return resultPendingIntent;
}
MyReceiver class has the following onReceive method:
Log.i(LOG_TAG, "onReceive: ");
String channel_id = intent.getStringExtra(NOTIFICATION_CHANNEL_ID_KEY);
int notificationId = intent.getIntExtra(NOTIFICATION_ID, 0);
String title = intent.getStringExtra(NOTIFICATION_TITLE_KEY);
String text = intent.getStringExtra(NOTIFICATION_TEXT_KEY);
PendingIntent pendingIntent = intent.getParcelableExtra(NOTIFICATION_PENDING_INTENT_KEY);
Toast.makeText(context, text + " (Notification ID " + notificationId + ")", Toast.LENGTH_LONG).show();
Notification notification = new NotificationCompat.Builder(context, channel_id)
.setSmallIcon(R.drawable.ic_alarm_notification)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentTitle(title)
.setContentText(text)
.setStyle(new NotificationCompat.BigTextStyle().bigText(text))
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationId, notification);
}
Quite by accident, I discovered that the extras for all other intents in the stack are being passed. It is ONLY the extras for the TOP stack that are not being passed (and therefore, the viewModel for the activity doesn't know which data to pull from the database to display.
I have scoured stackOverflow for hours and now days to now avail. I have tried to change the flags on the pendingIntent and on the Intent themselves. I tried to add a dummy action as suggested in another post. I've added a unique identifier as the request code for the intentToBroadcast. Nothing seems to have worked.
This code works on newer APIs; however, I am struggling to get it to work on API level 15.
I would very much appreciate any guidance you could give.
My problems are hopefully related to each other. I run a countdown timer service that fires an intent in the onfinish method. When on finish completes it automatically opens/ bring the app up which I don't want it to do. why is this so? id like it to just show the notification. Also when I click on the notification instead of just resuming the activity it creates another one. I figured the problems were related to each other due to the intents. here is the code
from onFinish() not from the notification
Intent intent = new Intent(BroadcastService.this, MainActivity.class);
intent.putExtra("id1",id1);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
and here is the code for the notification
NotificationCompat.Builder notificBuilder = new NotificationCompat.Builder(this);
notificBuilder.setContentTitle("Loot");
notificBuilder.setContentText("Claim your Gold now!");
notificBuilder.setSmallIcon(R.drawable.gold2);
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
notificBuilder.setSound(soundUri);
notificBuilder.setAutoCancel(true);
Intent backhome = new Intent(this, MainActivity.class);
backhome.putExtra("id2",id2);
TaskStackBuilder taskStackBuilder = TaskStackBuilder.create(this);
taskStackBuilder.addParentStack(MainActivity.class);
taskStackBuilder.addNextIntent(backhome);
PendingIntent pd = taskStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
notificBuilder.setContentIntent(pd);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notifID, notificBuilder.build());
isNoteActive = true;
}
If you don't want to open your MainActivity, then you shouldn't write this code:
Intent intent = new Intent(BroadcastService.this, MainActivity.class);
...
startActivity(intent);
Opening MainActivity is exactly what this does.
In my application I have a notification to show.
Let's say when notification is show I want press 'Yes' to go an Activity and hide notification, press 'No' do nothing just hide notification.
I tried this code but instead of onclick is onClckPendingIntent and I can't do anything that I want.
NotificationManager mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.custom_push_layout);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContent(remoteViews)
.setAutoCancel(true);
Intent intent = new Intent(this,GPSTrackingActivity.class);
final Intent yesIntent = new Intent(intent);
final Intent noIntent = new Intent(this, GPSTrackingActivity.class);
TaskStackBuilder yesStackBuilder = TaskStackBuilder.create(this);
yesStackBuilder.addParentStack(MainActivity.class);
yesStackBuilder.addNextIntent(yesIntent);
TaskStackBuilder noStackBuilder = TaskStackBuilder.create(this);
noStackBuilder.addParentStack(MainActivity.class);
noStackBuilder.addNextIntent(noIntent);
PendingIntent yesPendingIntent = yesStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
PendingIntent noPendingIntent = noStackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.btn_yes, yesPendingIntent);
remoteViews.setOnClickPendingIntent(R.id.btn_no, noPendingIntent);
mNotificationManager.notify(100, mBuilder.build());
How could I do this ?
I know it's kinda late, but I managed to get things done via receiver.
you should:
create a receiver
create two intents to the receiver -
String SHOULD_OPEN = "should_open_intent"
Intent yes = new Intent(this, MyReceiver.class);
yes.putBooleanExtra(SHOULD_OPEN, true);
and same on Intent "no"
wrap them with PendingIntent
in you receiver, at the function "onReceive" get that data out using intent.getBooleanExtra(SHOUOLD_OPEN, DEFAULT_VALUE_DOESNT_MATTER)
and handle it accordingly
check this out -
https://stackoverflow.com/a/26486425/3339597
I have problem my MainActivity can be created by 3 ways:
1) standart launch App
2) from Service
3) from notification click.
How I can check when it starts from notification click?
Notification code:
private void createNotification()
{
Log.d("service createNotification",MainActivity.TAG);
Context context = getApplicationContext();
Intent notificationIntent = new Intent(this,MainActivity.class);
intent.putExtra(AppNames.IS_NOTIFICATION_INTENT,true);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
notificationIntent, Intent.FLAG_ACTIVITY_NEW_TASK);
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setContentTitle(this.getString(R.string.notification_title))
.setContentText(this.getString(R.string.notification_text))
.setContentIntent(pendingIntent)
.setSmallIcon(R.drawable.ic_launcher);
getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(AppNames.APP_NOTIFICATION, builder.getNotification());
}
add
intent.putExtra("started_from","notification");
to the code that starts the intent from the notifications, and the same thing to the other startActivity calls just change the value, then inside your activity
String startedFrom = getIntent().getStringExtra("started_from");
for more refer to this question: How do I get extra data from intent on Android?
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()));