I am using an external library in our project. That library showing notification. On tapping that notification starts activity in the library.
I want to detect that activity launch from push notification to track some analytics data.
Is there any way to detect those notification taps or activity launch?
As far as I understand you activity is already launched on notification tap. For detecting activity launch you can use ActivityLifecycleCallbacks. In such case you will need to override onActivityCreated/onActivityStarted which includes created/started activity as argument. You can inject analytics component inside and send events about launched activities.
class AppLifecycleCallbacks : ActivityLifecycleCallbacks {
override fun onActivityStarted(activity: Activity) {
if (activity is MyActivity) {
//...
}
}
//...
}
Pass some extra meta data along with your pending intent generated for showing notification. And parse same in your destination activity.
Intent destination = new Intent(context, HomeActivity.class);
destination.putExtra("SOURCE","NOTIFICATION");
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, destination, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(context)
.setContentTitle("Notification Title")
.setAutoCancel(true)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setContentIntent(pendingIntent)
.setContentInfo("App")
.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher))
.setColor(context.getColor(R.color.colorAccent))
.setLights(Color.RED, 1000, 300)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setSmallIcon(R.drawable.ic_like);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, notificationBuilder.build());
And in activity level :
if(getIntent().getStringExtra("SOURCE").equals("NOTIFICATION")){
// launched from notification
}
If your activity is already running your intent might get delivered to :
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
Of course, yes. When you create Intent for launching your target activity you can pass arguments to the intent and when Activity starts just obtain outer arguments from intent and if these arguments came from Notification do your actions need.
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.
My app has one activity and one service. The service starts a foreground notification that has an action button that in some situations needs to tell the activity to do something besides just coming back to the front. It uses the Extras to indicate this something.
My issues are that I can't find any documentation on how to receive explicit intents other than through the "bundle" passed to onCreate() which isn't usually called because the activity could already be created.
How do you receive an intent after onCreate()?
Notification code snippet:
val actionIntent = Intent(this, MainActivity::class.java)
actionIntent.action = actionText
actionIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_CLEAR_TOP
val pendingActionIntent: PendingIntent = PendingIntent.getActivity(this, 0, actionIntent, 0)
val actionCancel: NotificationCompat.Action = NotificationCompat.Action.Builder(R.drawable.ic_cancel_black_24dp,
actionText,
pendingActionIntent).build()
val notificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID)
.setContentTitle(getText(R.string.notification_title))
.setSmallIcon(R.drawable.ic_logo_24dp)
.setContentIntent(pendingIntent)
.setOnlyAlertOnce(true)
.addAction(actionCancel)
.setContentText(text)
startForeground(ONGOING_NOTIFICATION_ID, notificationBuilder.build())
Override onNewIntent(). If the activity already exists, and an Intent is bringing it back to the foreground, that Intent is delivered to onNewIntent().
I have a notification and when I tap it I want to launch application if it is still not running, but if application already running, I do not want to relaunch it.
So, I am using PendingIntent.FLAG_UPDATE_CURRENT flag when creating PendingIntent.
My code:
private val notificationManager by lazy { NotificationManagerCompat.from(this) }
fun testPush() {
val notificationBuilder = NotificationCompat.Builder(this, BuildConfig.APPLICATION_ID)
.setSmallIcon(R.drawable.ill_launcher)
notificationBuilder
.setContentTitle("Title")
.setContentText("Test text")
.setContentIntent(buildPendingIntent())
notificationBuilder
.setAutoCancel(true)
.priority = NotificationCompat.PRIORITY_DEFAULT
notificationManager.notify(1, notificationBuilder.build())
}
private fun buildPendingIntent(): PendingIntent {
val intent = Intent(this, RootActivity::class.java)
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
intent.putExtra("action", RootActivity.DEFAULT_INTENT)
return PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
}
But when I launch the application and click on the notification, the activity is recreates.
Instead of building the Intent for RootActivity like you are doing, you need to create a "launch Intent" for your application. The easiest way to do this is to call PackageManager.getLaunchIntentForPackage() and pass your own package name. Use the returned Intent in the call to PendingIntent.getActivity().
This will launch your app if it isn't running, otherwise, if it is already running, it will just bring the existing task containing your app to the foreground.
I have MainActivity which I want to open when user clicks on a notification.
My code is below.
Manifest.xml:
<activity android:name=".activity.MainActivity"></activity>
Notification code:
private void sendNotification(String title, String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(0, notificationBuilder.build());
}
I want to know:
Which overridden method is called when my app is closed and I click on a notification?
Which overridden method is called when my app is running and I click on a notification?
Good Monday Morning!
It's actually a bit more complex: when your notification is clicked, the pending Intent you created is executed and, as a result, the activity which was assigned in your notification (in your case the MainActivity)
So the activity starts as a normal activity and if you need to pass some parameters, just add extra to the Intent before transforming it in a Pending Intent
OnMessage will always get called whenever notification came to mobile, even if app is closed or running or in background.
protected override void OnMessage(Context context, Intent intent) {
// Your code here
}
Is it possible not launch new activity if we receive a push notification while the app is running?
My activity works with fragments and I want to do transition to a determinate fragment when the notification is received. My activity have data that I need to show the fragments. The problem is that when I receive the push notification while the app is running the method onDestroy is called and here I clear the data and then the app crash because the data are null. How can I do to not create new activity when the app receive a push notification while is running? In case the app is running I want that if you click the notification do a transition fragment, not create again the activity.
Thanks in advance.
First of all, I think that you mean "notification" to be a "message", but not android.app.Notification class.
And second, I don't think it's a best practise to raise new GUI when receiving a message, which would interrupt the user interaction. For details, please refer to: http://developer.android.com/training/notify-user/index.html and http://developer.android.com/design/patterns/notifications.html.
At last, if you really wanna do what you stated in your thread, I wonder why the data used to generate the show-data fragment is held in the activity. Try holding the data in an android.app.IntentService object, and then generate transfer the data to new activity, and then use android.app.Fragment.setArguments method to transfer the data from activity to fragment.
I think that this code will help you. This which you need is PendingIntent, it make transaction to desired activity.
/**
* Issues a notification to inform the user that server has sent a message.
*/
private static void generateNotification(Context context, String title,
String message) {
//get the default notification sound URI
Uri uriNotificationSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
//make intent to the application. if the application is opened just maximize it.
Intent homeIntent = new Intent(context, 'your desired activity');
homeIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
PendingIntent contentIntent = PendingIntent.getActivity(context, 0,
homeIntent, 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("eCommCongress")
.setContentText(message)
.setLights(Color.GREEN, 1500, 1500)
.setSound(uriNotificationSound)
.setAutoCancel(true)
.setContentIntent(contentIntent);
NotificationManager mNotificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(counter, mBuilder.build());
counter++;
}
It is perfectly possible and I do such a thing in one of my apps. First, you need to declare your activity as android:launchMode="singleTop",
Then, when you build you must configure your pending intent not to fire a new instance of your activity:
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = new Intent("YOUR ACTION HERE");
intent.setClassName(this, MainActivity.class.getName());
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent resultPendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentIntent(resultPendingIntent);
Notification notification = mBuilder.build();
notification.defaults |= Notification.DEFAULT_VIBRATE | Notification.DEFAULT_LIGHTS;
notification.flags |= Notification.FLAG_SHOW_LIGHTS | Notification.FLAG_AUTO_CANCEL;
mNotificationManager.notify(idNotificacion,notification);
Now all you have to do is to override your onNewIntent inside your Activity and do whatever you want with your fragment:
#Override
protected void onNewIntent(Intent intent) {
MiLog.i(getApplicationContext(),"IntentShit","new intent received");
MiLog.i(getApplicationContext(),"IntentShit","Action: "+intent.getAction());
if(intent.getAction()!=null && intent.getAction().equals("YOUR ACTION HERE"){
//DO your stuff here
}
}
You should also take a look at this page for more info:
http://www.intridea.com/blog/2011/6/16/android-understanding-activity-launchmode