Fixed custom incoming call notification layout not working on some Xiaomi devices...

This commit is contained in:
Sylvain Berfini 2021-12-11 09:55:18 +01:00
parent 9572da70d4
commit b48b9e42ed
4 changed files with 133 additions and 37 deletions

View file

@ -22,10 +22,7 @@ package org.linphone.compatibility
import android.Manifest import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.annotation.TargetApi import android.annotation.TargetApi
import android.app.Activity import android.app.*
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PictureInPictureParams
import android.content.Context import android.content.Context
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.media.AudioAttributes import android.media.AudioAttributes
@ -33,10 +30,19 @@ import android.os.VibrationEffect
import android.os.Vibrator import android.os.Vibrator
import android.view.WindowManager import android.view.WindowManager
import android.view.inputmethod.EditorInfo import android.view.inputmethod.EditorInfo
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import org.linphone.LinphoneApplication
import org.linphone.R import org.linphone.R
import org.linphone.contact.Contact
import org.linphone.core.Call
import org.linphone.core.tools.Log import org.linphone.core.tools.Log
import org.linphone.notifications.NotificationsManager
import org.linphone.telecom.NativeCallWrapper import org.linphone.telecom.NativeCallWrapper
import org.linphone.utils.ImageUtils
import org.linphone.utils.LinphoneUtils
@TargetApi(26) @TargetApi(26)
class Api26Compatibility { class Api26Compatibility {
@ -128,6 +134,43 @@ class Api26Compatibility {
return WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY return WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
} }
fun createIncomingCallNotificationBuilder(
context: Context,
call: Call,
notificationsManager: NotificationsManager
): NotificationCompat.Builder {
val contact: Contact? = LinphoneApplication.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)
val notificationLayoutHeadsUp = RemoteViews(context.packageName, R.layout.call_incoming_notification_heads_up)
notificationLayoutHeadsUp.setTextViewText(R.id.caller, displayName)
notificationLayoutHeadsUp.setTextViewText(R.id.sip_uri, address)
notificationLayoutHeadsUp.setTextViewText(R.id.incoming_call_info, context.getString(R.string.incoming_call_notification_title))
if (roundPicture != null) {
notificationLayoutHeadsUp.setImageViewBitmap(R.id.caller_picture, roundPicture)
}
return 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)
.setContentTitle(displayName)
.setContentText(context.getString(R.string.incoming_call_notification_title))
.setCategory(NotificationCompat.CATEGORY_CALL)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setWhen(System.currentTimeMillis())
.setAutoCancel(false)
.setShowWhen(true)
.setOngoing(true)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
.setCustomHeadsUpContentView(notificationLayoutHeadsUp)
}
@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)

View file

