Most of the work for group/public calls

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2020-03-12 12:55:39 +01:00
parent b9091e5cc8
commit 624dea0ba1
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
7 changed files with 138 additions and 141 deletions

View File

@ -20,52 +20,15 @@
package com.nextcloud.talk.services.firebase package com.nextcloud.talk.services.firebase
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.app.Notification
import android.app.PendingIntent
import android.content.Intent import android.content.Intent
import android.media.AudioAttributes
import android.media.AudioManager
import android.net.Uri
import android.os.Bundle
import android.util.Base64
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.emoji.text.EmojiCompat
import androidx.work.Data
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
import com.bluelinelabs.logansquare.LoganSquare
import com.google.firebase.messaging.FirebaseMessagingService import com.google.firebase.messaging.FirebaseMessagingService
import com.google.firebase.messaging.RemoteMessage import com.google.firebase.messaging.RemoteMessage
import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MagicCallActivity
import com.nextcloud.talk.jobs.MessageNotificationWorker
import com.nextcloud.talk.models.SignatureVerification
import com.nextcloud.talk.models.json.push.DecryptedPushMessage
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
import com.nextcloud.talk.newarch.services.CallService import com.nextcloud.talk.newarch.services.CallService
import com.nextcloud.talk.newarch.utils.MagicJson
import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount
import com.nextcloud.talk.utils.NotificationUtils.cancelExistingNotificationWithId
import com.nextcloud.talk.utils.PushUtils
import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INCOMING_PUSH_MESSSAGE import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INCOMING_PUSH_MESSSAGE
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_OPEN_INCOMING_CALL
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
import com.nextcloud.talk.utils.preferences.AppPreferences import com.nextcloud.talk.utils.preferences.AppPreferences
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient
import org.greenrobot.eventbus.EventBus
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.inject import org.koin.core.inject
import retrofit2.Retrofit
import java.security.InvalidKeyException
import java.security.NoSuchAlgorithmException
import java.security.PrivateKey
import javax.crypto.Cipher
import javax.crypto.NoSuchPaddingException
class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent { class MagicFirebaseMessagingService : FirebaseMessagingService(), KoinComponent {
val tag: String = "MagicFirebaseMessagingService" val tag: String = "MagicFirebaseMessagingService"

View File

@ -95,7 +95,7 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr
var incomingTextRelativeLayout: RelativeLayout? = null var incomingTextRelativeLayout: RelativeLayout? = null
private val conversation: Conversation = Parcels.unwrap(originalBundle.getParcelable(BundleKeys.KEY_CONVERSATION)) private val conversation: Conversation = Parcels.unwrap(originalBundle.getParcelable(BundleKeys.KEY_CONVERSATION))
private val userBeingCalled: UserNgEntity = originalBundle.getParcelable(BundleKeys.KEY_USER_ENTITY)!! private val userBeingCalled: UserNgEntity = originalBundle.getParcelable(BundleKeys.KEY_USER_ENTITY)!!
private val activeNotification: String = originalBundle.getString(BundleKeys.KEY_ACTIVE_NOTIFICATION)!! private val activeNotification: String? = originalBundle.getString(BundleKeys.KEY_ACTIVE_NOTIFICATION)
override fun inflateView( override fun inflateView(
inflater: LayoutInflater, inflater: LayoutInflater,
@ -115,10 +115,12 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr
} }
private fun dismissIncomingCallNotification() { private fun dismissIncomingCallNotification() {
val hideIncomingCallNotificationIntent = Intent(applicationContext, CallService::class.java) if (activeNotification != null) {
hideIncomingCallNotificationIntent.action = BundleKeys.DISMISS_CALL_NOTIFICATION val hideIncomingCallNotificationIntent = Intent(applicationContext, CallService::class.java)
hideIncomingCallNotificationIntent.putExtra(BundleKeys.KEY_ACTIVE_NOTIFICATION, activeNotification) hideIncomingCallNotificationIntent.action = BundleKeys.DISMISS_CALL_NOTIFICATION
applicationContext?.startService(hideIncomingCallNotificationIntent) hideIncomingCallNotificationIntent.putExtra(BundleKeys.KEY_ACTIVE_NOTIFICATION, activeNotification)
applicationContext?.startService(hideIncomingCallNotificationIntent)
}
} }
@OnClick(R.id.callControlHangupView) @OnClick(R.id.callControlHangupView)

View File

@ -70,7 +70,7 @@ import org.koin.core.inject
import org.koin.core.parameter.parametersOf import org.koin.core.parameter.parametersOf
import java.util.function.Consumer import java.util.function.Consumer
class MessageNotificationWorker( class NotificationWorker(
context: Context, context: Context,
workerParams: WorkerParameters workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams), KoinComponent { ) : CoroutineWorker(context, workerParams), KoinComponent {
@ -82,23 +82,22 @@ class MessageNotificationWorker(
val data = inputData val data = inputData
val decryptedPushMessageString: String = data.getString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE)!! val decryptedPushMessageString: String = data.getString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE)!!
val signatureVerificationString: String = data.getString(BundleKeys.KEY_SIGNATURE_VERIFICATION)!! val signatureVerificationString: String = data.getString(BundleKeys.KEY_SIGNATURE_VERIFICATION)!!
val conversationString: String = data.getString(BundleKeys.KEY_CONVERSATION)!!
val json = Json(MagicJson.customJsonConfiguration) val json = Json(MagicJson.customJsonConfiguration)
val decryptedPushMessage = LoganSquare.parse(decryptedPushMessageString, DecryptedPushMessage::class.java) val decryptedPushMessage = LoganSquare.parse(decryptedPushMessageString, DecryptedPushMessage::class.java)
val signatureVerification = json.parse(SignatureVerification.serializer(), signatureVerificationString) val signatureVerification = json.parse(SignatureVerification.serializer(), signatureVerificationString)
val conversation = json.parse(Conversation.serializer(), conversationString)
// we support Nextcloud Talk 4.0 and up so assuming "no-ping" capability here
val intent = Intent(applicationContext, MainActivity::class.java)
intent.action = BundleKeys.KEY_OPEN_CONVERSATION
intent.putExtra(BundleKeys.KEY_INTERNAL_USER_ID, signatureVerification.userEntity!!.id)
intent.putExtra(BundleKeys.KEY_CONVERSATION_TOKEN, decryptedPushMessage.id)
when (decryptedPushMessage.type) { when (decryptedPushMessage.type) {
"room" -> { "room" -> {
showNotificationWithObjectData(this, decryptedPushMessage, signatureVerification, intent) showNotificationWithObjectData(this, decryptedPushMessage, signatureVerification, conversation)
} }
"chat" -> { "chat" -> {
showNotificationWithObjectData(this, decryptedPushMessage, signatureVerification, intent) showNotificationWithObjectData(this, decryptedPushMessage, signatureVerification, conversation)
}
"call" -> {
showNotification(decryptedPushMessage, signatureVerification, conversation)
} }
else -> { else -> {
// do nothing // do nothing
@ -108,12 +107,11 @@ class MessageNotificationWorker(
Result.success() Result.success()
} }
private fun showNotificationWithObjectData(coroutineScope: CoroutineScope, decryptedPushMessage: DecryptedPushMessage, signatureVerification: SignatureVerification, intent: Intent) { private fun showNotificationWithObjectData(coroutineScope: CoroutineScope, decryptedPushMessage: DecryptedPushMessage, signatureVerification: SignatureVerification, conversation: Conversation) {
val nextcloudTalkRepository = networkComponents.getRepository(false, signatureVerification.userEntity!!.toUser()) val nextcloudTalkRepository = networkComponents.getRepository(false, signatureVerification.userEntity!!.toUser())
val getNotificationUseCase = GetNotificationUseCase(nextcloudTalkRepository, apiErrorHandler) val getNotificationUseCase = GetNotificationUseCase(nextcloudTalkRepository, apiErrorHandler)
getNotificationUseCase.invoke(coroutineScope, parametersOf(signatureVerification.userEntity, decryptedPushMessage.notificationId.toString()), object : UseCaseResponse<NotificationOverall> { getNotificationUseCase.invoke(coroutineScope, parametersOf(signatureVerification.userEntity, decryptedPushMessage.notificationId.toString()), object : UseCaseResponse<NotificationOverall> {
override suspend fun onSuccess(result: NotificationOverall) { override suspend fun onSuccess(result: NotificationOverall) {
var conversationTypeString = "one2one"
val notification = result.ocs.notification val notification = result.ocs.notification
notification.messageRichParameters?.let { messageRichParameters -> notification.messageRichParameters?.let { messageRichParameters ->
@ -138,9 +136,6 @@ class MessageNotificationWorker(
decryptedPushMessage.subject = notification.subject decryptedPushMessage.subject = notification.subject
} }
if (callHashMap.containsKey("call-type")) {
conversationTypeString = callHashMap["call-type"]!!
}
} }
val notificationUser = NotificationUser() val notificationUser = NotificationUser()
@ -156,22 +151,9 @@ class MessageNotificationWorker(
notificationUser.name = guestHashMap["name"] notificationUser.name = guestHashMap["name"]
} }
var conversationType: Conversation.ConversationType = Conversation.ConversationType.ONE_TO_ONE_CONVERSATION
when (conversationTypeString) {
"public" -> {
conversationType = Conversation.ConversationType.PUBLIC_CONVERSATION
}
"group" -> {
conversationType = Conversation.ConversationType.GROUP_CONVERSATION
}
else -> {
// one2one
// do nothing
}
}
decryptedPushMessage.timestamp = notification.datetime.millis decryptedPushMessage.timestamp = notification.datetime.millis
decryptedPushMessage.notificationUser = notificationUser decryptedPushMessage.notificationUser = notificationUser
showNotification(decryptedPushMessage, signatureVerification, conversationType, intent) showNotification(decryptedPushMessage, signatureVerification, conversation)
} }
override suspend fun onError(errorModel: ErrorModel?) { override suspend fun onError(errorModel: ErrorModel?) {
@ -184,8 +166,8 @@ class MessageNotificationWorker(
private fun showNotification( private fun showNotification(
decryptedPushMessage: DecryptedPushMessage, decryptedPushMessage: DecryptedPushMessage,
signatureVerification: SignatureVerification, signatureVerification: SignatureVerification,
conversationType: Conversation.ConversationType = Conversation.ConversationType.ONE_TO_ONE_CONVERSATION, intent: Intent) { conversation: Conversation) {
val largeIcon = when (conversationType) { val largeIcon = when (conversation.type) {
Conversation.ConversationType.PUBLIC_CONVERSATION -> { Conversation.ConversationType.PUBLIC_CONVERSATION -> {
BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_link_black_24px) BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_link_black_24px)
} }
@ -194,12 +176,21 @@ class MessageNotificationWorker(
} }
else -> { else -> {
// one to one and unknown // one to one and unknown
BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_chat_black_24dp) if (decryptedPushMessage.type == "call") {
BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_baseline_person_black_24)
} else {
BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_chat_black_24dp)
}
} }
} }
val pendingIntent: PendingIntent? = PendingIntent.getActivity(applicationContext, var notificationId = decryptedPushMessage.timestamp.toInt()
0, intent, 0)
val pendingIntent = if (decryptedPushMessage.type == "call") {
NotificationUtils.getIncomingCallIPendingIntent(applicationContext, applicationContext, conversation, signatureVerification.userEntity!!, null)
} else {
NotificationUtils.getNotificationPendingIntent(applicationContext, signatureVerification.userEntity!!.id, conversation.token!!)
}
val soundUri = NotificationUtils.getMessageSoundUri(applicationContext, appPreferences) val soundUri = NotificationUtils.getMessageSoundUri(applicationContext, appPreferences)
@ -247,7 +238,6 @@ class MessageNotificationWorker(
notificationBuilder.color = applicationContext.resources.getColor(R.color.colorPrimary) notificationBuilder.color = applicationContext.resources.getColor(R.color.colorPrimary)
} }
var notificationId = decryptedPushMessage.timestamp.toInt()
val notificationInfoBundle = Bundle() val notificationInfoBundle = Bundle()
notificationInfoBundle.putLong(BundleKeys.KEY_INTERNAL_USER_ID, signatureVerification.userEntity!!.id) notificationInfoBundle.putLong(BundleKeys.KEY_INTERNAL_USER_ID, signatureVerification.userEntity!!.id)
@ -290,13 +280,13 @@ class MessageNotificationWorker(
override fun onSuccess(result: Drawable) { override fun onSuccess(result: Drawable) {
super.onSuccess(result) super.onSuccess(result)
person.setIcon(IconCompat.createWithBitmap(result.toBitmap())) person.setIcon(IconCompat.createWithBitmap(result.toBitmap()))
notificationBuilder.setStyle(getStyle(decryptedPushMessage, conversationType, person.build(), style)) notificationBuilder.setStyle(getStyle(decryptedPushMessage, conversation.type!!, person.build(), style))
NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build()) NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build())
} }
override fun onError(error: Drawable?) { override fun onError(error: Drawable?) {
super.onError(error) super.onError(error)
notificationBuilder.setStyle(getStyle(decryptedPushMessage, conversationType, person.build(), style)) notificationBuilder.setStyle(getStyle(decryptedPushMessage, conversation.type!!, person.build(), style))
NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build()) NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build())
} }
} }
@ -308,7 +298,7 @@ class MessageNotificationWorker(
networkComponents.getImageLoader(signatureVerification.userEntity!!.toUser()).load(request) networkComponents.getImageLoader(signatureVerification.userEntity!!.toUser()).load(request)
} else { } else {
notificationBuilder.setStyle(getStyle(decryptedPushMessage, conversationType, person.build(), style)) notificationBuilder.setStyle(getStyle(decryptedPushMessage, conversation.type!!, person.build(), style))
NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build()) NotificationManagerCompat.from(applicationContext).notify(notificationId, notificationBuilder.build())
} }
} }

