'Android Bad notification posted Crash
I'm new to coding. I have made a net speed indicator app for fun. It displays the network speed as a status bar icon. It also allows users to set data usage limits (like 100 GB per month) and sends a notification when they reach the limit.
The final output looks like this:
I followed this answer to display the status bar icon.
Here is the Notifications class I use:
class Notifications(private val context: Context) {
private val notificationChannelPrimary =
"Primary Channel Notification" // This is the persistent channel that shows live data usage
val notificationPersistentChannelID = 15 // To send notifications of persistent channel
private val notificationChannelDataLimit = "Data Limit Warning Notifications"
private val notificationDataLimitID = 10
private val intentNotification = Intent(context, MainActivity::class.java)
private val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
private var mNotificationBuilder: Notification.Builder? = null
private var tempValues = arrayOf(String())
// The following variables are for creating status bar icon
private val bitmap = Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)
private val canvas = Canvas(bitmap)
private val paintSpeed = Paint() // This is for speed value
private val paintUnit = Paint() // This is for speed unit
init {
// Set the paint styles
paintSpeed.color = Color.WHITE
paintSpeed.isAntiAlias = true
paintSpeed.textSize = 60f
paintSpeed.textAlign = Paint.Align.CENTER
paintSpeed.typeface = Typeface.DEFAULT_BOLD
paintUnit.color = Color.WHITE
paintUnit.isAntiAlias = true
paintUnit.textSize = 40f
paintUnit.textAlign = Paint.Align.CENTER
paintUnit.typeface = Typeface.DEFAULT_BOLD
createNotificationChannel()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mNotificationBuilder =
getNotificationBuilder()
}
}
// This method sets the speed to zero when the device is offline
fun setZeroSpeed() {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
canvas.drawText("0", 48f, 52f, paintSpeed)
canvas.drawText("Kb/s", 48f, 95f, paintUnit)
try {
mNotificationBuilder?.setSmallIcon(Icon.createWithBitmap(bitmap))
notificationManager.notify(notificationPersistentChannelID, mNotificationBuilder?.build())
} catch (e: Exception) {
e.printStackTrace()
}
}
// This method shows the speed + data usage on the notification
// It is called every second (from a worker thread)
fun updateDataUsage(
dataSpeed: Long,
remainingData: String?,
planDetails: String?
) {
canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
// BytesConversion.convertSpeed() method takes long value and returns speed with unit array (like 2 Mb/s)
tempValues = BytesConversion.convertSpeed(dataSpeed)
canvas.drawText(tempValues[0], 50f, 50f, paintSpeed)
canvas.drawText(tempValues[1], 50f, 95f, paintUnit)
// If the argument of setContentTitle is null, it's not displaying anything in the title
mNotificationBuilder?.setContentTitle(remainingData)
mNotificationBuilder?.setContentText(planDetails)
try {
mNotificationBuilder?.setSmallIcon(Icon.createWithBitmap(bitmap))
notificationManager.notify(notificationPersistentChannelID, mNotificationBuilder?.build())
} catch (e: Exception) {
}
}
// This method sends notifications when the data usage limit is reached
// You don't need to check supported or unsupported
// because it works in all the devices
// It's just a normal notification
fun sendDataLimitWarning(dataUsageTitle: String?, dataUsageDescription: String?) {
val notificationDataLimit = getNotificationBuilderDataLimit()
notificationDataLimit.setContentText(dataUsageDescription)
notificationDataLimit.setContentTitle(dataUsageTitle)
notificationManager.notify(
notificationDataLimitID,
notificationDataLimit.build()
)
}
// Notification channel is only available from Android Oreo
// So, check the condition
private fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationChannels = mutableListOf<NotificationChannel>()
val notificationChannel1 = NotificationChannel(
notificationChannelPrimary, "Persistent Notification",
NotificationManager.IMPORTANCE_HIGH
)
notificationChannel1.description = "Notification that shows data usage and speed"
notificationChannel1.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
val notificationChannel2 = NotificationChannel(
notificationChannelDataLimit, "Data Limit Warning",
NotificationManager.IMPORTANCE_HIGH
)
notificationChannel2.description = "Notification that shows data limit warnings"
notificationChannel2.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
notificationChannel2.enableVibration(true)
notificationChannel2.enableLights(true)
notificationChannels.add(notificationChannel1)
notificationChannels.add(notificationChannel2)
notificationManager.createNotificationChannels(notificationChannels)
}
}
// This is for sending data limit warnings
private fun getNotificationBuilderDataLimit(): NotificationCompat.Builder {
val pendingIntentDataLimit = PendingIntent.getActivity(
context,
notificationDataLimitID,
intentNotification,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
return NotificationCompat.Builder(
context,
notificationChannelDataLimit
)
.setContentTitle("Data Limit Warning")
.setSmallIcon(R.drawable.icon_notification)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
.setContentIntent(pendingIntentDataLimit)
.setDefaults(NotificationCompat.DEFAULT_ALL)
.setPriority(NotificationManager.IMPORTANCE_HIGH)
}
// This is for sending data + speed notification
// Speed indicator requires Notification.Builder
@RequiresApi(Build.VERSION_CODES.O)
fun getNotificationBuilder(
): Notification.Builder {
val pendingIntentNotification = PendingIntent.getActivity(
context,
notificationPersistentChannelID,
intentNotification,
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)
return Notification.Builder(
context,
notificationChannelPrimary
)
.setSmallIcon(R.drawable.icon_notification)
.setContentIntent(pendingIntentNotification)
.setAutoCancel(false)
.setStyle(Notification.BigTextStyle())
.setOnlyAlertOnce(true)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
}
}
The problem is that I'm getting the following crashes a lot.
Fatal Exception: android.app.RemoteServiceException: Bad notification(tag=null, id=15) posted from package [package_name], crashing app(uid=10769, pid=16295): Couldn't inflate contentViewsjava.util.ConcurrentModificationException
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1894)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7156)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:975)
and
Fatal Exception: android.app.RemoteServiceException: Bad notification(tag=null, id=15) posted from package [package_name], crashing app(uid=10337, pid=27920): Couldn't inflate contentViewsjava.lang.ArrayIndexOutOfBoundsException: src.length=8 srcPos=0 dst.length=8 dstPos=2 length=8
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2168)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:227)
at android.app.ActivityThread.main(ActivityThread.java:7822)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1026)
I searched for "Bad notification posted crash", I found that mNotificationBuilder.setSmallIcon() argument must be a PNG icon (I'm calling it in updateDataUsage() method). Can someone please tell me how to convert the bitmap to PNG and pass it to setSmallIcon()?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|

