As I correctly recall, with Android Oreo the system got more restrictive in terms of battery consumption, e.g., showing the user which app is currently running in the background draining the battery life.
This also shows in my app (scanning for BLE devices in the background, even if the app is not running in the foreground), stating
AppName is running in the background. Tap for Details on battery and
data usage
My question is, whether and how I would be able to exchange this text with a more user facing notification like
AppName is running in the background for reason XYZ
Even so with a notification with a specific icon, etc.
I already tried this by
Creating a custom notification channel in the application.
Starting the services with startForegroundService on Oreo devices.
From within the onCreate method of the service, I call
startForeground(1, NotificationCompat.Builder(applicationContext, "my_channel_id")
.setSmallIcon(R.drawable.some_icon)
.setContentTitle("Title")
.setContentText("AppName is running in the background for reason XYZ")
.build())
But all what happens is the same system-generated notification saying "AppName is running in the background".
Is it even possible to change this?
Thank you for sour suggestions in advance :)
In you service create the notification in onStartCommand() and set its priority. Don't forget to add android:enabled="true" in the manifest.
Service
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
ANDROID_CHANNEL_ID,
ANDROID_CHANNEL_NAME,
NotificationManager.IMPORTANCE_HIGH
)
notificationManager.createNotificationChannel(channel)
}
val notification = NotificationCompat.Builder(this, ANDROID_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle("Test title")
.setContentText("Test content")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setAutoCancel(true)
startForeground(1, notification.build())
return Service.START_NOT_STICKY
}
AndroidManifest
<service android:name=".utils.AppService"
android:enabled="true"/>
Related
I have a foreground service that shows an ongoing notification while running.
Now, it's a streaming app and I want the user to be notified when the stream gets broken (e.g. internet connection dropped). I can't use the main app because the stream can be going while other apps are active. So I need to send a notification to the user from the Foreground Service I use for streaming. The problem is, the notification is not being displayed.
Here's the code I'm currently using:
// registering notification channels
private fun createNotificationChannels() {
val serviceChannel = NotificationChannel(
NOTIFICATION_CHANNEL_ID_SERVICE,
NOTIFICATION_CHANNEL_NAME_SERVICE,
NotificationManager.IMPORTANCE_DEFAULT
)
val appChannel = NotificationChannel(
NOTIFICATION_CHANNEL_ID_APP,
NOTIFICATION_CHANNEL_NAME_APP,
NotificationManager.IMPORTANCE_HIGH
).apply {
enableVibration(true)
}
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannels(mutableListOf(serviceChannel, appChannel))
}
// starting the service with a required notification
startForeground(
nextInt(100000),
NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID_SERVICE)
.setSmallIcon(R.drawable.recording_notification)
.setContentText("Stream is in progress...")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.build(),
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION
)
// letting the user know that stream crashed
private fun sendDisconnectNotification() {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent = PendingIntent.getActivity(this, 0, intent, 0)
val builder = NotificationCompat.Builder(this, NOTIFICATION_CHANNEL_ID_APP)
.setSmallIcon(R.drawable.disconnected_notification)
.setContentTitle("The stream stopped unexpectedly!")
.setContentText("Please check your internet connection.")
.setPriority(NotificationCompat.PRIORITY_MAX)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.setDefaults(NotificationCompat.DEFAULT_ALL)
val manager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager
manager.notify(nextInt(100000), builder.build())
}
I know that sendDisconnectNotification() is being called (put logs there) but the notification never appears.
I was changing so many things that it's hard to specify every piece of code that I tried. But some of the important things I tried were changing the priorities for channels/notifications and sending the notifications in the same/different channels. I also uninstall the app and reboot the phone after every change to make sure the notification settings are applied.
Nothing has been working so far and it got me thinking it's impossible to do. I think that the foreground service only allows one notification to be displayed (the main ongoing one).
Can someone confirm this or give some advice on how to make it work?
I can provide some more code samples if needed.
OK, I’m feeling kinda dumb but it turned out “Do Not Disturb” was turned on on the device. That was the reason the notifications were not visible. Writing this as an answer in case someone like me forgets to turn off DND and finds this SO question.
The notification is now shown and hidden in the status bar after 2 seconds. How do I make the notification not go to the status bar?
val builder = NotificationCompat.Builder(context, "Over limit channel")
.setContentTitle("")
.setContentText("")
.setGroupSummary(false)
.setSmallIcon(R.mipmap.launcher_icon)
.setContent(remoteViews)
.setAutoCancel(false)
.setGroup("false")
.setGroupSummary(false)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
val notificationManager = NotificationManagerCompat.from(context)
notificationManager.notify(800, builder.build())
The trick I found is to use the method setFullScreenIntent(android.app.PendingIntent intent,boolean highPriority) with this method the notification will never be removed from the status bar except when you do it yourself.
here is an example:
val intent = Intent()
val pendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val builder = NotificationCompat.Builder(context, "Over limit channel")
.setContentTitle("")
.setContentText("")
.setGroupSummary(false)
.setSmallIcon(R.mipmap.launcher_icon)
.setContent(remoteViews)
.setAutoCancel(false)
.setGroup("false")
.setGroupSummary(false)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_MAX)
.setFullScreenIntent(pendingIntent,true)
From the android Studio documentation :
An intent to launch instead of posting the notification to the status
bar. Only for use with extremely high-priority notifications demanding
the user's immediate attention, such as an incoming phone call or
alarm clock that the user has explicitly set to a particular time. If
this facility is used for something else, please give the user an
option to turn it off and use a normal notification, as this can be
extremely disruptive. On some platforms, the system UI may choose to
display a heads-up notification, instead of launching this intent,
while the user is using the device.
Params: intent – The pending intent to launch. highPriority – Passing
true will cause this notification to be sent even if other
notifications are suppressed.
UPDATE
For some API version for this to work you must add this permission on the manifest
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT"></uses-permission>
You can start a foreground service with your required notification, or you can set the notification as an onGoing event to make it non dismissible
I wanted to implement a foreground service with an ongoing notification. So far I just want some proper title and some text, but even that doesn't work. Android only shows
"AppXXX is running
Tap for more information or stop app"
The code of making the notification is as followed:
Notification notification =
new Notification.Builder(this, CHANNEL_ID)
.setContentTitle("title")
.setTicker("ticker")
.setContentIntent(pendingIntent)
.build();
setSmallIcon(...) is required for the notification to show properly. According to the anatomy of an android notification here:
Small icon: This is required and set with setSmallIcon()
I am using service as foreground one.
on android pre O versions everything works fine.
but in android Oreo when i close app, the foreground service also closed...
here how i start service:
val i = Intent(activity, MyService::class.java)
ContextCompat.startForegroundService(activity, i)
and than inside service onStart:
val builder = NotificationCompat.Builder(context, MY_CHANEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(message)
.setContentIntent(resultPendingIntent)
val notification = builder.build()
startForeground(notificationId, notification)
service in manifest:
<service
android:name=".data.service.MyService"
android:exported="true"
android:enabled="true"
/>
any idea why it closed with app and how prevent it?
thanks!
Use JobIntentService instead of Service.
https://developer.android.com/reference/android/support/v4/app/JobIntentService.html
Our app has some services and intent-services that starts running when the user starts the app. These components needs to be started to continue the process running even if the user minimize the app.
On Android Oreo our app started crashing due the missing initialization of these services using startForegroundService(:intent) and startForeground(:id, :notification). We've fixed it attaching these notifications as requerested but we discovered a strange behaviour. These notifications appear even if the app is in foreground, since it doesn't make sense because our services are really short-running almost all the time, but it needs to be guaranteed to run 100% of the time. That's why the process runs on a service and not in the activity's context. I would like to show these notifications only when the user minimize the app and the service is up.
Is there any way to do it?
I can't change this message, very annoying!
Here is some code used to create the channel:
const val SERVICE_CHANNEL_ID = "com.myFunnyApp.notifications"
//.....
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationService = context.getSystemService(Context.NOTIFICATION_SERVICE)
(notificationService as? NotificationManager)?.let { notificationManager ->
if (notificationManager.getNotificationChannel(SERVICE_CHANNEL_ID) == null) {
val channel = NotificationChannel(
SERVICE_CHANNEL_ID,
context.resources.getString(R.string.test),
NotificationManager.IMPORTANCE_MIN)
channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
notificationManager.createNotificationChannel(channel)
return
}
}
}
On the service, the code runs:
val notification = Notification.Builder(context, SERVICE_CHANNEL_ID)
.setSubText("subText") //Not working
.setContentText("contentText") //Not working
.setSettingsText("settingsText") //Not working
.setContentTitle("title") //Not working
.build()
startForeground(1, notification)
Currently I am testing on the emulator, I don't have any Android Oreo device.
Thanks!
EDIT 1: The text only changes if you set the small icon.
In Android 8.0(Android Oreo) and onwards, we have to bring the service to the foreground before we trigger a Notification.
After which once you have triggered your Notification - you will have to stop the service running in the Foreground for which execute the following code after -
val notification = Notification.Builder(context, SERVICE_CHANNEL_ID)
.setSubText("subText") //Not working
.setContentText("contentText") //Not working
.setSettingsText("settingsText") //Not working
.setContentTitle("title") //Not working
.build()
startForeground(1, notification)
stopForeground(true);
stopSelf();