@ -25,15 +25,20 @@ import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.graphics.Bitmap import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Vibrator import android.os.Vibrator
import android.telephony.TelephonyManager import android.telephony.TelephonyManager
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import java.util.*
import org.linphone.core.Call
import org.linphone.core.ChatRoom import org.linphone.core.ChatRoom
import org.linphone.core.Content import org.linphone.core.Content
import org.linphone.mediastream.Version import org.linphone.mediastream.Version
import org.linphone.notifications.NotificationsManager
import org.linphone.telecom.NativeCallWrapper import org.linphone.telecom.NativeCallWrapper
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@ -165,6 +170,17 @@ class Compatibility {
return WindowManager.LayoutParams.TYPE_PHONE return WindowManager.LayoutParams.TYPE_PHONE
} }
fun createIncomingCallNotificationBuilder(
context: Context,
call: Call,
notificationsManager: NotificationsManager
): NotificationCompat.Builder {
if (Build.MANUFACTURER.lowercase(Locale.getDefault()) == "xiaomi") {
return XiaomiCompatibility.createIncomingCallNotificationBuilder(context, call, notificationsManager)
}
return Api26Compatibility.createIncomingCallNotificationBuilder(context, call, notificationsManager)
}
/* Call */ /* Call */
fun canDrawOverlay(context: Context): Boolean { fun canDrawOverlay(context: Context): Boolean {

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2010-2021 Belledonne Communications SARL.
*
* This file is part of linphone-android
* (see https://www.linphone.org).
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.linphone.compatibility
import android.annotation.TargetApi
import android.app.*
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.R
import org.linphone.contact.Contact
import org.linphone.core.Call
import org.linphone.notifications.NotificationsManager
import org.linphone.utils.ImageUtils
import org.linphone.utils.LinphoneUtils
@TargetApi(26)
class XiaomiCompatibility {
companion object {
fun createIncomingCallNotificationBuilder(
context: Context,
call: Call,
notificationsManager: NotificationsManager
): NotificationCompat.Builder {
val contact: Contact? = LinphoneApplication.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))
.addPerson(notificationsManager.getPerson(contact, displayName, roundPicture))
.setSmallIcon(R.drawable.topbar_call_notification)
.setLargeIcon(roundPicture ?: BitmapFactory.decodeResource(context.resources, R.drawable.avatar))
.setContentTitle(displayName)
.setContentText(address)
.setSubText(context.getString(R.string.incoming_call_notification_title))
.setCategory(NotificationCompat.CATEGORY_CALL)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setWhen(System.currentTimeMillis())
.setAutoCancel(false)
.setShowWhen(true)
.setOngoing(true)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
}
}
}

View file

@ -28,7 +28,6 @@ import android.graphics.Bitmap
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.webkit.MimeTypeMap import android.webkit.MimeTypeMap
import android.widget.RemoteViews
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import androidx.core.app.Person import androidx.core.app.Person
@ -397,7 +396,7 @@ class NotificationsManager(private val context: Context) {
return notifiable return notifiable
} }
private fun getPerson(contact: Contact?, displayName: String, picture: Bitmap?): Person { fun getPerson(contact: Contact?, displayName: String, picture: Bitmap?): Person {
return if (contact != null) { return if (contact != null) {
contact.getPerson() contact.getPerson()
} else { } else {
@ -419,19 +418,12 @@ class NotificationsManager(private val context: Context) {
return return
} }
val address = LinphoneUtils.getDisplayableAddress(call.remoteAddress)
val notifiable = getNotifiableForCall(call) val notifiable = getNotifiableForCall(call)
if (notifiable.notificationId == currentForegroundServiceNotificationId) { if (notifiable.notificationId == currentForegroundServiceNotificationId) {
Log.w("[Notifications Manager] Incoming call notification already displayed by foreground service [${notifiable.notificationId}], skipping") Log.w("[Notifications Manager] Incoming call notification already displayed by foreground service [${notifiable.notificationId}], skipping")
return return
} }
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 incomingCallNotificationIntent = Intent(context, IncomingCallActivity::class.java) val incomingCallNotificationIntent = Intent(context, IncomingCallActivity::class.java)
incomingCallNotificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) incomingCallNotificationIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
val pendingIntent = PendingIntent.getActivity( val pendingIntent = PendingIntent.getActivity(
@ -441,33 +433,11 @@ class NotificationsManager(private val context: Context) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
) )
val notificationLayoutHeadsUp = RemoteViews(context.packageName, R.layout.call_incoming_notification_heads_up) val builder = Compatibility.createIncomingCallNotificationBuilder(context, call, this)
notificationLayoutHeadsUp.setTextViewText(R.id.caller, displayName) builder
notificationLayoutHeadsUp.setTextViewText(R.id.sip_uri, address)
notificationLayoutHeadsUp.setTextViewText(R.id.incoming_call_info, context.getString(R.string.incoming_call_notification_title))
if (roundPicture != null) {
notificationLayoutHeadsUp.setImageViewBitmap(R.id.caller_picture, roundPicture)
}
val builder = NotificationCompat.Builder(context, context.getString(R.string.notification_channel_incoming_call_id))
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.addPerson(getPerson(contact, displayName, roundPicture))
.setSmallIcon(R.drawable.topbar_call_notification)
.setContentTitle(displayName)
.setContentText(context.getString(R.string.incoming_call_notification_title))
.setCategory(NotificationCompat.CATEGORY_CALL)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setWhen(System.currentTimeMillis())
.setAutoCancel(false)
.setShowWhen(true)
.setOngoing(true)
.setColor(ContextCompat.getColor(context, R.color.primary_color))
.setFullScreenIntent(pendingIntent, true) .setFullScreenIntent(pendingIntent, true)
.addAction(getCallDeclineAction(notifiable)) .addAction(getCallDeclineAction(notifiable))
.addAction(getCallAnswerAction(notifiable)) .addAction(getCallAnswerAction(notifiable))
.setCustomHeadsUpContentView(notificationLayoutHeadsUp)
if (!corePreferences.preventInterfaceFromShowingUp) { if (!corePreferences.preventInterfaceFromShowingUp) {
builder.setContentIntent(pendingIntent) builder.setContentIntent(pendingIntent)