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);
}
}
Related
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 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
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.
I am building a mono android app that receives notifications from GCM and opens an activity when then user clicks on the notification.
An issue is occurring when an instance of the activity the notification creates already exists and is the current active activity in the application. Upon clicking the notification a duplicate activity is created in the application. The issue is subtle as the new duplicate activity opens in the foreground and looks identical to previous activity, however when the user clicks the back button the duplicate activity is killed but the previous activity remains meaning the user has to click back button twice.
The following is current code used to generate notification and create an activity on click. I would hope the process would be something like, if activity exists then open existing activity else start new activity. Appreciate any help thank you.
void createNotification(string title, string desc)
{
//Create notification
var notificationManager = GetSystemService(Context.NotificationService) as NotificationManager;
//Create an intent to show ui
var uiIntent = new Intent(this, typeof(Messaging));
//Create the notification
var notification = new Notification(Android.Resource.Drawable.SymActionEmail, title);
notification.Defaults = NotificationDefaults.Sound;
//Auto cancel will remove the notification once the user touches it
notification.Flags = NotificationFlags.AutoCancel;
//Set the notification info
//we use the pending intent, passing our ui intent over which will get called
//when the notification is tapped.
notification.SetLatestEventInfo(this, title, desc, PendingIntent.GetActivity(this, 0, uiIntent, 0));
//Show the notification
notificationManager.Notify(1, notification);
}
Try this
Intent intent = new Intent(context, MyActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
startActivity(intent);
I have 3 Activities
A. MainActivity - just an Activity with a text and button on it
B. SettingsActivity - this will be displayed if the button on (A) is clicked, this initializes time picker that will send a notification when it alarms
C. DisplayNotification - activity for displaying notification in the status bar, when clicked, it should show A
This is what I want to happen:
I launch my application, A will be shown
I click the button, B will be shown
I set a time for the alarm
When the alarm triggers, a notification is shown in the status bar
If I click the notification, A will be shown
This is what happens (I have 2 scenarios with different results):
First scenario:
After step 3, I tap the back button, A will now be shown
Then, I tap again the back button, the onDestroy of A will be called and screen will show the 'home page' or 'desktop' of the phone
I wait till the alarm triggers
When the alarm triggers, notification is shown on the status bar
I click the notification, it launches my app displaying A
End of story. This is what is expected to happen
Second scenario: (the buggy one)
After step 3, I tap the HOME button, A's onDestroy is not yet called and the latest screen was B
The screen shows the 'home page' or 'desktop' of the phone
I wait till the alarm triggers
When the alarm triggers, notification is shown on the status bar AND B was shown automatically without me clicking the notification on the status bar
What I want to happen here is that it should not automatically display B activity.
Am I missing any flags for notification or intent?
Here is the code snippet for Activity B which triggers the alarm
AlarmManager alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
Intent i = new Intent(this, DisplayNotification.class);
i.putExtra("NotifID", 1);
PendingIntent displayIntent = PendingIntent.getActivity(getBaseContext(), 0, i, 0);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, displayIntent);
Here is the code for Activity C
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int notifID = getIntent().getExtras().getInt("NotifID");
Intent i = new Intent(this, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
i.putExtra("NotifID", notifID);
PendingIntent detailsIntent = PendingIntent.getActivity(this, 0, i, 0);
NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.ic_launcher, "See activity!", System.currentTimeMillis());
notif.flags |= Notification.FLAG_AUTO_CANCEL;
notif.defaults |= Notification.DEFAULT_SOUND;
CharSequence from = "Notification from me";
CharSequence message = "See activity!";
notif.setLatestEventInfo(this, from, message, detailsIntent);
nm.notify(notifID, notif);
finish();
}
I hope someone would help me :)
Thanks!
Edit:
Thanks Chirag_CID! I should have used Broadcast Receiver instead of another Activity. So, instead of extending Activity, the DisplayNotification now extends Broadcast Receiver. This is the onReceive method of DisplayNotification:
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "DisplayNotification onReceive");
int notifID = intent.getExtras().getInt("NotifID");
Intent i = new Intent(context, MainActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
i.putExtra("NotifID", notifID);
PendingIntent detailsIntent = PendingIntent.getActivity(context, 0, i, 0);
NotificationManager nm = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notif = new Notification(R.drawable.ic_launcher, "See the quote of the day!", System.currentTimeMillis());
notif.flags |= Notification.FLAG_AUTO_CANCEL;
notif.defaults |= Notification.DEFAULT_SOUND;
CharSequence from = "Notification";
CharSequence message = "See the activity!";
notif.setLatestEventInfo(context, from, message, detailsIntent);
nm.notify(notifID, notif);
}
I read the whole Question 2-3 times..
Now I want to point to few things up there,
You have made Activity C in which you are creating notification which will call MainActivity on it's Click.
But, When you set alarm from B you are passing intent of Activity C, Though your code of C doesn't have setContentView method, and Also you have written finish() in the end of onCreate() so when Activity C is called through the Alarm set from B, It just call Activity C and set Notification ..but As you written finish() it ends Activity C and shows Activity B latest from the Stack.
If You want to cross check..
Write logs in onCreate(),onPause() and onDestroy() of Activity C..and you will see the Activity C is created and Destroyed when Alarm triggered.
Solution:
If you don't want to show any activity when you are on Home Screen and Alarm trigger then,
In Activity B where you written pending intent for Activity C..You will need it to change to call the Broadcast Receiver and use PendingIntent.getBroadcast where its PendingIntent.getActivity and the code you have written in C for notification you will have to write that in Receiver...hence none of your activity will be called when the Alarm Trigger.
Happy Coding :)