I'm trying to show an Activity in onMessageReceived of my FirebaseMessagingService. I've already asked user for permission and checked that it granted.
For Android <=11 simple start activity method worked correctly. Also, it works correctly for Android 12 for emulator.
context.startActivity(Intent(context, MyActivity::class.java).apply {
// add extra
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
})
But for real devices (Samsung and Xiaomi) with Android 12 such approach is not working.
Also, I've tried PendingIntent without result:
val pendingIntent = PendingIntent.getActivity(
context,
0,
Intent(context, MyActivity::class.java)
.apply { // add extra },
PendingIntent.FLAG_IMMUTABLE
)
pendingIntent.send()
Both approaches works, if the application is running. Any suggestions?
If your application is in the background the notification is delivered to the device's system tray and is not handled by onMessageReceived.
Notifications handled by the system tray should just open your app.
More information can be found here
Related
i am building a flutter plugin in java that creates a media notification, and i am having a problem getting the notification click to bring the app to foreground, it used to work on previous android versions but not when testing it on S (31) as a target.
if found this section in the docs :
As of Android Build.VERSION_CODES.S, apps targeting API level Build.VERSION_CODES.S or higher won't be able to start activities while processing broadcast receivers or services in response to notification clicks. To launch an activity in those cases, provide a PendingIntent for the activity itself.
I would like to know if thi is the case or not, or if i need to check something else, here is the code i am using to create the intent i set in the notification builder :
private PendingIntent createContentIntent() {
Intent openUI = new Intent(mContext, AudioplayerPlugin.class);
openUI.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
return PendingIntent.getActivity(mContext, REQUEST_CODE, openUI,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT);
}
AudioplayerPlugin is the plugins own name, the app itself is another activity.
We are working on notification trampolines on Android 12.
Originally our app launches an activity by a broadcast receiver.
I found out that using PendingIntent.getActivity instead of PendingIntent.getBroadcast would solve the problem.
Regarding this, I have a following concern.
When the broadcast receiver is used, i.e. when PendingIntent.getBroadcast is used, I programmed so that the broadcast receiver determines whether to launch the app.
However, I no longer use the broadcast receiver due to notification trampolines. Therefore, PendingIntent.getActivity launches the app without choice.
I would like to know if there is any way to determine whether to launch the app depending of the state of app without using the broadcast receiver.
For example;
when App is in state A:Launch the app with a push notification tap
when App is in state B:NOT launch the app with a push notification tap
sort of workaround would be to launch some dedicated Activity, which may be set as fully transparent without any enter/exit animation, noHistory flag etc. and in there you may run your checking logic - starting "real" Activity or just finish() if there is no need
I'm using a transparent activity to handle this issue. all the notification related works are handled in the transparent activity.
Intent intent = new Intent(mContext, NotificationActivity.class);
intent.putExtra("notification", parseInt(this.mActionDetail.getNotifyId()));
PendingIntent pendingIntent = PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
builder.setContentIntent(pendingIntent);
builder.setAutoCancel(true);
notificationManager.notify(parseInt(this.mActionDetail.getNotifyId()), builder.build());
create a transparent activity NotificationActivity.class then you can identify the application state then you can decide the action
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 want to start an activity from the onReceive() method of the BroadcastReceiver. This is the code i am using:
class TimeReminderReceiver : BroadcastReceiver() {
override fun onReceive(p0: Context?, p1: Intent?) {
println("RECEIVED")
val i = Intent(p0!!, TimeReminderActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
p0.startActivity(i)
}
}
There are many answers for this question in stackoverflow, i tried all of it and none of it is working for me. The app just prints RECEIVED and stays there. Nothing shows at the logcat, no exception, nothing. I have added the receiver in the mainfest also.
<receiver
android:name=".receivers_and_activities.TimeReminderReceiver" />
Whats the problem with this code?
EDIT:
Code that calls the broadcast:
val intent = Intent(this#MainActivity, TimeReminderReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this#MainActivity, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT)
val am = this#MainActivity.getSystemService(Context.ALARM_SERVICE) as AlarmManager
am.set(AlarmManager.RTC_WAKEUP, calendar.timeInMillis, pendingIntent)
As you commented out you are trying to launch an Activity when your App is in Background on Android 10 (API level 29).
From Android (API level 29) they put some restrictions to open an Activity when your App is in Background.
Android 10 (API level 29) and higher place restrictions on when apps
can start activities when the app is running in the background.
You can find out here Restrictions on starting activities from the background.
They have also mentioned that
In nearly all cases, apps that are in the background should display
time-sensitive notifications to provide urgent information to the user
instead of directly starting an activity. Examples of when to use such
notifications include handling an incoming phone call or an active
alarm clock.
So to overcome this behavior instead of calling your App when it is in the background you should show high-priority notification with a full-screen intent.
For more information on High-Priority Notification and Full-Screen Intent, you can check it here Display time-sensitive notifications
I would that the notification does not disappear after a few seconds.
So i have create the notification like this:
NotificationCompat.Builder builder = new NotificationCompat.Builder(context);
builder.setSmallIcon(R.drawable.cast_ic_notification_small_icon)
.setDefaults(Notification.FLAG_ONGOING_EVENT)
.setPriority(Notification.PRIORITY_HIGH)
.setContentTitle(notificationDetails.getSubject())
.setContentText(notificationDetails.getMessage())
.setColor(context.getResources().getColor(R.color.colorPrimary))
.setOngoing(true);
and setting the FLAG_ONGOING_EVENT and the method setOngoing(true).
but after a few seconds the notification continues to disappears.
I wish the notification to disappear only when the user clicks on.
Thank you.
It is actually possible to make a heads-up notification persistent. The trick is to use setFullScreenIntent. If you don't want your notification to have a full-screen version, you can use a dummy intent that won't actually launch any activity, like this:
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, new Intent(), 0);
notificationBuilder.setFullScreenIntent(pendingIntent, true);
It's a hack, but the behavior makes some sense. If an app is trying to show a full-screen notification, then it must be an important event, like an alarm or a phone call. If the phone decides not to show the full-screen notification, it should probably still show something persistent until the user takes action.
This works on the phones I've tested, but the behavior isn't documented, so there are no guarantees.
This issue is observed on Honor and Huawei devices.
You can try to fix it by using setFullScreenIntent and adding permissions to AndroidManifest.
Code:
PendingIntent pIntent = PendingIntent.getActivity(this, 0, new Intent(), PendingIntent.FLAG_UPDATE_CURRENT);
notificationBuilder.setFullScreenIntent(pIntent, true);
AndroidManifest.xml:
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
Duration of heads-up notification can't be changed It is set at OS level Depends on OS how much time it provides for it.
The duration cannot be changed. Otherwise it would intrude with other heads-up notifications that are in the queue to be displayed.
You can do it with:
notificationBuilder.setFullScreenIntent(pendingIntent, true)
You also have to use these:
val tempChannel = NotificationChannel(tempChannelId, "temp channel",
NotificationManager.IMPORTANCE_HIGH) // Setting to high is important
tempChannel.enableVibration(true)
...
notificationBuilder.setAutoCancel(false)
notificationBuilder.setPriority(NotificationCompat.PRIORITY_MAX) // PRIORITY_HIGH works too
notificationBuilder.setVibrate(LongArray(0)) // For older devices we need to add vibration or sound for the Heads-Up notification. This line will not make it vibrate, you can use another pattern, or default, if you want it to vibrate
notificationBuilder.setFullScreenIntent(pendingIntent, true)
IMPORTANT:
On most of the devices, this will show the notification on the top of the screen, overlapping everything, and staying there.
BUT ON SOME DEVICE THIS WILL IMMEDIATELY LAUNCH THE PENDING INTENT THAT IS GIVEN TO THE NOTIFICATION. (Eg. Huawei)
TO SOLVE THIS we can use a dummy pendingIntent for the fullScreenIntent, that shows the notification the same way, just without the notificationBuilder.setFullScreenIntent(pendingIntent, true); This will work as a fallback, so the notification will appear, but will shrink itself to the status bar after like 5 seconds.
val servicePendingIntent = PendingIntent.getService(context, 0, Intent(context, FullScreenIntentService::class.java), 0)
val mainActivityPendingIntent = PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), PendingIntent.FLAG_ONE_SHOT)
...
notificationBuilder.setContentIntent(mainActivityPendingIntent)
notificationBuilder.setFullScreenIntent(servicePendingIntent, true)
Where:
class FullScreenIntentService : Service() {
override fun onCreate() {
super.onCreate()
showNotificationHereTheSameWayJustWithoutSetFullScreenIntent()
stopSelf()
}
override fun onBind(intent: Intent?): IBinder? = null
}
And don't forget to register the service in AndroidManifest.
.setFullScreenIntent(fullScreenPendingIntent, true)
For heads up notification to stay on, you need add a full screen intent
Apart from the same issue with foreground heads-up notifications disappearing after a few seconds, an additional issue I had was that the action buttons were collapsed.
Among other things, what helped me was:
builder.setCategory(NotificationCompat.CATEGORY_CALL);
After adding this line of code, the notification didn't disappeared after a few seconds and the action buttons weren't collapsed.