Use Android 12 CallStyle notification for incoming calls

This commit is contained in:
Sylvain Berfini 2021-12-11 10:24:23 +01:00
parent b48b9e42ed
commit 58e2fc98aa
5 changed files with 116 additions and 35 deletions

View file

@ -34,11 +34,13 @@ import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.linphone.LinphoneApplication
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R
import org.linphone.contact.Contact
import org.linphone.core.Call
import org.linphone.core.tools.Log
import org.linphone.notifications.Notifiable
import org.linphone.notifications.NotificationsManager
import org.linphone.telecom.NativeCallWrapper
import org.linphone.utils.ImageUtils
@ -134,12 +136,14 @@ class Api26Compatibility {
return WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
}
fun createIncomingCallNotificationBuilder(
fun createIncomingCallNotification(
context: Context,
call: Call,
notifiable: Notifiable,
pendingIntent: PendingIntent,
notificationsManager: NotificationsManager
): NotificationCompat.Builder {
val contact: Contact? = LinphoneApplication.coreContext.contactsManager.findContactByAddress(call.remoteAddress)
): Notification {
val contact: Contact? = coreContext.contactsManager.findContactByAddress(call.remoteAddress)
val pictureUri = contact?.getContactThumbnailPictureUri()
val roundPicture = ImageUtils.getRoundBitmapFromUri(context, pictureUri)
val displayName = contact?.fullName ?: LinphoneUtils.getDisplayName(call.remoteAddress)
@ -154,7 +158,7 @@ class Api26Compatibility {
notificationLayoutHeadsUp.setImageViewBitmap(R.id.caller_picture, roundPicture)
}
return NotificationCompat.Builder(context, context.getString(R.string.notification_channel_incoming_call_id))
val builder = NotificationCompat.Builder(context, context.getString(R.string.notification_channel_incoming_call_id))
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.addPerson(notificationsManager.getPerson(contact, displayName, roundPicture))
.setSmallIcon(R.drawable.topbar_call_notification)
@ -168,7 +172,16 @@ class Api26Compatibility {
.setShowWhen(true)
.setOngoing(true)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
.setFullScreenIntent(pendingIntent, true)
.addAction(notificationsManager.getCallDeclineAction(notifiable))
.addAction(notificationsManager.getCallAnswerAction(notifiable))
.setCustomHeadsUpContentView(notificationLayoutHeadsUp)
if (!corePreferences.preventInterfaceFromShowingUp) {
builder.setContentIntent(pendingIntent)
}
return builder.build()
}
@SuppressLint("MissingPermission")

View file

@ -20,7 +20,20 @@
package org.linphone.compatibility
import android.annotation.TargetApi
import android.app.Notification
import android.app.PendingIntent
import android.app.Person
import android.content.Context
import androidx.core.content.ContextCompat
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R
import org.linphone.contact.Contact
import org.linphone.core.Call
import org.linphone.notifications.Notifiable
import org.linphone.notifications.NotificationsManager
import org.linphone.utils.ImageUtils
import org.linphone.utils.LinphoneUtils
@TargetApi(31)
class Api31Compatibility {
@ -28,5 +41,47 @@ class Api31Compatibility {
fun getUpdateCurrentPendingIntentFlag(): Int {
return PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
}
fun createIncomingCallNotification(
context: Context,
call: Call,
notifiable: Notifiable,
pendingIntent: PendingIntent,
notificationsManager: NotificationsManager
): Notification {
val contact: Contact? = coreContext.contactsManager.findContactByAddress(call.remoteAddress)
val pictureUri = contact?.getContactThumbnailPictureUri()
val roundPicture = ImageUtils.getRoundBitmapFromUri(context, pictureUri)
val displayName = contact?.fullName ?: LinphoneUtils.getDisplayName(call.remoteAddress)
val person = notificationsManager.getPerson(contact, displayName, roundPicture)
val caller = Person.Builder()
.setName(person.name)
.setIcon(person.icon?.toIcon(context))
.setUri(person.uri)
.setKey(person.key)
.setImportant(person.isImportant)
.build()
val declineIntent = notificationsManager.getCallDeclinePendingIntent(notifiable)
val answerIntent = notificationsManager.getCallAnswerPendingIntent(notifiable)
val builder = Notification.Builder(context, context.getString(R.string.notification_channel_incoming_call_id))
.setStyle(Notification.CallStyle.forIncomingCall(caller, declineIntent, answerIntent))
.setSmallIcon(R.drawable.topbar_call_notification)
.setCategory(Notification.CATEGORY_CALL)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setPriority(Notification.PRIORITY_HIGH)
.setWhen(System.currentTimeMillis())
.setAutoCancel(false)
.setShowWhen(true)
.setOngoing(true)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
.setFullScreenIntent(pendingIntent, true)
if (!corePreferences.preventInterfaceFromShowingUp) {
builder.setContentIntent(pendingIntent)
}
return builder.build()
}
}
}

View file

@ -20,6 +20,8 @@
package org.linphone.compatibility
import android.app.Activity
import android.app.Notification
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
@ -30,7 +32,6 @@ import android.os.Vibrator
import android.telephony.TelephonyManager
import android.view.View
import android.view.WindowManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.fragment.app.Fragment
import java.util.*
@ -38,6 +39,7 @@ import org.linphone.core.Call
import org.linphone.core.ChatRoom
import org.linphone.core.Content
import org.linphone.mediastream.Version
import org.linphone.notifications.Notifiable
import org.linphone.notifications.NotificationsManager
import org.linphone.telecom.NativeCallWrapper
@ -170,15 +172,19 @@ class Compatibility {
return WindowManager.LayoutParams.TYPE_PHONE
}
fun createIncomingCallNotificationBuilder(
fun createIncomingCallNotification(
context: Context,
call: Call,
notifiable: Notifiable,
pendingIntent: PendingIntent,
notificationsManager: NotificationsManager
): NotificationCompat.Builder {
if (Build.MANUFACTURER.lowercase(Locale.getDefault()) == "xiaomi") {
return XiaomiCompatibility.createIncomingCallNotificationBuilder(context, call, notificationsManager)
): Notification {
if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
return Api31Compatibility.createIncomingCallNotification(context, call, notifiable, pendingIntent, notificationsManager)
} else if (Build.MANUFACTURER.lowercase(Locale.getDefault()) == "xiaomi") {
return XiaomiCompatibility.createIncomingCallNotification(context, call, notifiable, pendingIntent, notificationsManager)
}
return Api26Compatibility.createIncomingCallNotificationBuilder(context, call, notificationsManager)
return Api26Compatibility.createIncomingCallNotification(context, call, notifiable, pendingIntent, notificationsManager)
}
/* Call */

View file

@ -25,10 +25,12 @@ import android.content.Context
import android.graphics.BitmapFactory
import androidx.core.app.NotificationCompat
import androidx.core.content.ContextCompat
import org.linphone.LinphoneApplication
import org.linphone.LinphoneApplication.Companion.coreContext
import org.linphone.LinphoneApplication.Companion.corePreferences
import org.linphone.R
import org.linphone.contact.Contact
import org.linphone.core.Call
import org.linphone.notifications.Notifiable
import org.linphone.notifications.NotificationsManager
import org.linphone.utils.ImageUtils
import org.linphone.utils.LinphoneUtils
@ -36,18 +38,20 @@ import org.linphone.utils.LinphoneUtils
@TargetApi(26)
class XiaomiCompatibility {
companion object {
fun createIncomingCallNotificationBuilder(
fun createIncomingCallNotification(
context: Context,
call: Call,
notifiable: Notifiable,
pendingIntent: PendingIntent,
notificationsManager: NotificationsManager
): NotificationCompat.Builder {
val contact: Contact? = LinphoneApplication.coreContext.contactsManager.findContactByAddress(call.remoteAddress)
): Notification {
val contact: Contact? = coreContext.contactsManager.findContactByAddress(call.remoteAddress)
val pictureUri = contact?.getContactThumbnailPictureUri()
val roundPicture = ImageUtils.getRoundBitmapFromUri(context, pictureUri)
val displayName = contact?.fullName ?: LinphoneUtils.getDisplayName(call.remoteAddress)
val address = LinphoneUtils.getDisplayableAddress(call.remoteAddress)
return NotificationCompat.Builder(context, context.getString(R.string.notification_channel_incoming_call_id))
val builder = NotificationCompat.Builder(context, context.getString(R.string.notification_channel_incoming_call_id))
.addPerson(notificationsManager.getPerson(contact, displayName, roundPicture))
.setSmallIcon(R.drawable.topbar_call_notification)
.setLargeIcon(roundPicture ?: BitmapFactory.decodeResource(context.resources, R.drawable.avatar))
@ -62,6 +66,15 @@ class XiaomiCompatibility {
.setShowWhen(true)
.setOngoing(true)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
.setFullScreenIntent(pendingIntent, true)
.addAction(notificationsManager.getCallDeclineAction(notifiable))
.addAction(notificationsManager.getCallAnswerAction(notifiable))
if (!corePreferences.preventInterfaceFromShowingUp) {
builder.setContentIntent(pendingIntent)
}
return builder.build()
}
}
}

View file

@ -55,7 +55,7 @@ import org.linphone.utils.FileUtils
import org.linphone.utils.ImageUtils
import org.linphone.utils.LinphoneUtils
private class Notifiable(val notificationId: Int) {
class Notifiable(val notificationId: Int) {
val messages: ArrayList<NotifiableMessage> = arrayListOf()
var isGroup: Boolean = false
@ -66,7 +66,7 @@ private class Notifiable(val notificationId: Int) {
var dismissNotificationUponReadChatRoom: Boolean = true
}
private class NotifiableMessage(
class NotifiableMessage(
var message: String,
val contact: Contact?,
val sender: String,
@ -433,17 +433,7 @@ class NotificationsManager(private val context: Context) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val builder = Compatibility.createIncomingCallNotificationBuilder(context, call, this)
builder
.setFullScreenIntent(pendingIntent, true)
.addAction(getCallDeclineAction(notifiable))
.addAction(getCallAnswerAction(notifiable))
if (!corePreferences.preventInterfaceFromShowingUp) {
builder.setContentIntent(pendingIntent)
}
val notification = builder.build()
val notification = Compatibility.createIncomingCallNotification(context, call, notifiable, pendingIntent, this)
Log.i("[Notifications Manager] Notifying incoming call notification [${notifiable.notificationId}]")
notify(notifiable.notificationId, notification)
@ -851,43 +841,47 @@ class NotificationsManager(private val context: Context) {
/* Notifications actions */
private fun getCallAnswerAction(notifiable: Notifiable): NotificationCompat.Action {
fun getCallAnswerPendingIntent(notifiable: Notifiable): PendingIntent {
val answerIntent = Intent(context, NotificationBroadcastReceiver::class.java)
answerIntent.action = INTENT_ANSWER_CALL_NOTIF_ACTION
answerIntent.putExtra(INTENT_NOTIF_ID, notifiable.notificationId)
answerIntent.putExtra(INTENT_REMOTE_ADDRESS, notifiable.remoteAddress)
val answerPendingIntent = PendingIntent.getBroadcast(
return PendingIntent.getBroadcast(
context,
notifiable.notificationId,
answerIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
}
fun getCallAnswerAction(notifiable: Notifiable): NotificationCompat.Action {
return NotificationCompat.Action.Builder(
R.drawable.call_audio_start,
context.getString(R.string.incoming_call_notification_answer_action_label),
answerPendingIntent
getCallAnswerPendingIntent(notifiable)
).build()
}
private fun getCallDeclineAction(notifiable: Notifiable): NotificationCompat.Action {
fun getCallDeclinePendingIntent(notifiable: Notifiable): PendingIntent {
val hangupIntent = Intent(context, NotificationBroadcastReceiver::class.java)
hangupIntent.action = INTENT_HANGUP_CALL_NOTIF_ACTION
hangupIntent.putExtra(INTENT_NOTIF_ID, notifiable.notificationId)
hangupIntent.putExtra(INTENT_REMOTE_ADDRESS, notifiable.remoteAddress)
val hangupPendingIntent = PendingIntent.getBroadcast(
return PendingIntent.getBroadcast(
context,
notifiable.notificationId,
hangupIntent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
}
fun getCallDeclineAction(notifiable: Notifiable): NotificationCompat.Action {
return NotificationCompat.Action.Builder(
R.drawable.call_hangup,
context.getString(R.string.incoming_call_notification_hangup_action_label),
hangupPendingIntent
getCallDeclinePendingIntent(notifiable)
).build()
}