View File

@ -6,10 +6,8 @@ import android.app.Service
import android.content.Intent import android.content.Intent
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.media.AudioAttributes
import android.media.AudioManager import android.media.AudioManager
import android.net.Uri import android.net.Uri
import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.util.Base64 import android.util.Base64
import android.util.Log import android.util.Log
@ -24,9 +22,8 @@ import coil.target.Target
import coil.transform.CircleCropTransformation import coil.transform.CircleCropTransformation
import com.bluelinelabs.logansquare.LoganSquare import com.bluelinelabs.logansquare.LoganSquare
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MagicCallActivity
import com.nextcloud.talk.events.CallEvent import com.nextcloud.talk.events.CallEvent
import com.nextcloud.talk.jobs.MessageNotificationWorker import com.nextcloud.talk.jobs.NotificationWorker
import com.nextcloud.talk.models.SignatureVerification import com.nextcloud.talk.models.SignatureVerification
import com.nextcloud.talk.models.json.conversations.Conversation import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.ConversationOverall import com.nextcloud.talk.models.json.conversations.ConversationOverall
@ -56,7 +53,6 @@ import org.greenrobot.eventbus.EventBus
import org.koin.core.KoinComponent import org.koin.core.KoinComponent
import org.koin.core.inject import org.koin.core.inject
import org.koin.core.parameter.parametersOf import org.koin.core.parameter.parametersOf
import org.parceler.Parcels
import java.security.InvalidKeyException import java.security.InvalidKeyException
import java.security.NoSuchAlgorithmException import java.security.NoSuchAlgorithmException
import java.security.PrivateKey import java.security.PrivateKey
@ -124,22 +120,10 @@ class CallService : Service(), KoinComponent, CoroutineScope {
deleteAll -> { deleteAll -> {
NotificationUtils.cancelAllNotificationsForAccount(applicationContext, signatureVerification.userEntity!!) NotificationUtils.cancelAllNotificationsForAccount(applicationContext, signatureVerification.userEntity!!)
} }
type == "call" -> { type == "call" && (conversation?.type == Conversation.ConversationType.ONE_TO_ONE_CONVERSATION || conversation?.objectType.equals("share:password")) -> {
if (conversation != null) { if (conversation != null) {
val generatedActiveNotificationId = signatureVerification.userEntity!!.id.toString() + "@" + decryptedPushMessage.notificationId!!.toString() val generatedActiveNotificationId = signatureVerification.userEntity!!.id.toString() + "@" + decryptedPushMessage.notificationId!!.toString()
val fullScreenIntent = Intent(applicationContext, MagicCallActivity::class.java) val fullScreenPendingIntent = NotificationUtils.getIncomingCallIPendingIntent(applicationContext, this@CallService, conversation, signatureVerification.userEntity!!, generatedActiveNotificationId)
fullScreenIntent.action = BundleKeys.KEY_OPEN_INCOMING_CALL
val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_CONVERSATION, Parcels.wrap(conversation))
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, signatureVerification.userEntity)
bundle.putString(BundleKeys.KEY_ACTIVE_NOTIFICATION, generatedActiveNotificationId)
fullScreenIntent.putExtras(bundle)
fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
val fullScreenPendingIntent = PendingIntent.getActivity(this@CallService, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val audioAttributesBuilder = AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
val soundUri = NotificationUtils.getCallSoundUri(applicationContext, appPreferences) val soundUri = NotificationUtils.getCallSoundUri(applicationContext, appPreferences)
val vibrationEffect = NotificationUtils.getVibrationEffect(appPreferences) val vibrationEffect = NotificationUtils.getVibrationEffect(appPreferences)
@ -148,23 +132,17 @@ class CallService : Service(), KoinComponent, CoroutineScope {
.getString(R.string.nc_notification_channel_calls), applicationContext.resources .getString(R.string.nc_notification_channel_calls), applicationContext.resources
.getString(R.string.nc_notification_channel_calls_description), true, .getString(R.string.nc_notification_channel_calls_description), true,
NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!, NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!,
audioAttributesBuilder.build(), vibrationEffect, false, null) NotificationUtils.getCallAudioAttributes(true), vibrationEffect, false, null)
val userBaseUrl = Uri.parse(signatureVerification.userEntity!!.baseUrl).toString() val uri: Uri = Uri.parse(signatureVerification.userEntity?.baseUrl)
var baseUrl = uri.host
var largeIcon = when (conversation.type) { if (baseUrl == null) {
Conversation.ConversationType.PUBLIC_CONVERSATION -> { baseUrl = signatureVerification.userEntity?.baseUrl
BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_link_black_24px)
}
Conversation.ConversationType.GROUP_CONVERSATION -> {
BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_people_group_black_24px)
}
else -> {
// one to one and unknown
BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_user)
}
} }
var largeIcon = BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_baseline_person_black_24)
val rejectCallIntent = Intent(this@CallService, CallService::class.java) val rejectCallIntent = Intent(this@CallService, CallService::class.java)
rejectCallIntent.action = BundleKeys.KEY_REJECT_INCOMING_CALL rejectCallIntent.action = BundleKeys.KEY_REJECT_INCOMING_CALL
rejectCallIntent.putExtra(BundleKeys.KEY_ACTIVE_NOTIFICATION, generatedActiveNotificationId) rejectCallIntent.putExtra(BundleKeys.KEY_ACTIVE_NOTIFICATION, generatedActiveNotificationId)
@ -174,7 +152,7 @@ class CallService : Service(), KoinComponent, CoroutineScope {
.setCategory(NotificationCompat.CATEGORY_CALL) .setCategory(NotificationCompat.CATEGORY_CALL)
.setSmallIcon(R.drawable.ic_call_black_24dp) .setSmallIcon(R.drawable.ic_call_black_24dp)
.setLargeIcon(largeIcon) .setLargeIcon(largeIcon)
.setSubText(userBaseUrl) .setSubText(baseUrl)
.setShowWhen(true) .setShowWhen(true)
.setWhen(System.currentTimeMillis()) .setWhen(System.currentTimeMillis())
.setContentTitle(EmojiCompat.get().process(decryptedPushMessage.subject.toString())) .setContentTitle(EmojiCompat.get().process(decryptedPushMessage.subject.toString()))
@ -189,32 +167,28 @@ class CallService : Service(), KoinComponent, CoroutineScope {
notificationBuilder.setVibrate(vibrationEffect) notificationBuilder.setVibrate(vibrationEffect)
} }
if (conversation.type == Conversation.ConversationType.ONE_TO_ONE_CONVERSATION) { val target = object : Target {
val target = object : Target { override fun onSuccess(result: Drawable) {
override fun onSuccess(result: Drawable) { super.onSuccess(result)
super.onSuccess(result) largeIcon = result.toBitmap()
largeIcon = result.toBitmap() notificationBuilder.setLargeIcon(largeIcon)
notificationBuilder.setLargeIcon(largeIcon) showNotification(notificationBuilder, signatureVerification.userEntity!!, conversation.token!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId)
showNotification(notificationBuilder, signatureVerification.userEntity!!, conversation.token!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId)
}
override fun onError(error: Drawable?) {
super.onError(error)
showNotification(notificationBuilder, signatureVerification.userEntity!!, conversation.token!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId)
}
} }
val avatarUrl = ApiUtils.getUrlForAvatarWithName(signatureVerification.userEntity!!.baseUrl, conversation.name, R.dimen.avatar_size) override fun onError(error: Drawable?) {
val imageLoader = networkComponents.getImageLoader(signatureVerification.userEntity!!.toUser()) super.onError(error)
showNotification(notificationBuilder, signatureVerification.userEntity!!, conversation.token!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId)
val request = Images().getRequestForUrl( }
imageLoader, applicationContext, avatarUrl, signatureVerification.userEntity,
target, null, CircleCropTransformation())
imageLoader.load(request)
} else {
showNotification(notificationBuilder, signatureVerification.userEntity!!, conversation.token!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId)
} }
val avatarUrl = ApiUtils.getUrlForAvatarWithName(signatureVerification.userEntity!!.baseUrl, conversation.name, R.dimen.avatar_size)
val imageLoader = networkComponents.getImageLoader(signatureVerification.userEntity!!.toUser())
val request = Images().getRequestForUrl(
imageLoader, applicationContext, avatarUrl, signatureVerification.userEntity,
target, null, CircleCropTransformation())
imageLoader.load(request)
} }
} }
else -> { else -> {
@ -224,8 +198,9 @@ class CallService : Service(), KoinComponent, CoroutineScope {
val messageData = Data.Builder() val messageData = Data.Builder()
.putString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE, LoganSquare.serialize(decryptedPushMessage)) .putString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE, LoganSquare.serialize(decryptedPushMessage))
.putString(BundleKeys.KEY_SIGNATURE_VERIFICATION, json.stringify(SignatureVerification.serializer(), signatureVerification)) .putString(BundleKeys.KEY_SIGNATURE_VERIFICATION, json.stringify(SignatureVerification.serializer(), signatureVerification))
.putString(BundleKeys.KEY_CONVERSATION, json.stringify(Conversation.serializer(), conversation))
.build() .build()
val pushNotificationWork = OneTimeWorkRequest.Builder(MessageNotificationWorker::class.java).setInputData(messageData).build() val pushNotificationWork = OneTimeWorkRequest.Builder(NotificationWorker::class.java).setInputData(messageData).build()
WorkManager.getInstance().enqueue(pushNotificationWork) WorkManager.getInstance().enqueue(pushNotificationWork)
} }
} }

