I have the following code for dispatching a notification...
private void publishNotification(Intent intent, String header, String content){
try {
NotificationManager manager = getNotificationManager();
Notification notification = new Notification(R.drawable.droid, header, System.currentTimeMillis());
if(intent != null){
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, Intent.FLAG_ACTIVITY_NEW_TASK);
notification.setLatestEventInfo(this, header, content, pendingIntent);
}
manager.notify(0, notification);
} catch (Exception ex) {
FileManager.writeToLogFile(this.getClass(), "publishNotification", LogMessageType.ERROR, ex.getMessage());
}
}
And the following code that calls on it...
Intent intent = new Intent();
intent.setAction(DevicePolicyManager.ACTION_SET_NEW_PASSWORD);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
publishNotification(intent, "Default Password Changed", "Device configuration have changed.\nClick here to change this password.");
My problem is as follows...
The notification appears on the notification and even after it is slid down. The problem is that when I click on this notification, the activity does not launch. I think I have done everything mentioned in the tutorial. What am I doing wrong ?
If you want to launch an activity, you should use PendingIntent.getActivity() instead of PendingIntent.getService().
Intent intent = new Intent(context, class_name.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
and also use PendingIntent.getActivity() instead of PendingIntent.getService().
Related
I'm trying to create an notification to launch an Activity with extra information. However, currently it is not working.
Here is the code for creating the notification
private void showNotification(RemoteMessage remoteMessage){
try{
// Create an explicit intent for an Activity in your app
Intent i = new Intent(getBaseContext(), MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
i.putExtra(EXTRA_MESSAGE,remoteMessage);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i, 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_action_name)
.setContentTitle("Title")
.setContentText("Content")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setAutoCancel(true)
// Set the intent that will fire when the user taps the notification
.setFullScreenIntent(pendingIntent, true);
// notificationId is a unique int for each notification that you must define
notificationId++;
//https://developer.android.com/training/notify-user/time-sensitive
// Provide a unique integer for the "notificationId" of each notification.
startForeground(notificationId, builder.build());
}catch (Exception e){
Log.d(TAG, e.getMessage());
}
}
The Activity is launching after clicking the notification. However, inside the onCreate of the Activity when checking for the extra in the bundle it doesn't find it:
EDIT: Actually what I want is for the activity to show without the user having to click anything hence why I am using setFullScreenIntent.
if(bundle!=null && bundle.containsKey(CustomFirebaseMessagingService.EXTRA_MESSAGE)){
Log.d(TAG, "MainActivity has extra message");
}else{
Log.d(TAG, "MainActivity doesn't have extra message");
}
My logs say
MainActivity doesn't have extra message
Try
setContentIntent(pendingIntent)
Since you want an intent that will fire on the notification click, the docs for this method says:
Supply a PendingIntent to send when the notification is clicked.
You need to set the flag FLAG_UPDATE_CURRENT when creating the PendingIntent:
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, i,
PendingIntent.FLAG_UPDATE_CURRENT);
This will ensure that your "extras" are actually added to the PendingIntent.
I created a NotificationListenerService to play a sound once a I receive PUSH notification. But the NotificationListenerService informs me about any Notification occured system-wide, and
what i am trying to do is, to restrict the behaviour of the NotificationListenerService so that to respond to notifications posted from my App only. In other words, the callback onNotificationPostedPosted
in the below posted code in NLS section, is getting called even if I plug the USB cable to the device and the code in that callback executes, and I want the code in
`onNotificationPostedPosted' to be executed only when my App send a notification.
To solve this issue, as shown in the code below, I added extra to my Intent as follows:
intent.putExtra("key_message", "MANT-App");
The problem I have no is, that I can not have access to that intent in `onNotificationPostedPosted'.
Please let me know how to get/access the Intentor the PendingIntent in `onNotificationPostedPosted'?
code:
Intent intent = new Intent(getApplicationContext(), HomeActivity_.class);
intent.putExtra("key_message", "MANT-App");
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
String title = getString(R.string.app_name);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_launcher);
builder.setStyle(new NotificationCompat.BigTextStyle().bigText(msg)).setContentText(msg).setContentTitle(title);
builder.setContentIntent(contentIntent).setAutoCancel(true);
builder.setLights(Color.argb(1, 255, 0, 0), 400, 1300);
builder.setOngoing(true);
builder.setAutoCancel(true);
((NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE)).notify(NOTIFICATION_ID, builder.build());
NLS
#Override
public void onNotificationPosted(StatusBarNotification sbn) {
super.onNotificationPosted(sbn);
Log.w(TAG, "onNotificationPosted");
Log.d(TAG, "sbn.describeContents(): " + sbn.describeContents());
Log.d(TAG, "getNotification().contentIntent.describeContents(): " + sbn.getNotification().contentIntent.describeContents());
Message msg = handler.obtainMessage();
msg.obj = "onNotificationPosted";
handler.sendMessage(msg);
mNotificationRemoved = false;
if (!NLSNotificationTone11.TONE_IS_PLAYING) {
NLSNotificationTone11.TONE_IS_PLAYING = true;
new ThreadPlayTone(this, NLSNotificationTone11.DURATION_OF_RING_TONE).start();
}
}
PendingIntent pendingIntent = statusBarNotification.getNotification().contentIntent
use this method to get PendingIntent for API level 18 & Higher in NotificationListener Class
Please let me know how to get/access the Intent or the PendingIntent in
onNotificationPosted()?
You can't. You can send the PendingIntent, but you cannot examine it.
However, you can get the package name of the package posting the Notification, so that would be a way to ignore all notifications except ones from your own app.
In onNotificationPosted(StatusBarNotification sbn):
if (sbn.getPackageName().equals("my.package.name")) {
// do stuff
}
EDIT: It looks like you can get the Intent from a PendingIntent using reflection starting with Android 4.2.2. Do it like this:
PendingIntent pendingIntent = ... // PendingIntent
try {
Method method = PendingIntent.class.getDeclaredMethod("getIntent");
method.setAccessible(true);
Intent intent = method.invoke(pendingIntent);
// Here you should have the Intent that is wrapped by the PendingIntent.
// You should be able to access the component name, extras,
// flags, etc. in the Intent
} catch (Exception e) {
// Problem using reflection
}
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
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.
Unfortunately, I was unable to find a resolution to this issue in other StackOverflow posts so I apologize in advance for re-posting this question. Essentially, I have an AppWidget that creates a Notification. I want the user to click the Notification to launch an Activity. The AppWidget and Activity are in the same APK.
The following code is all in the AppWidget. Clicking on the Notification broadcasts a custom Intent which is received by the AppWidget.
The problem is that the Activity does not appear to launch, even though logcat demonstrates that the custom Intent has indeed been broadcast. The only clue is the logcat message reiterated in the post title.
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Constants.BROWSER_INTENT)) {
launchActivity(context, R.layout.appwidget, R.id.launch_button, Activity.class);
}
super.onReceive(context, intent);
}
private void displayNotification(Context context, String ticker, String title, String msg) {
Intent intent = new Intent(context, ThisWidget.class);
intent.setAction(Constants.BROWSER_INTENT);
PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.icon, ticker, System.currentTimeMillis());
notification.setLatestEventInfo(context, title, msg, pending);
notificationManager.notify(1, notification);
}
Some notes:
Pressing a button to execute launchActivity() works (it launches the
Activity)
launchActivity uses Intent.FLAG_ACTIVITY_NEW_TASK as
recommended by Android lifecycle documentation
Has anyone solved this issue when launching an Activity from a Notification press?
er, figures, I answered my own question just minutes after posting it. I guess I was over-complicating the implementation by using an Intent action. I changed these lines:
Intent intent = new Intent(context, ThisWidget.class);
intent.setAction(Constants.BROWSER_INTENT);
PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);
to this:
Intent intent = new Intent(context, Activity.class);
PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);
and it worked.
Sorry for the bogus post.