i am trying to implement notifications in my android application.
when the user clicks on the notification i run the activity if it isn't already running .. but if the activity is already running i don't want to recreate it, i just want to refresh the data by intercepting the intent from the onNewIntent function.
the problem is that every time I click on the notification, the activity is recreated, and the onNewIntent function is not called.
the problem occurs when I create the notification from a service.
but when I create the notification from the same activity that I am going to run, everything works fine.
I searched the internet and tried all the solutions I found, but it still doesn't work
I tried several combinations of intent flags, but nothing works
this is my code
val intent : Intent = Intent(this, HomeActivity::class.java)
finalIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP)
val pendingIntentFlags : Int = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S)
{
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
}
else
{
PendingIntent.FLAG_UPDATE_CURRENT
}
val pendingIntent : PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(finalIntent)
getPendingIntent(0, pendingIntentFlags)
}
val notification = NotificationCompat.Builder(context, type.channelId)
.setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setCategory(Notification.CATEGORY_SERVICE)
.setDefaults(Notification.DEFAULT_ALL)
.setAllowSystemGeneratedContextualActions(true)
.setOnlyAlertOnce(true)
.setAutoCancel(true)
.setLocalOnly(true)
.setOngoing(false)
.setSilent(false)
.setSmallIcon(R.drawable.icon_notification)
.setContentIntent(pendingIntent)
.build()
notificationManager?.notify(NOTIFICATION_ID, notification)
Let your notification send a broadcast.
In your activity you should register a dynamic broadcast receiver.
This will allow you to refresh the content in the activity without reloading it.
For the case that the activity is not running, you should define a broadcast receiver in the manifest which starts the activity.
when your activity starts, disable the broadcast receiver and re-enable it when your activity stops.
You can just set launch mode attribute to singleInstance in the manifest on your activity and start it with FLAG_ACTIVITY_NEW_TASK only.
Related
I'm building a video calling app and need to display an incoming call screen. I use a Notification that displays an activity with fullscreen intent mechanism as follows:
private fun createIncomingCallNotification(): Notification {
val fullscreenPendingIntent = IncomingCallActivity.intent() // from splitties.intents module
.toPendingActivity(flags =
PendingIntent.FLAG_UPDATE_CURRENT or
Intent.FLAG_ACTIVITY_CLEAR_TASK or
Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_NO_HISTORY or
Intent.FLAG_ACTIVITY_CLEAR_TOP
)
return NotificationCompat.Builder(this, INCOMING_CALL_NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_baseline_call_24)
.setContentTitle("Incoming call")
.setContentText("(919) 555-1234")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setFullScreenIntent(fullscreenPendingIntent, true)
.setContentIntent(
VideoCallActivity.intent()
.toPendingActivity(flags =
Intent.FLAG_ACTIVITY_CLEAR_TASK or
Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_NO_HISTORY or
Intent.FLAG_ACTIVITY_NO_HISTORY or
Intent.FLAG_ACTIVITY_CLEAR_TOP
)
)
.setAutoCancel(true)
.setVibrate(DEFAULT_VIBRATE_PATTERN)
.setSound(incomingCallSound)
.build()
}
It is used as a notification for a foreground service which is triggered when the receiver receives an incoming call request.
The fullscreen activity and notification display OK. However, when I accept the call by clicking on the notification, fullscreen activity remains in the history stack (even with all these flags added plus the autoCancel). So then, when I end my call the fullscreen IncomingCallActivity pops up. It remains even when I stop the foreground service associated with the notification.
Any help would be appreciated!
TL;DR:
I'm looking for a auto-cancel-like behavior for a fullScreenIntent accompaniying an annotation. As it's for the system to decide whether the activity is shown, I'd like to have a generic approach to cancel the notification and close the fullscreen activity on any action selection (reject or accept the call). I suspect it should be done with a BroadcastReceiver, but looking for tips on how it should be done in a concise manner.
EDIT:
I've managed to solve this with BroadcastReceiver registered within the fullscreen activity with a IntentFilter. In the notification reject action I just sendBroadcast which then finishes the fullscreen activity.
However still looking for a 'best practices' approach on that.
I have an app that has a background service running that listens for events.
One of the events should unlock the phone and bring the app to the foreground.
What approaches here are possible?
I was thinking, would it be possible to send a local notification that is actually high priority so it opens the app automatically?
Currently I try to open apps activity this way:
private fun getIntent(pin: String): Intent = Intent(context, XActivity::class.java).apply {
putExtra(XActivity.EXTRA_SMTH, x)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP)
}
private fun showActivity(x: String) {
val intent = getIntent(x)
context.startActivity(intent)
}
This code piece works alright if the app is in the foreground, but does not if the app is in the background.
Any ideas/solutions are welcomed.
At first, if you listened for ACTION_SCREEN_ON or ACTION_SCREEN_ON, make sure to explicitly set your listeners ref.
Secondly, due to background restriction, you cannot start an Activity from background. You have to start a foreground service which you will start when the receiver receives the event. From that service, you can launch your activity with your desired intent.
Foreground service needs a notification. Inside your service, create a notification with your intent like following and call startForeground() with this notification. Also create and register NotificationChannel before if not already.
val fullScreenIntent = Intent(this, XActivity::class.java)
val fullScreenPendingIntent = PendingIntent.getActivity(this, 0,
fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val notificationBuilder =
NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("Launch Activity")
.setContentText("Tap to launch Activity")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_ALARM) // Set your desired category
// Use a full-screen intent only for the highest-priority alerts where you
// have an associated activity that you would like to launch after the user
// interacts with the notification. Also, if your app targets Android 10
// or higher, you need to request the USE_FULL_SCREEN_INTENT permission in
// order for the platform to invoke this notification.
.setFullScreenIntent(fullScreenPendingIntent, true)
val alarmNotification = notificationBuilder.build()
I have 5 activities in my app. Every activity starts the same foreground service.
In onStartCommand method of the service foreground notification is created which unfortunately means that every call of startForegroundService() in any activity plays notification sound (even though the service is already running). How can I create the foreground notification only once or at least how not to play notification sound on successive startForegroundService() calls?
The other related question is: how can I go back to my application when I click the foreground notification? I have 5 activites and I would like to reopen the activity that was the last one the user was interacting with.
#1. before starting the service just check if its already running or not. In that case this will help you https://stackoverflow.com/a/5921190/6413387
#2. To reopen your last opened activity, you need to update the pending intent of your notification. Hope you will find your answer here https://stackoverflow.com/a/20142620/6413387
How can I create the foreground notification only once or at least how not to play notification sound on successive startForegroundService() calls?
You can check if the notification is already visible and show it only if it's not visible. You need to have a reference to the notification PendingIntent and notificationId.
fun isNotificationVisible(context: Context, notificationIntent: Intent, notificationId: Int): Boolean {
return PendingIntent.getActivity(context, notificationId, notificationIntent, PendingIntent.FLAG_NO_CREATE) != null
}
how can I go back to my application when I click the foreground notification?
You need a PendingIntent to open the app from a notification. To open the last activity shown you can remember this using Preferences in the onResume() method of each activity and route the notification into a routing activity that starts the right activity according to the value saved into the preferences.
val intent = Intent(context, RouteActivity::class.java)
val notificationBuilder = NotificationCompat.Builder(context, channelId)
.setContentIntent(intent)
val notificationManager = NotificationManagerCompat.from(context)
val notification = notificationBuilder.build()
notificationManager.notify(notificationId, notification)
Another way to do this is to update the notification PendingIntent if it's already visible with the last activity shown. In this case you don't have to store any value on Preferences and you don't need a route activity.
I have a notification service running that will create a notification for the user and if the user clicks the notification it opens an activity to display the message, the method I am using to create the notification is :
public void createNotificationMsg(String name,String doing, boolean persistent){
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(),
0, new Intent(getApplicationContext(), MessageNotificationActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_SINGLE_TOP).putExtra("message", doing),
PendingIntent.FLAG_CANCEL_CURRENT);
NotificationCompat.Builder notificationBuilder =
(NotificationCompat.Builder) new NotificationCompat.Builder(getApplicationContext())
.setSmallIcon(R.drawable.my_logo_96)
.setContentTitle(name)
.setContentText(doing)
.setPriority(Notification.PRIORITY_HIGH)
.setDefaults(Notification.DEFAULT_ALL)
.setContentIntent(pendingIntent)
.setPriority(Notification.PRIORITY_HIGH)
.setColor(Color.parseColor("#1aadce"));
if (persistent){
notificationBuilder.setOngoing(true);
}
else {
notificationBuilder.setOngoing(false);
}
NotificationManagerCompat notificationManager =
NotificationManagerCompat.from(getApplicationContext());
Notification notification = notificationBuilder.build();
notificationManager.notify(0, notification);
}
the MessageNotificationActivity is using the "android:style/Theme.Dialog" to make it look like a dialog now the thing is that when I click on the notification everything goes well and the activity is opened like a dialog with nothing in the background but if the app is paused and is in background when I click the notification it brings the apps Main activity to the front and then opens the MessageNotiicationActivity on top of it. How can I make the notification not bring the main activity to front and only intent to the specefied activity?
The reason this happens is that your dialog-themed Activity has the same "task affinity" as the other activities in your app, so when you click on the notification, Android looks for an appropriate task in which to launch the dialog-themed Activity. If your app is in the background, Android will see it as a task with the same "task affinity" as the dialog-themed Activity and bring that task to the foreground and launch the dialog-themed Activity into that task.
To prevent this from happening, you need to add android:taskAffinity="" to the <activity> declaration in the manifest for your dialog-themed Activity. This tells Android to launch the dialog-themed Activity into a new task, and not into your app's task.
Try adding the flag Intent.FLAG_ACTIVITY_CLEAR_TASK to your intent. This will clear any other activities in the task.
I have a service in background which gives a notification.
I want the next thing:
If I click the notification and the app is not opened open the XActivity.
If the app is opened and the XActivity is created, go there and don't recreate the activity (because if this happen, on back key i will see the same activity again).
My notification code
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("New posts!")
.setContentText("New funny posts had just arrived! Click here to see them!");
mBuilder.setAutoCancel(true);
Intent resultIntent = new Intent(context, XActivity.class);
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
context,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
mBuilder.setContentIntent(resultPendingIntent);
int mNotificationId = 001;
// Gets an instance of the NotificationManager service
NotificationManager mNotifyMgr =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// Builds the notification and issues it.
mNotifyMgr.notify(mNotificationId, mBuilder.build());
I start the service from the XActivity. (just a activity name example)
Thank you.
i had the same problem, what i did was , i added this line android:launchMode="singleTop" to my activity in manifest, and it worked.
Problem for duplicate activity in your case is because of standard structure design of Activity in Android. For creating only single instance of activity (no duplication) you need to give launchMode property to your activity in your manifest file. You can use singleTop property for this behaviour. You can read more in provided link.
In Addition, for new data access you can use onNewIntent() for new intent coming to this activity and set intent using setIntent() and continue working with new data.
Hope this helps.
Thanks.