I have 3 samsung S10 devices, on two of which this problem occurs:
If there is a notification present in the system tray that belongs to the app, it takes the phone about 5 seconds to turn on the screen when clicking the power button.
If there is no notification in the system tray, the screen turns on immediately.
If you manually remove the notification from the system tray, without opening the app, it fixes the issue with the delay in turning on the screen.
What could be causing this problem?
There could only be 1 notification, each new notification replaces the old one.
All the notification does is open the app.
The problem is apparent without opening the app, just having the notification in the tray and the app is not in the background is enough to cause the problem.
The problem is not apparent on any other device that I have.
This is the code that loads the notification into the system tray once it arrives via firebase messaging
private fun sendNotification(message: RemoteMessage) {
val intent = this.packageManager.getLaunchIntentForPackage(this.packageName)
intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent =
PendingIntent.getActivity(applicationContext, Random().nextInt(), intent, PendingIntent.FLAG_UPDATE_CURRENT)
val gson = Gson()
val jsonData = gson.toJson(message.data)
val data = gson.fromJson(jsonData, NotificationPayload::class.java)
if (data.isEmpty()) {
Timber.i("Was supposed to display notification, but there was no data to display")
return
}
val defaultSoundUri: Uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, context.getString(R.string.app_name))
.setSmallIcon(R.drawable.ic_notification) //
.setContentTitle(data.title) //
.setContentText(data.body) //
.setColor(ContextCompat.getColor(context, R.color.very_dark_blue)).setAutoCancel(true) //
.setSound(defaultSoundUri) //
.setOnlyAlertOnce(true) //
.setContentIntent(pendingIntent) as NotificationCompat.Builder
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
val importance = when(ApplicationForegroundListener.isApplicationForeground()) {
true -> NotificationManager.IMPORTANCE_DEFAULT
else -> NotificationManager.IMPORTANCE_HIGH
}
notificationBuilder.priority = importance
notificationBuilder.setVibrate(LongArray(0))
// Since android Oreo notification channel is needed.
val channel = NotificationChannel(context.getString(R.string.app_name),
context.getString(R.string.app_name),
importance)
notificationManager.createNotificationChannel(channel)
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
}
The issue was the size of the notification icon in dp.
I needed to scale it down to 48x48 to fix it.
Related
My app uses a receiver to send the user notifications after a certain amount of time. The receiver works great as it runs a few functions, the notification however doesn't work so smoothly.
On the emulator (API29 and Android 10) it sends them correctly however when I install it on real devices it either doesn't work at all or works perfectly fine.
My phone had the notifications perfectly until when I updated it to android 12, from then on no notifications are fired. I also tested it on an older device (Android 7) and again it doesn't work.
I read into it and don't really understand how the channels work, so I think the issue might be there however I find it weird how it would then still work on some devices/emulators.
Here is my code:
class MyReceiver: BroadcastReceiver() {
#RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context, intent: Intent) {
val notificationChannel =
NotificationChannel("My Channel", "New Quote",
NotificationManager.IMPORTANCE_DEFAULT).apply {
description = "Alerts when A new daily quote is set!"
}
val titles = arrayOf(
"Become inspired!",
"Check out this quote!",
"A new quote appeared!",
"Daily quote available!"
)
val title = titles.random()
val i = Intent(context, Qinperation::class.java)
val builder = NotificationCompat.Builder(context, "My Channel")
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(title)
.setContentText("A new daily quote is available for viewing")
.setContentIntent(
PendingIntent.getActivity(
context,
0,
i,
PendingIntent.FLAG_UPDATE_CURRENT
)
);
with(NotificationManagerCompat.from(context)) {
createNotificationChannel(notificationChannel)
notify(1, builder.build())
}
}
}
All help is appreciated :)
Channels are required for android version O and above. You need to create the channel(s) before you receive a notification. Channels basically are like a "switch" that can be turned off and on from the settings of the app and you configure your notifications, this means you can configure if you receive a notification if it should vibrate etc.
Before android version O you don't require a channel and the configuration of the notification is happening from the notificationBuilder.
So if you want to configure your notifications for above and bellow version O you have to do it on both places.
Now regarding your problem I think, you create to late the channel and call this method in your first activity or in the application class :
private fun createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val name = getString(R.string.channel_name)
val descriptionText = getString(R.string.channel_description)
val importance = NotificationManager.IMPORTANCE_DEFAULT
val channel = NotificationChannel(CHANNEL_ID, name, importance).apply {
description = descriptionText
}
// Register the channel with the system
val notificationManager: NotificationManager =
getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}
And then in your receiver you need only to create your notification and finally call this:
with(NotificationManagerCompat.from(this)) {
// notificationId is a unique int for each notification that you must define
notify(notificationId, builder.build())
}
In case this doesn't work you might want to add a log to see if your receiver is indeed called.
This was my bad. Turns out that on certain devices (like the one I was testing on), Doesn't support the pending intent I was using to fire the notification. If people have a similar issue, try changing Pending Intents to - PendingIntent.FLAG_IMMUTABLE as this works on more devices, Especially newer ones!
I am sending a notification to an Android device with my Java backend.
The Android device receives the notification and when I click on it, it simply opens my app.
So far so good, but what I would like to achieve is to be able to read the data from the Firebase message in the onCreate() method of the MainActivity class. How would that be possible?
private fun sendNotification(messageBody: String) {
val intent = Intent(this, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_ONE_SHOT)
val channelId = "" // TODO CHANNEL ID NEEDED
val defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
val notificationBuilder = NotificationCompat.Builder(this, channelId)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent)
val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
// Since android Oreo notification channel is needed.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channelId,
"Channel human readable title",
NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build())
}
This doesn't log anything for me (in onCreate()):
if (getIntent() != null) {
val dataBundle = getIntent().extras
Log.d("data bundle", dataBundle.toString())
}
At first, check the 2 different types of notifications that you can send. link
Depending on each type and the state of your app (background or Foreground) you cannot always take the data from a Notification, check this for more link2.
When your application gets a notification there is a service with a method you can override to get the data. The method is called OnMessageReceived(RemoteMessage), you can find more info about the service at link2.
That's the way to get the data of a notification. If you want the data on your Activity there are some ways you could achieve that. You could try to save them at a Database(persistent) or at SharedPreferences and access them when your Activity starts or you could pass the data through the bundle to the activity you are about to open(Deeplinks), check this stackoverflow answer.
I'm developing my custom calling app, like skype and I need to show "incoming call" screen to user, when I receive fcm message. I use full screen intent notification for this purpose. My code now is like this:
val intent = Intent(Intent.ACTION_MAIN, null)
val fakeIntent = Intent()
intent.flags = Intent.FLAG_ACTIVITY_NO_USER_ACTION or Intent.FLAG_ACTIVITY_NEW_TASK
intent.setClass(ctx, IncomingCallActivity::class.java!!)
val pendingIntent = PendingIntent.getActivity(ctx, 1, intent, 0)
val pendingIntent2 = PendingIntent.getActivity(ctx, 1, fakeIntent, PendingIntent.FLAG_ONE_SHOT)
val builder = Notification.Builder(ctx)
builder.setOngoing(true)
builder.setPriority(Notification.PRIORITY_HIGH)
// Set notification content intent to take user to fullscreen UI if user taps on the
// notification body.
builder.setContentIntent(pendingIntent)
// Set full screen intent to trigger display of the fullscreen UI when the notification
// manager deems it appropriate.
builder.setFullScreenIntent(pendingIntent, true)
// Setup notification content.
builder.setSmallIcon(R.mipmap.ic_launcher)
builder.setContentTitle("Call from Vitalii")
builder.setContentText("Your notification content.")
builder.setAutoCancel(true)
// Use builder.addAction(..) to add buttons to answer or reject the call.
val acceptAction = Notification.Action.Builder(Icon.createWithResource(ctx, R.drawable.ic_launch), "Accept", pendingIntent).build()
val declineAction = Notification.Action.Builder(Icon.createWithResource(ctx, R.drawable.ic_launch), "Decline", pendingIntent2).build()
builder.addAction(acceptAction)
builder.addAction(declineAction)
val notificationManager = ctx.getSystemService(
NotificationManager::class.java)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("callnotification", "Incoming Calls", NotificationManager.IMPORTANCE_MAX)
val ringtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
channel.setSound(ringtoneUri, AudioAttributes.Builder()
.setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.build())
notificationManager.createNotificationChannel(channel)
builder.setChannelId("callnotification")
}
val notification = builder.build()
notification.flags = Notification.FLAG_INSISTENT
currentNotificationId = Random().nextInt(500)
intent.putExtra("notifid", currentNotificationId)
notificationManager.notify("callnotification", currentNotificationId, notification)
And when screen is unlocked I receive calling notification with buttons to accept the call and decline. But when screen is locked I receive only sound and vibration, but not the custom screen with buttons like in telegram, whatsup and viber. How can I show such custom screen when device is locked?
Add following code in your CallActivity:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED| WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON|WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
I have been trying to display a notification but it either doesn't show or causes a fatal error inside the notify method. This notification is supposed to effectively be a toast that will stay in the notification drawer until tapped.
I've tried several different intents including none. I have also, at points, copied an entire example in which still didn't work.
I have no clue what's causing the error and I've tried to attach a logcat into the app but I wasn't able to get anything out.
I'm using a Pixel 2 running stock 8.1; my programming is on the phone itself so I can't use adb / root options
public int noti(String title, String body, String ico){
//Bitmap bitmap = ((BitmapDrawable)drawable).getBitmap();
showToast(title+">"+body+">"+ico);
try{
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.google.com/"));
PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0);
Notification.Builder mBuilder =
new Notification.Builder(getApplicationContext(), "83")
.setSmallIcon(Icon.createWithContentUri(ico))
.setContentTitle(title)
.setContentText(body)
.setOngoing(true)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getApplicationContext());
Notification noti = mBuilder.build();
if(noti==null){
logBack("noti.builder == null.");
return -2;
}
int notificationId = notiIDz.getAndIncrement();
// notificationId is a unique int for each notification that you must define
notificationManager.notify(notificationId, noti);
return notificationId;
} catch(Exception e){
logBack(e.toString());
}
return -1;
}
I know that the parameters are valid from the toast, I also know that none of the logBack()s are fired.
Notification channel creation, called during onCreate:
private void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel("83", "vzyNotiChan", NotificationManager.IMPORTANCE_DEFAULT);
channel.setDescription("The notification channel for vzy apps.");
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
NotificationManager notificationManager = getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
}
Edit, finally got to the logcat:07-24 10:48:10.879 27133 27133 E AndroidRuntime: android.app.RemoteServiceException: Bad notification posted from package vzy.html.tester: Couldn't create icon: StatusBarIcon(icon=Icon(typ=URI uri=content://com.android.externalstorage.documents/document/primary%3Ayp_sodapop.png) visible user=0 )
My guess is that you didn't create a notification channel for your notification. On All Android devices running 8.0+, each notification needs to be associated to a notification channel. You're passing in the channel ID "83" to the notification builder, but maybe you haven't actually created the channel beforehand.
For more information on how to create channels, check this out:
https://developer.android.com/training/notify-user/channels
I need to generate notifications when a PUSH notification is received but also I need to generate notifications (for display them in the notification bar of the device) when something happens in the application, so I'm using NotificationCompat.Builder for it.
As you know, android has deprecated this call to Notification.Builder:
Notification.Builder (Context context)
And now you must use this call:
NotificationCompat.Builder (Context context, String channelId)
What happens if you don't want to specify a notification channel and you want to send general notifications to all the users of your app and you want to receive all the notifications in all the apps installed without dealing with notification channels? Or what happens if you want to create a simple notification in the notification bar when a user has pressed a button in your app? How to display a notification without specifying the channelId? I mean... just working like until api 26 and before notification channels appeared.
Can't see how to work without specifying notification channels in any place of the official documentation.
Notification Channels are mandatory on Android 8+. So you must use NotificationCompat.Builder(Context context, String channelId) and create channel(s) on api 26+ via NotificationManager.createNotificationChannel(NotificationChannel channel).
On api < 26, just don't call createNotificationChannel but let the channel id parameter (just a String).
val builder = NotificationCompat.Builder(context, "a_channel_id")
builder.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setSmallIcon(R.drawable.ic_notif)
.setAutoCancel(true)
...
val notificationManager = NotificationManagerCompat.from(context)
notificationManager.notify(NOTIFICATION_ID, builder.build())
on Api 26+, create a channel before:
val channel = NotificationChannel("a_channel_id", "channel_name", NotificationManager.IMPORTANCE_HIGH)
channel.description = "channel_description"
channel.enableLights(true)
channel.lightColor = Color.RED
channel.enableVibration(true)
val notificationManager = NotificationManagerCompat.from(context)
notificationManager.createNotificationChannel(channel)
There is currently no workaround for this. Notification Channels has been recently announced (last last I/O if I remember correctly), and is (most probably if not absolutely) here to stay. What I do though is something like this.
To abide to the new standard, I just implement the Notification Channels, but only as needed. I also use FCM on my app and here's something similar to what I have for it -- this is in my Application class:
private void initFirebase() {
... // other Firebase stuff.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) initNotificationChannels();
}
#TargetApi(Build.VERSION_CODES.O)
private void initNotificationChannels() {
NotificationChannel publicChannel = new NotificationChannel(NOTIFICATION_CHANNEL_PUBLIC,
NOTIFICATION_CHANNEL_PUBLIC, NotificationManager.IMPORTANCE_DEFAULT);
publicChannel.setDescription(NOTIFICATION_CHANNEL_PUBLIC);
NotificationChannel privateChannel = new NotificationChannel(NOTIFICATION_CHANNEL_PRIVATE,
NOTIFICATION_CHANNEL_PRIVATE, NotificationManager.IMPORTANCE_HIGH);
publicChannel.setDescription(NOTIFICATION_CHANNEL_PRIVATE);
NotificationManager mNotificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (mNotificationManager != null) {
mNotificationManager.createNotificationChannel(publicChannel);
mNotificationManager.createNotificationChannel(privateChannel);
}
}
And my MessagingService has something like this:
private static final String NOTIFICATION_CHANNEL_PRIVATE = "my.app.package.name.private";
private static final String NOTIFICATION_CHANNEL_PUBLIC = "my.app.package.name.public";
private void buildNotification(....(other params),String source, String message) {
String channelId = getChannelId(source);
Intent resultIntent = new Intent(this, MyActivity.class);
resultIntent.putExtra(EXTRAS_PARAM_ID, myVal);
PendingIntent notificationIntent = buildNotificationIntent(channelId, roomId, roomType);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, getChannelId(source))
.setSmallIcon(R.drawable.ic_sample
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_SOUND)
.setContentIntent(notificationIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(id, 0, notificationBuilder.build());
}
private String getChannelId(String source) {
switch(source){
case PRIVATE:
return NOTIFIFICATION_CHANNEL_PRIVATE;
default:
return NOTIFICATION_CHANNEL_PUBLIC;
}
}
I don't know if this answers the question or not. But, having any channel below api 26 just worked without doing anything on my app.
1. instantiate notificationCompat with some channel Id
//which is irrelevant for api < 26
2. handle the case of creating notification channel for api 26+
3. bundled it up.
It just worked. Configuring Notifications did not have any effects below api 26.