Reputation: 41226
I'm trying to present a notification which is handled by a special activity which is not in the normal application flow, and trying to get the back stack handling "correct," meaning:
So far, the code I'm using to present the notification is:
/**
* Show (or update) a notification for the current message set.
*
* @param showNotification true to use a high priority notification which will be immediately
* displayed (as opposed to just added to the status bar)
*/
private void createOrUpdateNotification(boolean showNotification) {
Message oldest = messages.get(0);
Message newest = messages.get(messages.size() - 1);
// Create the notification
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
// Set notification data and appearance
.setContentTitle(title)
.setContentText(newest.message)
.setSmallIcon(smallIcon)
.setWhen(newest.when)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
// Set notification options
.setAutoCancel(true)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setPriority(showNotification ? NotificationCompat.PRIORITY_HIGH : NotificationCompat.PRIORITY_LOW)
.setDefaults(NotificationCompat.DEFAULT_VIBRATE)
.setOnlyAlertOnce(!showNotification);
// Set up the action if the first (oldest) message has an intent builder
if(oldest.intent != null) {
TaskStackBuilder stackBuilder = TaskStackBuilder.create(context.getApplicationContext());
stackBuilder.addNextIntent(oldest.intent);
builder.setContentIntent(stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT));
}
NotificationManagerCompat.from(context).notify(notificationId, builder.build());
Log.i("notification created");
}
For clarification, Message.intent
is a single intent, configured to open the notification handling activity.
My problem is that if the application is currently running and open when the notification is opened, the application is closed and the notification presented on an empty stack and the application's back stack is cleared out.
My understanding is that the desired behavior should be automatic if the content intent is a pending intent containing a single intent, which is the case here.
What am I missing?
Upvotes: 4
Views: 2632
Reputation: 41226
To expand a little bit on @leco's answer, my final solution had two parts.
The first is building the Notification
as he recommended, using a PendingIntent
directly instead of trying to use a TaskStackBuilder
:
builder.setContentIntent(
PendingIntent.getActivity(
context,
0,
oldest.intent,
PendingIntent.FLAG_UPDATE_CURRENT
));
This got me the correct behavior if the application was running, but not currently open (ie., up until the user hit back all the way out of the application)
To get the "correct" behavior at that point, I modified my Notification
handling Activity by overriding finish()
:
public void finish() {
if(isTaskRoot()) {
// If we're the task root, probably because we were launched from a notification with the
// application closed, we should just open the default activity
try {
String homeClassName = getPackageManager().queryIntentActivities(
new Intent(Intent.ACTION_MAIN).setPackage(getApplicationContext().getPackageName()),
0
).get(0).activityInfo.name;
Class homeClass = Class.forName(homeClassName);
getApplicationContext().startActivity(new Intent(getApplicationContext(), homeClass).setFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
}
catch(Exception exception) {
Log.w(String.format("Can't find the MAIN activity for package %s", getApplicationContext().getPackageName()));
}
}
super.finish();
}
The gyrations with queryIntentActivities
etc are due to the fact that I'm actually developing a drop-in component for applications, so I don't actually know what their root/home/launch activity actually is. I tried a simpler approach of just building a HOME intent:
startActivity(new Intent(Intent.ACTION_MAIN).setPackage(getApplicationContext().getPackageName())
but for some reason startActivity
was throwing an exception:
android.content.ActivityNotFoundException: No Activity found to handle Intent
even though the queryIntentActivities
approach demonstrates that there is an appropriate Activity
for the Intent
.
Upvotes: 1
Reputation: 81
Create a Queue of Bundle and keep adding and removing Bundle Objects from the queue as per your requirement.
/**
* Queue that holds notifications messages
*/
private Queue<Bundle> mNotificationQueue = new LinkedList<Bundle>();
/**
* Method returning the singleton queue maintained in a static class
*/
public Queue<Bundle> getNotificationQueue() {
return mNotificationQueue;
}
Now when the Notification is received add the notification message to the queue
// Fetching the message from intent and adding in bundle to add in the queue
Bundle notificationMsgBundle = intent.getExtras();
notificationMsgBundle.getString(MyConstants.KEY_CHANNEL) + " :: " + notificationMsgBundle.getString(MyConstants.KEY_DATA));
DataManager.getInstance().getmNotificationQueue().add(notificationMsgBundle)
Now this static queue is maintained throughout the application and you can remove or add messages from the queue
// removing the node message in the queue as per requirement
DataManager.getInstance().getmNotificationQueue().remove();
Upvotes: 0
Reputation: 3571
TaskStackBuilder.create will launch a fresh task stack.
Set the content intent like this instead:
builder.setContentIntent(
PendingIntent.getActivity(
context,
0,
oldest.intent,
PendingIntent.FLAG_UPDATE_CURRENT
));
Upvotes: 1