View File

@ -21,23 +21,26 @@
package com.nextcloud.talk.utils package com.nextcloud.talk.utils
import android.annotation.TargetApi import android.annotation.TargetApi
import android.app.Notification import android.app.*
import android.app.NotificationChannel
import android.app.NotificationChannelGroup
import android.app.NotificationManager
import android.content.Context import android.content.Context
import android.content.Intent
import android.media.AudioAttributes import android.media.AudioAttributes
import android.net.Uri import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle
import android.service.notification.StatusBarNotification import android.service.notification.StatusBarNotification
import android.text.TextUtils import android.text.TextUtils
import androidx.core.app.NotificationManagerCompat import androidx.core.app.NotificationManagerCompat
import com.bluelinelabs.logansquare.LoganSquare import com.bluelinelabs.logansquare.LoganSquare
import com.nextcloud.talk.R import com.nextcloud.talk.R
import com.nextcloud.talk.activities.MagicCallActivity
import com.nextcloud.talk.activities.MainActivity
import com.nextcloud.talk.models.RingtoneSettings import com.nextcloud.talk.models.RingtoneSettings
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.newarch.local.models.UserNgEntity import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.preferences.AppPreferences import com.nextcloud.talk.utils.preferences.AppPreferences
import org.parceler.Parcels
import java.io.IOException import java.io.IOException
import java.util.* import java.util.*
@ -49,6 +52,44 @@ object NotificationUtils {
val NOTIFICATION_CHANNEL_MESSAGES_V3 = "NOTIFICATION_CHANNEL_MESSAGES_V3" val NOTIFICATION_CHANNEL_MESSAGES_V3 = "NOTIFICATION_CHANNEL_MESSAGES_V3"
val NOTIFICATION_CHANNEL_CALLS_V3 = "NOTIFICATION_CHANNEL_CALLS_V3" val NOTIFICATION_CHANNEL_CALLS_V3 = "NOTIFICATION_CHANNEL_CALLS_V3"
fun getNotificationPendingIntent(applicationContext: Context, internalUserId: Long, conversationToken: String): PendingIntent {
val intent = Intent(applicationContext, MainActivity::class.java)
intent.action = BundleKeys.KEY_OPEN_CONVERSATION
intent.putExtra(BundleKeys.KEY_INTERNAL_USER_ID, internalUserId)
intent.putExtra(BundleKeys.KEY_CONVERSATION_TOKEN, conversationToken)
return PendingIntent.getActivity(applicationContext, 0, intent, 0)
}
fun getIncomingCallIPendingIntent(applicationContext: Context, serviceContext: Context, conversation: Conversation, user: UserNgEntity, notificationId: String?): PendingIntent {
val fullScreenIntent = Intent(applicationContext, MagicCallActivity::class.java)
fullScreenIntent.action = BundleKeys.KEY_OPEN_INCOMING_CALL
val bundle = Bundle()
bundle.putParcelable(BundleKeys.KEY_CONVERSATION, Parcels.wrap(conversation))
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, user)
if (notificationId != null) {
bundle.putString(BundleKeys.KEY_ACTIVE_NOTIFICATION, notificationId)
}
fullScreenIntent.putExtras(bundle)
fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
return PendingIntent.getActivity(serviceContext, 0, fullScreenIntent, PendingIntent.FLAG_UPDATE_CURRENT)
}
fun getCallAudioAttributes(isCall: Boolean): AudioAttributes {
return if (isCall) {
val audioAttributesBuilder = AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
audioAttributesBuilder.build()
} else {
val audioAttributesBuilder: AudioAttributes.Builder =
AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT)
audioAttributesBuilder.build()
}
}
fun getVibrationEffect(appPreferences: AppPreferences): LongArray? { fun getVibrationEffect(appPreferences: AppPreferences): LongArray? {
return if (appPreferences.shouldVibrateSetting) { return if (appPreferences.shouldVibrateSetting) {
longArrayOf(0L, 400L, 800L, 600L, 800L, 800L, 800L, 1000L) longArrayOf(0L, 400L, 800L, 600L, 800L, 800L, 800L, 1000L)

View File

@ -29,7 +29,6 @@ object BundleKeys {
val KEY_BASE_URL = "KEY_BASE_URL" val KEY_BASE_URL = "KEY_BASE_URL"
val KEY_IS_ACCOUNT_IMPORT = "KEY_IS_ACCOUNT_IMPORT" val KEY_IS_ACCOUNT_IMPORT = "KEY_IS_ACCOUNT_IMPORT"
val KEY_ORIGINAL_PROTOCOL = "KEY_ORIGINAL_PROTOCOL" val KEY_ORIGINAL_PROTOCOL = "KEY_ORIGINAL_PROTOCOL"
val KEY_ROOM = "KEY_CONVERSATION"
val KEY_OPERATION_CODE = "KEY_OPERATION_CODE" val KEY_OPERATION_CODE = "KEY_OPERATION_CODE"
val KEY_SHARE_INTENT = "KEY_SHARE_INTENT" val KEY_SHARE_INTENT = "KEY_SHARE_INTENT"
val KEY_APP_ITEM_PACKAGE_NAME = "KEY_APP_ITEM_PACKAGE_NAME" val KEY_APP_ITEM_PACKAGE_NAME = "KEY_APP_ITEM_PACKAGE_NAME"

View File

@ -0,0 +1,27 @@
<!--
~ /*
~ * Nextcloud Talk application
~ *
~ * @author Mario Danic
~ * Copyright (C) 2017-2020 Mario Danic <mario@lovelyhq.com>
~ *
~ * 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/>.
~ */
-->
<vector android:autoMirrored="true" android:height="24dp"
android:viewportHeight="24.0" android:viewportWidth="24.0"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/black" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
</vector>