2020-10-01 22:20:19 +02:00
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
2021-02-05 09:31:25 +08:00
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
2020-10-01 22:20:19 +02:00
import android.graphics.Color
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
2021-02-05 09:31:25 +08:00
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat
2020-10-01 22:20:19 +02:00
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.utf8
2021-02-05 09:31:25 +08:00
import java.io.Closeable
2020-10-01 22:20:19 +02:00
class MeshServiceNotifications (
private val context : Context
2021-02-05 09:31:25 +08:00
) : Closeable
{
2020-10-01 22:20:19 +02:00
private val notificationManager : NotificationManager get ( ) = context . notificationManager
val notifyId = 101
2021-02-05 09:31:25 +08:00
private var largeIcon : Bitmap ? = null
2020-10-01 22:20:19 +02:00
@RequiresApi ( Build . VERSION_CODES . O )
private fun createNotificationChannel ( ) : String {
val channelId = " my_service "
val channelName = context . getString ( R . string . meshtastic _service _notifications )
2021-02-05 09:31:25 +08:00
val channel = NotificationChannel (
channelId ,
channelName ,
NotificationManager . IMPORTANCE _HIGH
) . apply {
2020-10-01 22:20:19 +02:00
lightColor = Color . BLUE
importance = NotificationManager . IMPORTANCE _NONE
lockscreenVisibility = Notification . VISIBILITY _PRIVATE
}
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)
" "
}
}
/ * *
* 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 openAppIntent : PendingIntent by lazy {
PendingIntent . getActivity ( context , 0 , Intent ( context , MainActivity :: class . java ) , 0 )
}
2021-02-05 09:31:25 +08:00
/ * *
* 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
}
2020-10-01 22:20:19 +02:00
/ * *
* Generate a new version of our notification - reflecting current app state
* /
fun createNotification (
recentReceivedText : DataPacket ? ,
summaryString : String ,
senderName : String
) : Notification {
2021-02-05 09:31:25 +08:00
// We delay making this bitmap until we know we need it
if ( largeIcon == null )
largeIcon = getBitmapFromVectorDrawable ( R . mipmap . ic _launcher2 )
2020-10-01 22:20:19 +02:00
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 )
2021-02-04 08:20:43 +08:00
. 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
2021-02-05 09:31:25 +08:00
. setLargeIcon ( largeIcon ) // we must include a large icon because of a bug in cyanogenmod https://github.com/open-keychain/open-keychain/issues/1356#issue-89493995
2020-10-01 22:20:19 +02:00
. setContentTitle ( summaryString ) // leave this off for now so our notification looks smaller
. setVisibility ( NotificationCompat . VISIBILITY _PUBLIC )
. setContentIntent ( openAppIntent )
// FIXME, show information about the nearest node
// if(shortContent != null) builder.setContentText(shortContent)
// 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 (
NotificationCompat . BigTextStyle ( )
. bigText ( packet . bytes !! . toString ( utf8 ) )
)
}
return builder . build ( )
}
2021-02-05 09:31:25 +08:00
override fun close ( ) {
largeIcon ?. recycle ( )
largeIcon = null
}
2020-10-01 22:20:19 +02:00
}