kopia lustrzana https://github.com/meshtastic/Meshtastic-Android
Separate notification channel for messages
rodzic
be738787f0
commit
e2c8ca2fb2
|
@ -98,6 +98,8 @@ class MeshService : Service(), Logging {
|
|||
DEVICE_SLEEP // device is in LS sleep state, it will reconnected to us over bluetooth once it has data
|
||||
}
|
||||
|
||||
private var previousSummary: String? = null
|
||||
|
||||
/// A mapping of receiver class name to package name - used for explicit broadcasts
|
||||
private val clientPackages = mutableMapOf<String, String>()
|
||||
private val serviceNotifications = MeshServiceNotifications(this)
|
||||
|
@ -124,19 +126,11 @@ class MeshService : Service(), Logging {
|
|||
getNodeNum = { myNodeNum }
|
||||
)
|
||||
|
||||
private fun getSenderName(): String {
|
||||
val recentFrom = recentReceivedTextPacket?.from // safe, immutable copy
|
||||
return if (recentFrom != null) {
|
||||
nodeDBbyID[recentFrom]?.user?.longName
|
||||
?: recentFrom
|
||||
} else {
|
||||
getString(R.string.unknown_username)
|
||||
}
|
||||
private fun getSenderName(packet : DataPacket?): String {
|
||||
val name = nodeDBbyID[packet?.from]?.user?.longName
|
||||
return name ?: "Unknown username"
|
||||
}
|
||||
|
||||
/// A text message that has a arrived since the last notification update
|
||||
private var recentReceivedTextPacket: DataPacket? = null
|
||||
|
||||
private val notificationSummary
|
||||
get() = when (connectionState) {
|
||||
ConnectionState.CONNECTED -> getString(R.string.connected_count).format(
|
||||
|
@ -259,11 +253,9 @@ class MeshService : Service(), Logging {
|
|||
})
|
||||
}
|
||||
|
||||
private fun updateNotification() = serviceNotifications.updateNotification(
|
||||
recentReceivedTextPacket,
|
||||
notificationSummary,
|
||||
getSenderName()
|
||||
)
|
||||
private fun updateMessageNotification(message: DataPacket) =
|
||||
serviceNotifications.updateMessageNotification(
|
||||
getSenderName(message), message.bytes!!.toString(utf8))
|
||||
|
||||
/**
|
||||
* tell android not to kill us
|
||||
|
@ -276,11 +268,9 @@ class MeshService : Service(), Logging {
|
|||
|
||||
// We always start foreground because that's how our service is always started (if we didn't then android would kill us)
|
||||
// but if we don't really need foreground we immediately stop it.
|
||||
val notification = serviceNotifications.createNotification(
|
||||
recentReceivedTextPacket,
|
||||
notificationSummary,
|
||||
getSenderName()
|
||||
)
|
||||
val notification = serviceNotifications.createServiceStateNotification(
|
||||
notificationSummary)
|
||||
|
||||
startForeground(serviceNotifications.notifyId, notification)
|
||||
if (!wantForeground) {
|
||||
stopForeground(true)
|
||||
|
@ -634,9 +624,7 @@ class MeshService : Service(), Logging {
|
|||
when (data.portnumValue) {
|
||||
Portnums.PortNum.TEXT_MESSAGE_APP_VALUE -> {
|
||||
debug("Received CLEAR_TEXT from $fromId")
|
||||
|
||||
recentReceivedTextPacket = dataPacket
|
||||
updateNotification()
|
||||
updateMessageNotification(dataPacket)
|
||||
}
|
||||
|
||||
// Handle new style position info
|
||||
|
@ -814,7 +802,7 @@ class MeshService : Service(), Logging {
|
|||
|
||||
/// If we just changed our nodedb, we might want to do somethings
|
||||
private fun onNodeDBChanged() {
|
||||
updateNotification()
|
||||
maybeUpdateServiceStatusNotification()
|
||||
|
||||
// we don't ask for GPS locations from android if our device has a built in GPS
|
||||
// Note: myNodeInfo can go away if we lose connections, so it might be null
|
||||
|
@ -956,7 +944,15 @@ class MeshService : Service(), Logging {
|
|||
}
|
||||
|
||||
// Update the android notification in the status bar
|
||||
updateNotification()
|
||||
maybeUpdateServiceStatusNotification()
|
||||
}
|
||||
|
||||
private fun maybeUpdateServiceStatusNotification() {
|
||||
val currentSummary = notificationSummary
|
||||
if (previousSummary == null || !previousSummary.equals(currentSummary)) {
|
||||
serviceNotifications.updateServiceStateNotification(currentSummary)
|
||||
previousSummary = currentSummary
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -9,6 +9,8 @@ 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
|
||||
|
@ -18,6 +20,7 @@ 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
|
||||
|
||||
|
@ -26,21 +29,47 @@ 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
|
||||
importance = NotificationManager.IMPORTANCE_NONE
|
||||
lockscreenVisibility = Notification.VISIBILITY_PRIVATE
|
||||
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
|
||||
|
@ -56,18 +85,24 @@ class MeshServiceNotifications(
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update our notification with latest data
|
||||
*/
|
||||
fun updateNotification(
|
||||
recentReceivedText: DataPacket?,
|
||||
summaryString: String,
|
||||
senderName: String
|
||||
) {
|
||||
val notification = createNotification(recentReceivedText, summaryString, senderName)
|
||||
notificationManager.notify(notifyId, notification)
|
||||
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)
|
||||
}
|
||||
|
@ -91,20 +126,8 @@ class MeshServiceNotifications(
|
|||
return bitmap
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a new version of our notification - reflecting current app state
|
||||
*/
|
||||
fun createNotification(
|
||||
recentReceivedText: DataPacket?,
|
||||
summaryString: String,
|
||||
senderName: String
|
||||
): Notification {
|
||||
val category =
|
||||
if (recentReceivedText != null) Notification.CATEGORY_SERVICE else Notification.CATEGORY_MESSAGE
|
||||
val builder = NotificationCompat.Builder(context, channelId).setOngoing(true)
|
||||
.setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
.setCategory(category)
|
||||
.setContentTitle(summaryString) // leave this off for now so our notification looks smaller
|
||||
fun commonBuilder(channel: String) : NotificationCompat.Builder {
|
||||
val builder = NotificationCompat.Builder(context, channel)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setContentIntent(openAppIntent)
|
||||
|
||||
|
@ -123,20 +146,32 @@ class MeshServiceNotifications(
|
|||
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
|
||||
}
|
||||
|
||||
// FIXME, show information about the nearest node
|
||||
// if(shortContent != null) builder.setContentText(shortContent)
|
||||
fun createServiceStateNotification(summaryString: String): Notification {
|
||||
val builder = commonBuilder(channelId)
|
||||
with(builder) {
|
||||
setPriority(NotificationCompat.PRIORITY_MIN)
|
||||
setCategory(Notification.CATEGORY_SERVICE)
|
||||
setOngoing(true)
|
||||
setContentTitle(summaryString) // leave this off for now so our notification looks smaller
|
||||
}
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
// If a text message arrived include it with our notification
|
||||
recentReceivedText?.let { packet ->
|
||||
// Try to show the human name of the sender if possible
|
||||
builder.setContentText("Message from $senderName")
|
||||
builder.setStyle(
|
||||
fun createMessageNotifcation(name: String, message: String): Notification {
|
||||
val builder = commonBuilder(messageChannelId)
|
||||
with(builder) {
|
||||
setPriority(NotificationCompat.PRIORITY_DEFAULT)
|
||||
setCategory(Notification.CATEGORY_MESSAGE)
|
||||
setAutoCancel(true)
|
||||
setContentTitle(name)
|
||||
setStyle(
|
||||
NotificationCompat.BigTextStyle()
|
||||
.bigText(packet.bytes!!.toString(utf8))
|
||||
.bigText(message),
|
||||
)
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
|
|
|
@ -85,4 +85,5 @@
|
|||
<string name="message_delivery_status">Message delivery status</string>
|
||||
<string name="broadcast_position_secs">Broadcast position period (in seconds), 0 - disable</string>
|
||||
<string name="ls_sleep_secs">Device sleep period (in seconds)</string>
|
||||
<string name="meshtastic_messages_notifications">Notifications about messages</string>
|
||||
</resources>
|
||||
|
|
Ładowanie…
Reference in New Issue