Use Android 12 CallStyle notification for ongoing calls
This commit is contained in:
parent
58e2fc98aa
commit
57b0255cc4
5 changed files with 149 additions and 59 deletions
|
@ -22,6 +22,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
- New video call UI on foldable device like Galaxy Z Fold
|
||||
- Setting to automatically record all calls
|
||||
- When using a physical keyboard, use left control + enter keys to send message
|
||||
- Using CallStyle notifications for calls for devices running Android 12 or newer
|
||||
|
||||
### Changed
|
||||
- UI has been reworked around SlidingPane component to better handle tablets & foldable devices
|
||||
|
@ -38,6 +39,7 @@ Group changes to describe their impact on the project, as follows:
|
|||
- "Infinite backstack", now each view is stored (at most) once in the backstack
|
||||
- Going back to the dialer when pressing back in a chat room after clicking on a chat message notification
|
||||
- Missing international prefix / phone number in assistant after granting permission
|
||||
- Display issue for incoming call notification preventing to use answer/hangup actions on some Xiaomi devices (like Redmi Note 9S)
|
||||
|
||||
### Removed
|
||||
- Launcher Activity has been replaced by [Splash Screen API](https://developer.android.com/reference/kotlin/androidx/core/splashscreen/SplashScreen)
|
||||
|
|
|
@ -184,6 +184,69 @@ class Api26Compatibility {
|
|||
return builder.build()
|
||||
}
|
||||
|
||||
fun createCallNotification(
|
||||
context: Context,
|
||||
call: Call,
|
||||
notifiable: Notifiable,
|
||||
pendingIntent: PendingIntent,
|
||||
channel: String,
|
||||
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 stringResourceId: Int
|
||||
val iconResourceId: Int
|
||||
when (call.state) {
|
||||
Call.State.Paused, Call.State.Pausing, Call.State.PausedByRemote -> {
|
||||
stringResourceId = R.string.call_notification_paused
|
||||
iconResourceId = R.drawable.topbar_call_paused_notification
|
||||
}
|
||||
Call.State.OutgoingRinging, Call.State.OutgoingProgress, Call.State.OutgoingInit, Call.State.OutgoingEarlyMedia -> {
|
||||
stringResourceId = R.string.call_notification_outgoing
|
||||
iconResourceId = if (call.params.videoEnabled()) {
|
||||
R.drawable.topbar_videocall_notification
|
||||
} else {
|
||||
R.drawable.topbar_call_notification
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
stringResourceId = R.string.call_notification_active
|
||||
iconResourceId = if (call.currentParams.videoEnabled()) {
|
||||
R.drawable.topbar_videocall_notification
|
||||
} else {
|
||||
R.drawable.topbar_call_notification
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val builder = NotificationCompat.Builder(
|
||||
context, channel
|
||||
)
|
||||
.setContentTitle(contact?.fullName ?: displayName)
|
||||
.setContentText(context.getString(stringResourceId))
|
||||
.setSmallIcon(iconResourceId)
|
||||
.setLargeIcon(roundPicture)
|
||||
.addPerson(notificationsManager.getPerson(contact, displayName, roundPicture))
|
||||
.setAutoCancel(false)
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setShowWhen(true)
|
||||
.setOngoing(true)
|
||||
.setColor(ContextCompat.getColor(context, R.color.notification_led_color))
|
||||
.addAction(notificationsManager.getCallDeclineAction(notifiable))
|
||||
|
||||
if (!corePreferences.preventInterfaceFromShowingUp) {
|
||||
builder.setContentIntent(pendingIntent)
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
fun eventVibration(vibrator: Vibrator) {
|
||||
val effect = VibrationEffect.createWaveform(longArrayOf(0L, 100L, 100L), intArrayOf(0, VibrationEffect.DEFAULT_AMPLITUDE, 0), -1)
|
||||
|
|
|
@ -69,7 +69,6 @@ class Api31Compatibility {
|
|||
.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)
|
||||
|
@ -83,5 +82,62 @@ class Api31Compatibility {
|
|||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
fun createCallNotification(
|
||||
context: Context,
|
||||
call: Call,
|
||||
notifiable: Notifiable,
|
||||
pendingIntent: PendingIntent,
|
||||
channel: String,
|
||||
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 isVideo = call.currentParams.videoEnabled()
|
||||
val iconResourceId: Int = when (call.state) {
|
||||
Call.State.Paused, Call.State.Pausing, Call.State.PausedByRemote -> {
|
||||
R.drawable.topbar_call_paused_notification
|
||||
}
|
||||
else -> {
|
||||
if (isVideo) {
|
||||
R.drawable.topbar_videocall_notification
|
||||
} else {
|
||||
R.drawable.topbar_call_notification
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 builder = Notification.Builder(
|
||||
context, channel
|
||||
)
|
||||
.setStyle(Notification.CallStyle.forOngoingCall(caller, declineIntent).setIsVideo(isVideo))
|
||||
.setSmallIcon(iconResourceId)
|
||||
.setAutoCancel(false)
|
||||
.setCategory(Notification.CATEGORY_CALL)
|
||||
.setVisibility(Notification.VISIBILITY_PUBLIC)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setShowWhen(true)
|
||||
.setOngoing(true)
|
||||
.setColor(ContextCompat.getColor(context, R.color.notification_led_color))
|
||||
.setFullScreenIntent(pendingIntent, true) // This is required for CallStyle notification
|
||||
|
||||
if (!corePreferences.preventInterfaceFromShowingUp) {
|
||||
builder.setContentIntent(pendingIntent)
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -187,6 +187,20 @@ class Compatibility {
|
|||
return Api26Compatibility.createIncomingCallNotification(context, call, notifiable, pendingIntent, notificationsManager)
|
||||
}
|
||||
|
||||
fun createCallNotification(
|
||||
context: Context,
|
||||
call: Call,
|
||||
notifiable: Notifiable,
|
||||
pendingIntent: PendingIntent,
|
||||
channel: String,
|
||||
notificationsManager: NotificationsManager
|
||||
): Notification {
|
||||
if (Version.sdkAboveOrEqual(Version.API31_ANDROID_12)) {
|
||||
return Api31Compatibility.createCallNotification(context, call, notifiable, pendingIntent, channel, notificationsManager)
|
||||
}
|
||||
return Api26Compatibility.createCallNotification(context, call, notifiable, pendingIntent, channel, notificationsManager)
|
||||
}
|
||||
|
||||
/* Call */
|
||||
|
||||
fun canDrawOverlay(context: Context): Boolean {
|
||||
|
|
|
@ -482,7 +482,6 @@ class NotificationsManager(private val context: Context) {
|
|||
}
|
||||
|
||||
val notification = builder.build()
|
||||
|
||||
notify(MISSED_CALLS_NOTIF_ID, notification, MISSED_CALL_TAG)
|
||||
}
|
||||
|
||||
|
@ -493,6 +492,18 @@ class NotificationsManager(private val context: Context) {
|
|||
fun displayCallNotification(call: Call, useAsForeground: Boolean = false) {
|
||||
val notifiable = getNotifiableForCall(call)
|
||||
|
||||
val callActivity: Class<*> = when (call.state) {
|
||||
Call.State.Paused, Call.State.Pausing, Call.State.PausedByRemote -> {
|
||||
CallActivity::class.java
|
||||
}
|
||||
Call.State.OutgoingRinging, Call.State.OutgoingProgress, Call.State.OutgoingInit, Call.State.OutgoingEarlyMedia -> {
|
||||
OutgoingCallActivity::class.java
|
||||
}
|
||||
else -> {
|
||||
CallActivity::class.java
|
||||
}
|
||||
}
|
||||
|
||||
val serviceChannel = context.getString(R.string.notification_channel_service_id)
|
||||
val channelToUse = when (val serviceChannelImportance = Compatibility.getChannelImportance(notificationManager, serviceChannel)) {
|
||||
NotificationManagerCompat.IMPORTANCE_NONE -> {
|
||||
|
@ -510,40 +521,6 @@ class NotificationsManager(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
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 stringResourceId: Int
|
||||
val iconResourceId: Int
|
||||
val callActivity: Class<*>
|
||||
when (call.state) {
|
||||
Call.State.Paused, Call.State.Pausing, Call.State.PausedByRemote -> {
|
||||
callActivity = CallActivity::class.java
|
||||
stringResourceId = R.string.call_notification_paused
|
||||
iconResourceId = R.drawable.topbar_call_paused_notification
|
||||
}
|
||||
Call.State.OutgoingRinging, Call.State.OutgoingProgress, Call.State.OutgoingInit, Call.State.OutgoingEarlyMedia -> {
|
||||
callActivity = OutgoingCallActivity::class.java
|
||||
stringResourceId = R.string.call_notification_outgoing
|
||||
iconResourceId = if (call.params.videoEnabled()) {
|
||||
R.drawable.topbar_videocall_notification
|
||||
} else {
|
||||
R.drawable.topbar_call_notification
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
callActivity = CallActivity::class.java
|
||||
stringResourceId = R.string.call_notification_active
|
||||
iconResourceId = if (call.currentParams.videoEnabled()) {
|
||||
R.drawable.topbar_videocall_notification
|
||||
} else {
|
||||
R.drawable.topbar_call_notification
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val callNotificationIntent = Intent(context, callActivity)
|
||||
callNotificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
val pendingIntent = PendingIntent.getActivity(
|
||||
|
@ -553,29 +530,7 @@ class NotificationsManager(private val context: Context) {
|
|||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||
)
|
||||
|
||||
val builder = NotificationCompat.Builder(
|
||||
context, channelToUse
|
||||
)
|
||||
.setContentTitle(contact?.fullName ?: displayName)
|
||||
.setContentText(context.getString(stringResourceId))
|
||||
.setSmallIcon(iconResourceId)
|
||||
.setLargeIcon(roundPicture)
|
||||
.addPerson(getPerson(contact, displayName, roundPicture))
|
||||
.setAutoCancel(false)
|
||||
.setCategory(NotificationCompat.CATEGORY_CALL)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
.setPriority(NotificationCompat.PRIORITY_LOW)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setShowWhen(true)
|
||||
.setOngoing(true)
|
||||
.setColor(ContextCompat.getColor(context, R.color.notification_led_color))
|
||||
.addAction(getCallDeclineAction(notifiable))
|
||||
|
||||
if (!corePreferences.preventInterfaceFromShowingUp) {
|
||||
builder.setContentIntent(pendingIntent)
|
||||
}
|
||||
|
||||
val notification = builder.build()
|
||||
val notification = Compatibility.createCallNotification(context, call, notifiable, pendingIntent, channelToUse, this)
|
||||
Log.i("[Notifications Manager] Notifying call notification [${notifiable.notificationId}]")
|
||||
notify(notifiable.notificationId, notification)
|
||||
|
||||
|
|
Loading…
Reference in a new issue