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
|
- New video call UI on foldable device like Galaxy Z Fold
|
||||||
- Setting to automatically record all calls
|
- Setting to automatically record all calls
|
||||||
- When using a physical keyboard, use left control + enter keys to send message
|
- 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
|
### Changed
|
||||||
- UI has been reworked around SlidingPane component to better handle tablets & foldable devices
|
- 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
|
- "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
|
- 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
|
- 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
|
### Removed
|
||||||
- Launcher Activity has been replaced by [Splash Screen API](https://developer.android.com/reference/kotlin/androidx/core/splashscreen/SplashScreen)
|
- 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()
|
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")
|
@SuppressLint("MissingPermission")
|
||||||
fun eventVibration(vibrator: Vibrator) {
|
fun eventVibration(vibrator: Vibrator) {
|
||||||
val effect = VibrationEffect.createWaveform(longArrayOf(0L, 100L, 100L), intArrayOf(0, VibrationEffect.DEFAULT_AMPLITUDE, 0), -1)
|
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)
|
.setSmallIcon(R.drawable.topbar_call_notification)
|
||||||
.setCategory(Notification.CATEGORY_CALL)
|
.setCategory(Notification.CATEGORY_CALL)
|
||||||
.setVisibility(Notification.VISIBILITY_PUBLIC)
|
.setVisibility(Notification.VISIBILITY_PUBLIC)
|
||||||
.setPriority(Notification.PRIORITY_HIGH)
|
|
||||||
.setWhen(System.currentTimeMillis())
|
.setWhen(System.currentTimeMillis())
|
||||||
.setAutoCancel(false)
|
.setAutoCancel(false)
|
||||||
.setShowWhen(true)
|
.setShowWhen(true)
|
||||||
|
@ -83,5 +82,62 @@ class Api31Compatibility {
|
||||||
|
|
||||||
return builder.build()
|
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)
|
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 */
|
/* Call */
|
||||||
|
|
||||||
fun canDrawOverlay(context: Context): Boolean {
|
fun canDrawOverlay(context: Context): Boolean {
|
||||||
|
|
|
@ -482,7 +482,6 @@ class NotificationsManager(private val context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
val notification = builder.build()
|
val notification = builder.build()
|
||||||
|
|
||||||
notify(MISSED_CALLS_NOTIF_ID, notification, MISSED_CALL_TAG)
|
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) {
|
fun displayCallNotification(call: Call, useAsForeground: Boolean = false) {
|
||||||
val notifiable = getNotifiableForCall(call)
|
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 serviceChannel = context.getString(R.string.notification_channel_service_id)
|
||||||
val channelToUse = when (val serviceChannelImportance = Compatibility.getChannelImportance(notificationManager, serviceChannel)) {
|
val channelToUse = when (val serviceChannelImportance = Compatibility.getChannelImportance(notificationManager, serviceChannel)) {
|
||||||
NotificationManagerCompat.IMPORTANCE_NONE -> {
|
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)
|
val callNotificationIntent = Intent(context, callActivity)
|
||||||
callNotificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
callNotificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||||
val pendingIntent = PendingIntent.getActivity(
|
val pendingIntent = PendingIntent.getActivity(
|
||||||
|
@ -553,29 +530,7 @@ class NotificationsManager(private val context: Context) {
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
)
|
||||||
|
|
||||||
val builder = NotificationCompat.Builder(
|
val notification = Compatibility.createCallNotification(context, call, notifiable, pendingIntent, channelToUse, this)
|
||||||
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()
|
|
||||||
Log.i("[Notifications Manager] Notifying call notification [${notifiable.notificationId}]")
|
Log.i("[Notifications Manager] Notifying call notification [${notifiable.notificationId}]")
|
||||||
notify(notifiable.notificationId, notification)
|
notify(notifiable.notificationId, notification)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue