mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
183 lines
7.1 KiB
Kotlin
183 lines
7.1 KiB
Kotlin
package com.geeksville.mesh.service
|
|
|
|
import android.app.Notification
|
|
import android.app.NotificationChannel
|
|
import android.app.NotificationManager
|
|
import android.app.PendingIntent
|
|
import android.content.Context
|
|
import android.content.Intent
|
|
import android.graphics.Bitmap
|
|
import android.graphics.Canvas
|
|
import android.graphics.Color
|
|
import android.media.AudioAttributes
|
|
import android.media.RingtoneManager
|
|
import android.os.Build
|
|
import androidx.annotation.RequiresApi
|
|
import androidx.core.app.NotificationCompat
|
|
import androidx.core.content.ContextCompat
|
|
import androidx.core.graphics.drawable.DrawableCompat
|
|
import com.geeksville.mesh.DataPacket
|
|
import com.geeksville.mesh.MainActivity
|
|
import com.geeksville.mesh.R
|
|
import com.geeksville.mesh.android.notificationManager
|
|
import com.geeksville.mesh.ui.SLogging
|
|
import com.geeksville.mesh.utf8
|
|
import java.io.Closeable
|
|
|
|
|
|
class MeshServiceNotifications(
|
|
private val context: Context
|
|
) : Closeable {
|
|
private val notificationManager: NotificationManager get() = context.notificationManager
|
|
// We have two notification channels: one for general service status and another one for messages
|
|
val notifyId = 101
|
|
private val messageNotifyId = 102
|
|
|
|
private var largeIcon: Bitmap? = null
|
|
|
|
@RequiresApi(Build.VERSION_CODES.O)
|
|
private fun createNotificationChannel(): String {
|
|
val channelId = "my_service"
|
|
val channelName = context.getString(R.string.meshtastic_service_notifications)
|
|
val channel = NotificationChannel(
|
|
channelId,
|
|
channelName,
|
|
NotificationManager.IMPORTANCE_MIN
|
|
).apply {
|
|
lightColor = Color.BLUE
|
|
lockscreenVisibility = Notification.VISIBILITY_PRIVATE
|
|
}
|
|
notificationManager.createNotificationChannel(channel)
|
|
return channelId
|
|
}
|
|
|
|
@RequiresApi(Build.VERSION_CODES.O)
|
|
private fun createMessageNotificationChannel(): String {
|
|
val channelId = "my_messages"
|
|
val channelName = context.getString(R.string.meshtastic_messages_notifications)
|
|
val channel = NotificationChannel(
|
|
channelId,
|
|
channelName,
|
|
NotificationManager.IMPORTANCE_HIGH
|
|
).apply {
|
|
lightColor = Color.BLUE
|
|
lockscreenVisibility = Notification.VISIBILITY_PUBLIC
|
|
setShowBadge(true)
|
|
setSound(
|
|
RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION),
|
|
AudioAttributes.Builder()
|
|
.setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
|
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
|
.build()
|
|
)
|
|
}
|
|
notificationManager.createNotificationChannel(channel)
|
|
return channelId
|
|
}
|
|
|
|
private val channelId: String by lazy {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
createNotificationChannel()
|
|
} else {
|
|
// If earlier version channel ID is not used
|
|
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
|
""
|
|
}
|
|
}
|
|
|
|
private val messageChannelId: String by lazy {
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
createMessageNotificationChannel()
|
|
} else {
|
|
// If earlier version channel ID is not used
|
|
// https://developer.android.com/reference/android/support/v4/app/NotificationCompat.Builder.html#NotificationCompat.Builder(android.content.Context)
|
|
""
|
|
}
|
|
}
|
|
|
|
fun updateServiceStateNotification(summaryString: String) =
|
|
notificationManager.notify(notifyId,
|
|
createServiceStateNotification(summaryString))
|
|
|
|
fun updateMessageNotification(name: String, message: String) =
|
|
notificationManager.notify(messageNotifyId,
|
|
createMessageNotifcation(name, message))
|
|
|
|
private val openAppIntent: PendingIntent by lazy {
|
|
PendingIntent.getActivity(context, 0, Intent(context, MainActivity::class.java), 0)
|
|
}
|
|
|
|
/**
|
|
* Generate a bitmap from a vector drawable (even on old builds)
|
|
* https://stackoverflow.com/questions/33696488/getting-bitmap-from-vector-drawable
|
|
*/
|
|
fun getBitmapFromVectorDrawable(drawableId: Int): Bitmap {
|
|
var drawable = ContextCompat.getDrawable(context, drawableId)!!
|
|
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
|
drawable = DrawableCompat.wrap(drawable).mutate()
|
|
}
|
|
val bitmap = Bitmap.createBitmap(
|
|
drawable.intrinsicWidth,
|
|
drawable.intrinsicHeight, Bitmap.Config.ARGB_8888
|
|
)
|
|
val canvas = Canvas(bitmap)
|
|
drawable.setBounds(0, 0, canvas.width, canvas.height)
|
|
drawable.draw(canvas)
|
|
return bitmap
|
|
}
|
|
|
|
fun commonBuilder(channel: String) : NotificationCompat.Builder {
|
|
val builder = NotificationCompat.Builder(context, channel)
|
|
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
|
.setContentIntent(openAppIntent)
|
|
|
|
// Set the notification icon
|
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
|
// If running on really old versions of android (<= 5.1.1) (possibly only cyanogen) we might encounter a bug with setting application specific icons
|
|
// so punt and stay with just the bluetooth icon - see https://meshtastic.discourse.group/t/android-1-1-42-ready-for-alpha-testing/2399/3?u=geeksville
|
|
builder.setSmallIcon(android.R.drawable.stat_sys_data_bluetooth)
|
|
} else {
|
|
// Newer androids also support a 'large' icon
|
|
|
|
// We delay making this bitmap until we know we need it
|
|
if (largeIcon == null)
|
|
largeIcon = getBitmapFromVectorDrawable(R.mipmap.ic_launcher2)
|
|
|
|
builder.setSmallIcon(if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) R.drawable.app_icon_novect else R.drawable.app_icon) // vector form icons don't work reliably on older androids
|
|
.setLargeIcon(largeIcon)
|
|
}
|
|
return builder
|
|
}
|
|
|
|
fun createServiceStateNotification(summaryString: String): Notification {
|
|
val builder = commonBuilder(channelId)
|
|
with(builder) {
|
|
priority = NotificationCompat.PRIORITY_MIN
|
|
setCategory(Notification.CATEGORY_SERVICE)
|
|
setOngoing(true)
|
|
setContentTitle(summaryString) // leave this off for now so our notification looks smaller
|
|
}
|
|
return builder.build()
|
|
}
|
|
|
|
fun createMessageNotifcation(name: String, message: String): Notification {
|
|
val builder = commonBuilder(messageChannelId)
|
|
with(builder) {
|
|
priority = NotificationCompat.PRIORITY_DEFAULT
|
|
setCategory(Notification.CATEGORY_MESSAGE)
|
|
setAutoCancel(true)
|
|
setContentTitle(name)
|
|
setContentText(message)
|
|
setStyle(
|
|
NotificationCompat.BigTextStyle()
|
|
.bigText(message),
|
|
)
|
|
}
|
|
return builder.build()
|
|
}
|
|
|
|
override fun close() {
|
|
largeIcon?.recycle()
|
|
largeIcon = null
|
|
}
|
|
}
|