I'm able to queue and launch notifications through AlarmManager, I'm also able to launch my application when clicking the notification. Unfortunately the notification isn't removing itself when the application is launched.
Notification setup:
Intent intent = new Intent(mainActivity, NotificationPublisher.class);
intent.setAction("handle");
PendingIntent pIntent = PendingIntent.getBroadcast(mainActivity, 0, intent,
PendingIntent.FLAG_CANCEL_CURRENT);
Notification.Builder builder = new Notification.Builder(mainActivity)
.setSmallIcon(R.drawable.phone)
.setContentTitle(title)
.setContentText(textContent)
.setAutoCancel(true)
.setContentIntent(pIntent);
return builder.getNotification();
The notification click broadcasts and hits this function:
void handle(Context context, Intent intent) {
System.out.println("handle");
Context mainContext = Extension.mainContext;
Activity mainActivity = Extension.mainActivity;
Intent launchIntent = new Intent(mainContext, mainActivity.getClass());
launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(launchIntent);
}
The handle function will launch the activity but not remove the notification from the status bar. Interestingly... If I remove the call to startActivity, the notification will close.
Things I've tried:
Setting the auto cancel flag manually
Using the builder.build() instead
NotificationManger cancel(id) and/or cancelAll
Using NotificationCompat.Builder
Using a regular launch intent for the setContentIntent instead of manually calling startActivity
Based on this statement from your question:
Interestingly... If I remove the call to startActivity, the
notification will close.
I'm assuming that your Activity is just reposting the Notification.
I worked around this by launching my App 300ms after clicking the notification.
Related
I'm using single activity architecture in my app. Now I'm stuck with handing notifications. I'm receiving notification from firebase and when app is on background, the google play services handle such notifications great. When it's tapped it brings the app from background to foreground (it does't recreate activity / app).
I need to have the same behaviour for notification received while the app is on foreground. Therefore I override onMessageReceived() in my firebase service and create new notification here. I tried many variation of Intent's Flags passed to the notification and launchMode in manifest but it always results into activity recreation (activity has different hashcode and it's onCreate() it's called) after tapping on notification created by onMessageReceived().
Here is the code:
#Override
public void onMessageReceived(#NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Logger.d("Msg received " + remoteMessage.getNotification().getTitle());
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Notification notification = new NotificationCompat.Builder(this, FCM_CHANNEL_ID)
.setContentTitle(remoteMessage.getNotification().getTitle())
.setContentText(remoteMessage.getNotification().getBody())
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setAutoCancel(true)
.setStyle(new NotificationCompat.BigTextStyle().bigText(remoteMessage.getNotification().getBody()))
.build();
NotificationManagerCompat manager = NotificationManagerCompat.from(getApplicationContext());
manager.notify(FCM_NOTIFICATION_ID, notification);
}
manifest: android:launchMode="singleTask"
Any idea what to change to prevent activity recreation? (I'm testing on android 10, MainActivity extends AppCompatActivity)
Thanks.
Finally I get it work. All magic was done by adding those two lines to my code.
intent.setAction(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_LAUNCHER);
Original answer
Did you try this?
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Use the
Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK flags.
This will start activity as the root of the stack.
I have an App that responds to Firebase messages, posts a notification on the device, and when the notification is tapped by the user is supposed to relaunch the App with the tidbit of info that came with the Firebase message (it's a single < 20 char String).
// In response to onMessageReceived() in a FirebaseMessagingService object...
// 1. create the intent to bundle with the notification and add custom data
Context appContext = this.getApplicationContext();
Intent intent = new Intent(appContext, MainActivity.class);
intent.putExtra("myData",myData); // myData is a simple string passed from FCM - verified it's correct
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP); // per docs/StackOverflow
intent.setAction(Intent.ACTION_VIEW);
// 2. package as a one shot pending intent that is fired when the user taps it in system notification list
int requestCode = (int) System.currentTimeMillis();
PendingIntent pendingIntent =
PendingIntent.getActivity(myActivity, requestCode, intent,
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); // tried with/without FLAG_UPDATE_CURRENT
// 3. build a notification around launching the intent
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(appContext)
.setSmallIcon(R.drawable.mylogo)
.setContentTitle(messageTitle)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setContentIntent(pendingIntent);
// 4. send notification to the system
NotificationManager notificationManager =
(NotificationManager) appContext.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify((int) System.currentTimeMillis(), notificationBuilder.build());
The Firebase message is received and the notification is successfully sent to the system notification service. When the user taps the notification, the app is brought to the forground but with the same Intent as was originally passed to the app - ie. without myData bundled with the intent. I've tried retrieve the intent in onResume and onCreate and the results are the same - it's missing the data bunlded with the notification.
// Back in the Main activity
Intent intent = this.getIntent();
String myData = intent.getStringExtra("myData"); // always null
doAction(myData); // fails because myData always null
I've been combing StackOverflow and the net for answers and so far I've tried lots of variations but the results are the same - myData is never forwarded.
I am not sure how you are receiving new Intent. You can try onNewIntent().
Lot of this depends on how you have setup your activity in manifest.
If same instance of the activity is brought to front, new intent will be delivered in onNewIntent().
Hope this helps.
I am working on an functionality where I get notification for POI (Point of Interest )while the user is navigating through Google Navigation app (used background service to get location update ).
scenario
1) User clicks navigate button from my app
2) He is taken to Google Navigation with data to navigate
3) Now user receives Notification for POI , then he clicks on it and he is taken to my app (my app brought to foreground , still Google Navigation i in background)
4) Now user is seeing my app , now he clicks the same notification , In this case I must put my app to background , so that use now sees Google Navigation
what i tried
Bringing my app to foreground is achieved , but putting my app to background on Notification click is not achieved .
moveTaskToBack(true) this is what I came across, but how can I implement this in Notification click
code
Intent intent = new Intent();
intent.setComponent(new ComponentName(getPackageName(), B_Activity.class.getName()));
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.putExtra("toFront", toFront);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
moveTaskToBack(boolean bool) is a method Of Activity class . So you can only call it with activity reference. I don't thing that there is way to do it with intent . What you can do send a broadcast in notification intent, and then validate the intent in activity if its in foreground -> call movetaskBack().
If your B_Activity has no Ui . Then just set null component in Pending Intent.
Use Local Broadcast to notify your currently running activity to call moveTaskToBack().
Intent intent = new Intent();
intent.setAction("com.settaskback");//Your custom action goes here
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
Then send broadcast on notification click. The activity which will receive this broadcast will put task to background (only if its in forground)
final Intent broadcastIntent = new Intent("com.settaskback");
PendingIntent intent = PendingIntent.getBroadcast(getApplicationContext(), 0, broadcastIntent, PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setContentIntent(intent);
notification = notificationBuilder.build();
notification.flags |= Notification.FLAG_AUTO_CANCEL;
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotificationManager.notify(1, notification);
You need to register a Local broadcast receiver for this action in Activity.
#Override
public void onReceive(Context context, Intent intent) {
if(somecondition){
moveTaskToBack(true);
}
}
I have the method
private Notification getNotification() {
Activity currentActivity = MyApplication.getApplication().getCurrentActivity();
Intent i = new Intent(currentActivity, SpeechActivationService.class);
i.putExtra(ACTIVATION_STOP_INTENT_KEY, true);
PendingIntent resultPendingIntent = PendingIntent.getActivity(currentActivity, 0, i, PendingIntent.FLAG_UPDATE_CURRENT);
NotificationCompat.Action action = new NotificationCompat.Action(R.drawable.ic_mic_off, "Deactivate", resultPendingIntent);
Notification notification = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_mic)
.setTicker("TickerSample")
.setWhen(System.currentTimeMillis())
.setContentTitle("My App Voice Control")
.setContentText("Voice Control is Activated")
.addAction(action)
.build();
return notification;
}
It is supposed to make a notification which stays active for as long as the service is active. The notification has a DEACTIVATE Button, which can send an Intent, wrapped in a Pending Intent (whatever the difference is?!). It seems Intents are the only form of Action a notification can take for handling Button clicks, so I can't just do
stopService(new Intent(this, SpeechActivationService.class));
on that DEACTIVATE. But with my code onStartCommand() in SpeechActivationService never gets called when I click on DEACTIVATE. And Services don't inherit an onNewIntent() method. So what method gets called when I send this intent by pressing DEACTIVATE?
So what method gets called when I send this intent by pressing DEACTIVATE?
Nothing will. You are attempting to use a getActivity() PendingIntent with an Intent that points to a service. This will not work, and you should be getting messages in LogCat to that effect.
If you change getActivity() to getService(), then onStartCommand() of your service should be called.
Pending intents is ment to be used for controlling stuff outide of your app (system features use those). For stopping service create BroadcastReceiver, which will receive pending intent (PendingIntent.getBroadcast()), which, in turn, will stop your Service
Wasn't really sure how to search for this...
I have a the following which is called whenever a job is added or removed from my queue to put a notification in the status bar:
private void showNotification()
{
int jobsize = mJobQueue.size();
int icon = (jobsize == 0) ?
android.R.drawable.stat_sys_upload_done :
android.R.drawable.stat_sys_upload;
Notification notification =
new Notification(icon, "Test", System.currentTimeMillis());
Intent intent = new Intent(this, FileManagerActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, 0);
notification.flags =
(Notification.FLAG_SHOW_LIGHTS | Notification.FLAG_AUTO_CANCEL);
notification.setLatestEventInfo(this,
"Uploading to our servers",
getString((jobsize > 0) ?
R.string.notification_active_transfers :
R.string.notification_no_transfers),
pendingIntent);
mNotifyManager.notify(NOTIFICATION, notification);
}
As it is now the behavior is this:
if the user logs out and hits the notification, it will still open a new FileManagerActivity (ops!) I could get around this by starting at my authentication activity and passing the intent up my stack in a natural order, its when the application is already running is where I have difficulties.
if the user already has the FileManagerActivity open clicking the notification will put a second instance over it. In this case, I want the currently running FileManagerActivity to recieve focus instead of launching a new instance.
How could I get the correct behavior?
I've done this before by setting my Activity to use the launch mode 'singleTop' in the Application Manifest. It will achieve the desired function, using the existing activity if one exists. In this case, onNewIntent will be called in your activity.
You'll need to check in your FileManagerActivity for authentication and start a new activity as appropriate if the user is not logged in.
I think Worked when added these:
intent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent.FLAG_UPDATE_CUR
Intent intent = new Intent(context, MyOwnActivity.class);
intent.putExtra("foo_bar_extra_key", "foo_bar_extra_value");
intent.setAction(Long.toString(System.currentTimeMillis()));
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,intent,PendingIntent.FLAG_UPDATE_CURRENT);