mirror of
https://github.com/nextcloud/talk-android
synced 2025-06-23 13:40:43 +01:00
Cleanup
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
d75e84c1fa
commit
550eba9de4
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Mario Danic
|
|
||||||
* Copyright (C) 2017-2019 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/>.
|
|
||||||
*/
|
|
||||||
package com.nextcloud.talk.jobs
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import androidx.work.CoroutineWorker
|
|
||||||
import androidx.work.WorkerParameters
|
|
||||||
import com.nextcloud.talk.api.NcApi
|
|
||||||
import com.nextcloud.talk.events.EventStatus
|
|
||||||
import com.nextcloud.talk.models.RetrofitBucket
|
|
||||||
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SELECTED_GROUPS
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SELECTED_USERS
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_TOKEN
|
|
||||||
import io.reactivex.schedulers.Schedulers
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import org.koin.core.KoinComponent
|
|
||||||
import org.koin.core.inject
|
|
||||||
|
|
||||||
class AddParticipantsToConversation(context: Context,
|
|
||||||
workerParams: WorkerParameters) : CoroutineWorker(context, workerParams), KoinComponent {
|
|
||||||
val ncApi: NcApi by inject()
|
|
||||||
val eventBus: EventBus by inject()
|
|
||||||
val usersRepository: UsersRepository by inject()
|
|
||||||
|
|
||||||
override suspend fun doWork(): Result {
|
|
||||||
val data = inputData
|
|
||||||
val selectedUserIds = data.getStringArray(KEY_SELECTED_USERS)
|
|
||||||
val selectedGroupIds = data.getStringArray(KEY_SELECTED_GROUPS)
|
|
||||||
val user = usersRepository.getUserWithId(data.getLong(KEY_INTERNAL_USER_ID, -1))
|
|
||||||
val conversationToken = data.getString(KEY_TOKEN)
|
|
||||||
val credentials = ApiUtils.getCredentials(user.username, user.token)
|
|
||||||
var retrofitBucket: RetrofitBucket
|
|
||||||
for (userId in selectedUserIds!!) {
|
|
||||||
retrofitBucket = ApiUtils.getRetrofitBucketForAddParticipant(user.baseUrl, conversationToken,
|
|
||||||
userId)
|
|
||||||
ncApi.addParticipant(credentials, retrofitBucket.url, retrofitBucket.queryMap)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.blockingSubscribe()
|
|
||||||
}
|
|
||||||
for (groupId in selectedGroupIds!!) {
|
|
||||||
retrofitBucket = ApiUtils.getRetrofitBucketForAddGroupParticipant(user.baseUrl, conversationToken,
|
|
||||||
groupId)
|
|
||||||
ncApi.addParticipant(credentials, retrofitBucket.url, retrofitBucket.queryMap)
|
|
||||||
.subscribeOn(Schedulers.io())
|
|
||||||
.blockingSubscribe()
|
|
||||||
}
|
|
||||||
eventBus.post(EventStatus(user.id!!, EventStatus.EventType.PARTICIPANTS_UPDATE, true))
|
|
||||||
return Result.success()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,712 +0,0 @@
|
|||||||
/*
|
|
||||||
* Nextcloud Talk application
|
|
||||||
*
|
|
||||||
* @author Mario Danic
|
|
||||||
* Copyright (C) 2017-2018 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/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.nextcloud.talk.jobs
|
|
||||||
|
|
||||||
import android.app.Notification
|
|
||||||
import android.app.NotificationManager
|
|
||||||
import android.app.PendingIntent
|
|
||||||
import android.content.Context
|
|
||||||
import android.content.Intent
|
|
||||||
import android.graphics.Bitmap
|
|
||||||
import android.graphics.BitmapFactory
|
|
||||||
import android.graphics.drawable.Drawable
|
|
||||||
import android.media.AudioAttributes
|
|
||||||
import android.media.MediaPlayer
|
|
||||||
import android.net.Uri
|
|
||||||
import android.os.Build.VERSION
|
|
||||||
import android.os.Build.VERSION_CODES
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.os.VibrationEffect
|
|
||||||
import android.os.Vibrator
|
|
||||||
import android.text.TextUtils
|
|
||||||
import android.util.Base64
|
|
||||||
import android.util.Log
|
|
||||||
import androidx.core.app.NotificationCompat.Builder
|
|
||||||
import androidx.core.app.NotificationCompat.MessagingStyle
|
|
||||||
import androidx.core.app.NotificationCompat.MessagingStyle.Message
|
|
||||||
import androidx.core.app.NotificationManagerCompat
|
|
||||||
import androidx.core.app.Person
|
|
||||||
import androidx.core.graphics.drawable.IconCompat
|
|
||||||
import androidx.core.graphics.drawable.toBitmap
|
|
||||||
import androidx.emoji.text.EmojiCompat
|
|
||||||
import androidx.work.Worker
|
|
||||||
import androidx.work.WorkerParameters
|
|
||||||
import coil.Coil
|
|
||||||
import coil.target.Target
|
|
||||||
import coil.transform.CircleCropTransformation
|
|
||||||
import com.bluelinelabs.logansquare.LoganSquare
|
|
||||||
import com.nextcloud.talk.R.*
|
|
||||||
import com.nextcloud.talk.activities.MagicCallActivity
|
|
||||||
import com.nextcloud.talk.activities.MainActivity
|
|
||||||
import com.nextcloud.talk.api.NcApi
|
|
||||||
import com.nextcloud.talk.models.RingtoneSettings
|
|
||||||
import com.nextcloud.talk.models.SignatureVerification
|
|
||||||
import com.nextcloud.talk.models.database.ArbitraryStorageEntity
|
|
||||||
import com.nextcloud.talk.models.json.chat.ChatUtils
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType.GROUP_CONVERSATION
|
|
||||||
import com.nextcloud.talk.models.json.conversations.Conversation.ConversationType.ONE_TO_ONE_CONVERSATION
|
|
||||||
import com.nextcloud.talk.models.json.conversations.ConversationOverall
|
|
||||||
import com.nextcloud.talk.models.json.notifications.NotificationOverall
|
|
||||||
import com.nextcloud.talk.models.json.push.DecryptedPushMessage
|
|
||||||
import com.nextcloud.talk.models.json.push.NotificationUser
|
|
||||||
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
|
|
||||||
import com.nextcloud.talk.newarch.local.models.UserNgEntity
|
|
||||||
import com.nextcloud.talk.newarch.local.models.getCredentials
|
|
||||||
import com.nextcloud.talk.newarch.utils.Images
|
|
||||||
import com.nextcloud.talk.utils.ApiUtils
|
|
||||||
import com.nextcloud.talk.utils.DoNotDisturbUtils.isDnDActive
|
|
||||||
import com.nextcloud.talk.utils.DoNotDisturbUtils.isInDoNotDisturbWithPriority
|
|
||||||
import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound
|
|
||||||
import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldVibrate
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.NOTIFICATION_CHANNEL_CALLS_V3
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.NOTIFICATION_CHANNEL_MESSAGES_V3
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.cancelExistingNotificationWithId
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.createNotificationChannel
|
|
||||||
import com.nextcloud.talk.utils.NotificationUtils.findNotificationForRoom
|
|
||||||
import com.nextcloud.talk.utils.PushUtils
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_TOKEN
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_FROM_NOTIFICATION_START_CALL
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_INTERNAL_USER_ID
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_ID
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_SIGNATURE
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_SUBJECT
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ID
|
|
||||||
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_USER_ENTITY
|
|
||||||
import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageUtils
|
|
||||||
import com.nextcloud.talk.utils.preferences.AppPreferences
|
|
||||||
import io.reactivex.Observer
|
|
||||||
import io.reactivex.disposables.Disposable
|
|
||||||
import okhttp3.JavaNetCookieJar
|
|
||||||
import okhttp3.OkHttpClient
|
|
||||||
import org.koin.core.KoinComponent
|
|
||||||
import org.koin.core.inject
|
|
||||||
import org.parceler.Parcels
|
|
||||||
import retrofit2.Retrofit
|
|
||||||
import java.io.IOException
|
|
||||||
import java.net.CookieManager
|
|
||||||
import java.security.InvalidKeyException
|
|
||||||
import java.security.NoSuchAlgorithmException
|
|
||||||
import java.security.PrivateKey
|
|
||||||
import java.util.*
|
|
||||||
import java.util.function.Consumer
|
|
||||||
import java.util.zip.CRC32
|
|
||||||
import javax.crypto.Cipher
|
|
||||||
import javax.crypto.NoSuchPaddingException
|
|
||||||
|
|
||||||
class NotificationWorker(
|
|
||||||
context: Context,
|
|
||||||
workerParams: WorkerParameters
|
|
||||||
) : Worker(context, workerParams), KoinComponent {
|
|
||||||
|
|
||||||
val appPreferences: AppPreferences by inject()
|
|
||||||
val retrofit: Retrofit by inject()
|
|
||||||
val okHttpClient: OkHttpClient by inject()
|
|
||||||
val usersRepository: UsersRepository by inject()
|
|
||||||
val arbitraryStorageUtils: ArbitraryStorageUtils by inject()
|
|
||||||
|
|
||||||
private var ncApi: NcApi? = null
|
|
||||||
private var decryptedPushMessage: DecryptedPushMessage? = null
|
|
||||||
private var context: Context? = null
|
|
||||||
private var signatureVerification: SignatureVerification? = null
|
|
||||||
private var conversationType: String? = "one2one"
|
|
||||||
private var credentials: String? = null
|
|
||||||
private var muteCall = false
|
|
||||||
private var importantConversation = false
|
|
||||||
|
|
||||||
|
|
||||||
private fun showNotificationForCallWithNoPing(intent: Intent) {
|
|
||||||
val userEntity: UserNgEntity =
|
|
||||||
signatureVerification!!.userEntity
|
|
||||||
var arbitraryStorageEntity: ArbitraryStorageEntity?
|
|
||||||
|
|
||||||
arbitraryStorageEntity = arbitraryStorageUtils.getStorageSetting(
|
|
||||||
userEntity.id!!,
|
|
||||||
"mute_calls",
|
|
||||||
intent.extras!!.getString(KEY_CONVERSATION_TOKEN)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (arbitraryStorageEntity != null) {
|
|
||||||
muteCall = arbitraryStorageEntity.value!!.toBoolean()
|
|
||||||
}
|
|
||||||
|
|
||||||
arbitraryStorageEntity = arbitraryStorageUtils.getStorageSetting(
|
|
||||||
userEntity.id!!,
|
|
||||||
"important_conversation",
|
|
||||||
intent.extras!!.getString(KEY_CONVERSATION_TOKEN)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (arbitraryStorageEntity != null) {
|
|
||||||
importantConversation = arbitraryStorageEntity.value!!.toBoolean()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isDnDActive()) {
|
|
||||||
if (!isInDoNotDisturbWithPriority()
|
|
||||||
|| !importantConversation
|
|
||||||
|| muteCall
|
|
||||||
) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ncApi!!.getRoom(
|
|
||||||
credentials, ApiUtils.getRoom(
|
|
||||||
userEntity.baseUrl,
|
|
||||||
intent.extras!!.getString(KEY_CONVERSATION_TOKEN)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.blockingSubscribe(object : Observer<ConversationOverall?> {
|
|
||||||
override fun onSubscribe(d: Disposable) {}
|
|
||||||
override fun onNext(conversationOverall: ConversationOverall) {
|
|
||||||
val conversation: Conversation =
|
|
||||||
conversationOverall.ocs.data
|
|
||||||
intent.putExtra(
|
|
||||||
KEY_ROOM,
|
|
||||||
Parcels.wrap(
|
|
||||||
conversation
|
|
||||||
)
|
|
||||||
)
|
|
||||||
if ((conversation.type
|
|
||||||
== ONE_TO_ONE_CONVERSATION) ||
|
|
||||||
!TextUtils.isEmpty(
|
|
||||||
conversation.objectType
|
|
||||||
) && "share:password" == conversation.objectType
|
|
||||||
) {
|
|
||||||
context!!.startActivity(intent)
|
|
||||||
} else {
|
|
||||||
conversationType = if (conversation.type == GROUP_CONVERSATION) {
|
|
||||||
"group"
|
|
||||||
} else {
|
|
||||||
"public"
|
|
||||||
}
|
|
||||||
if (decryptedPushMessage!!.notificationId != Long.MIN_VALUE) {
|
|
||||||
showNotificationWithObjectData(intent)
|
|
||||||
} else {
|
|
||||||
showNotification(intent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {}
|
|
||||||
override fun onComplete() {}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showNotificationWithObjectData(intent: Intent) {
|
|
||||||
val userEntity: UserNgEntity =
|
|
||||||
signatureVerification!!.userEntity
|
|
||||||
ncApi!!.getNotification(
|
|
||||||
credentials, ApiUtils.getUrlForNotificationWithId(
|
|
||||||
userEntity.baseUrl,
|
|
||||||
decryptedPushMessage!!.notificationId.toString()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.blockingSubscribe(object : Observer<NotificationOverall?> {
|
|
||||||
override fun onSubscribe(d: Disposable) {}
|
|
||||||
override fun onNext(notificationOverall: NotificationOverall) {
|
|
||||||
val notification: com.nextcloud.talk.models.json.notifications.Notification =
|
|
||||||
notificationOverall.ocs
|
|
||||||
.notification
|
|
||||||
if (notification.messageRichParameters != null &&
|
|
||||||
notification.messageRichParameters.size > 0
|
|
||||||
) {
|
|
||||||
decryptedPushMessage!!.text = ChatUtils.getParsedMessage(
|
|
||||||
notification.messageRich,
|
|
||||||
notification.messageRichParameters
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
decryptedPushMessage!!.text = notification.message
|
|
||||||
}
|
|
||||||
val subjectRichParameters: HashMap<String, HashMap<String, String>>? =
|
|
||||||
notification
|
|
||||||
.subjectRichParameters
|
|
||||||
decryptedPushMessage!!.timestamp = notification.datetime.millis
|
|
||||||
if (subjectRichParameters != null && subjectRichParameters.size > 0) {
|
|
||||||
val callHashMap =
|
|
||||||
subjectRichParameters["call"]
|
|
||||||
val userHashMap =
|
|
||||||
subjectRichParameters["user"]
|
|
||||||
val guestHashMap =
|
|
||||||
subjectRichParameters["guest"]
|
|
||||||
if (callHashMap != null && callHashMap.size > 0 && callHashMap.containsKey(
|
|
||||||
"name"
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
if (notification.objectType == "chat") {
|
|
||||||
decryptedPushMessage!!.subject = callHashMap["name"]
|
|
||||||
} else {
|
|
||||||
decryptedPushMessage!!.subject = notification.subject
|
|
||||||
}
|
|
||||||
if (callHashMap.containsKey("call-type")) {
|
|
||||||
conversationType = callHashMap["call-type"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val notificationUser =
|
|
||||||
NotificationUser()
|
|
||||||
if (userHashMap != null && !userHashMap.isEmpty()) {
|
|
||||||
notificationUser.id = userHashMap["id"]
|
|
||||||
notificationUser.type = userHashMap["type"]
|
|
||||||
notificationUser.name = userHashMap["name"]
|
|
||||||
decryptedPushMessage!!.notificationUser = notificationUser
|
|
||||||
} else if (guestHashMap != null && !guestHashMap.isEmpty()) {
|
|
||||||
notificationUser.id = guestHashMap["id"]
|
|
||||||
notificationUser.type = guestHashMap["type"]
|
|
||||||
notificationUser.name = guestHashMap["name"]
|
|
||||||
decryptedPushMessage!!.notificationUser = notificationUser
|
|
||||||
}
|
|
||||||
}
|
|
||||||
showNotification(intent)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(e: Throwable) {}
|
|
||||||
override fun onComplete() {}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun showNotification(intent: Intent) {
|
|
||||||
val smallIcon: Int
|
|
||||||
val largeIcon: Bitmap?
|
|
||||||
val category: String
|
|
||||||
val priority = Notification.PRIORITY_HIGH
|
|
||||||
smallIcon = drawable.ic_logo
|
|
||||||
category = if (decryptedPushMessage!!.type == "chat" || (decryptedPushMessage!!.type
|
|
||||||
== "room")
|
|
||||||
) {
|
|
||||||
Notification.CATEGORY_MESSAGE
|
|
||||||
} else {
|
|
||||||
Notification.CATEGORY_CALL
|
|
||||||
}
|
|
||||||
largeIcon = when (conversationType) {
|
|
||||||
"group" -> BitmapFactory.decodeResource(
|
|
||||||
context!!.resources,
|
|
||||||
drawable.ic_people_group_black_24px
|
|
||||||
)
|
|
||||||
"public" -> BitmapFactory.decodeResource(
|
|
||||||
context!!.resources, drawable.ic_link_black_24px
|
|
||||||
)
|
|
||||||
else -> // assuming one2one
|
|
||||||
if (decryptedPushMessage!!.type == "chat" || (decryptedPushMessage!!.type
|
|
||||||
== "room")
|
|
||||||
) {
|
|
||||||
BitmapFactory.decodeResource(
|
|
||||||
context!!.resources, drawable.ic_chat_black_24dp
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
BitmapFactory.decodeResource(
|
|
||||||
context!!.resources, drawable.ic_call_black_24dp
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
intent.action = System.currentTimeMillis()
|
|
||||||
.toString()
|
|
||||||
val pendingIntent: PendingIntent? = PendingIntent.getActivity(
|
|
||||||
context,
|
|
||||||
0, intent, 0
|
|
||||||
)
|
|
||||||
val uri: Uri =
|
|
||||||
Uri.parse(signatureVerification!!.userEntity.baseUrl)
|
|
||||||
val baseUrl = uri.host
|
|
||||||
val notificationBuilder: Builder =
|
|
||||||
Builder(context!!, "1")
|
|
||||||
.setLargeIcon(largeIcon)
|
|
||||||
.setSmallIcon(smallIcon)
|
|
||||||
.setCategory(category)
|
|
||||||
.setPriority(priority)
|
|
||||||
.setSubText(baseUrl)
|
|
||||||
.setWhen(decryptedPushMessage!!.timestamp)
|
|
||||||
.setShowWhen(true)
|
|
||||||
.setContentTitle(
|
|
||||||
EmojiCompat.get().process(decryptedPushMessage!!.subject)
|
|
||||||
)
|
|
||||||
.setContentIntent(pendingIntent)
|
|
||||||
.setAutoCancel(true)
|
|
||||||
if (!TextUtils.isEmpty(decryptedPushMessage!!.text)) {
|
|
||||||
notificationBuilder.setContentText(
|
|
||||||
EmojiCompat.get().process(decryptedPushMessage!!.text)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
if (VERSION.SDK_INT >= 23) {
|
|
||||||
// This method should exist since API 21, but some phones don't have it
|
|
||||||
// So as a safeguard, we don't use it until 23
|
|
||||||
|
|
||||||
notificationBuilder.color = context!!.resources.getColor(color.colorPrimary)
|
|
||||||
}
|
|
||||||
val notificationInfo = Bundle()
|
|
||||||
notificationInfo.putLong(
|
|
||||||
KEY_INTERNAL_USER_ID,
|
|
||||||
signatureVerification!!.userEntity.id!!
|
|
||||||
)
|
|
||||||
// could be an ID or a TOKEN
|
|
||||||
|
|
||||||
notificationInfo.putString(
|
|
||||||
KEY_CONVERSATION_TOKEN,
|
|
||||||
decryptedPushMessage!!.id
|
|
||||||
)
|
|
||||||
notificationInfo.putLong(
|
|
||||||
KEY_NOTIFICATION_ID,
|
|
||||||
decryptedPushMessage!!.notificationId
|
|
||||||
)
|
|
||||||
notificationBuilder.extras = notificationInfo
|
|
||||||
if (VERSION.SDK_INT >= VERSION_CODES.O) {
|
|
||||||
|
|
||||||
/*NotificationUtils.createNotificationChannelGroup(context,
|
|
||||||
Long.toString(crc32.getValue()),
|
|
||||||
groupName);*/
|
|
||||||
|
|
||||||
if (decryptedPushMessage!!.type == "chat" || (decryptedPushMessage!!.type
|
|
||||||
== "room")
|
|
||||||
) {
|
|
||||||
createNotificationChannel(
|
|
||||||
context!!,
|
|
||||||
NOTIFICATION_CHANNEL_MESSAGES_V3,
|
|
||||||
context!!.resources
|
|
||||||
.getString(string.nc_notification_channel_messages),
|
|
||||||
context!!.resources
|
|
||||||
.getString(string.nc_notification_channel_messages), true,
|
|
||||||
NotificationManager.IMPORTANCE_HIGH
|
|
||||||
)
|
|
||||||
notificationBuilder.setChannelId(
|
|
||||||
NOTIFICATION_CHANNEL_MESSAGES_V3
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
createNotificationChannel(
|
|
||||||
context!!,
|
|
||||||
NOTIFICATION_CHANNEL_CALLS_V3,
|
|
||||||
context!!.resources
|
|
||||||
.getString(string.nc_notification_channel_calls),
|
|
||||||
context!!.resources
|
|
||||||
.getString(string.nc_notification_channel_calls_description),
|
|
||||||
true,
|
|
||||||
NotificationManager.IMPORTANCE_HIGH
|
|
||||||
)
|
|
||||||
notificationBuilder.setChannelId(
|
|
||||||
NOTIFICATION_CHANNEL_CALLS_V3
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// red color for the lights
|
|
||||||
|
|
||||||
notificationBuilder.setLights(-0x10000, 200, 200)
|
|
||||||
}
|
|
||||||
notificationBuilder.setContentIntent(pendingIntent)
|
|
||||||
var crc32 = CRC32()
|
|
||||||
val groupName =
|
|
||||||
signatureVerification!!.userEntity.id.toString() + "@" + decryptedPushMessage!!.id
|
|
||||||
crc32.update(groupName.toByteArray())
|
|
||||||
notificationBuilder.setGroup(crc32.value.toString())
|
|
||||||
|
|
||||||
// notificationId
|
|
||||||
|
|
||||||
crc32 = CRC32()
|
|
||||||
val stringForCrc = System.currentTimeMillis()
|
|
||||||
.toString()
|
|
||||||
crc32.update(stringForCrc.toByteArray())
|
|
||||||
val activeStatusBarNotification =
|
|
||||||
findNotificationForRoom(
|
|
||||||
context,
|
|
||||||
signatureVerification!!.userEntity, decryptedPushMessage!!.id
|
|
||||||
)
|
|
||||||
val notificationId: Int
|
|
||||||
notificationId = activeStatusBarNotification?.id ?: crc32.value.toInt()
|
|
||||||
if (VERSION.SDK_INT >= VERSION_CODES.N && decryptedPushMessage!!.notificationUser != null && decryptedPushMessage!!.type == "chat") {
|
|
||||||
var style: MessagingStyle? = null
|
|
||||||
if (activeStatusBarNotification != null) {
|
|
||||||
val activeNotification: Notification? =
|
|
||||||
activeStatusBarNotification.notification
|
|
||||||
style =
|
|
||||||
MessagingStyle.extractMessagingStyleFromNotification(
|
|
||||||
activeNotification
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val person = Person.Builder()
|
|
||||||
.setKey(
|
|
||||||
signatureVerification!!.userEntity.id.toString() +
|
|
||||||
"@" + decryptedPushMessage!!.notificationUser.id
|
|
||||||
)
|
|
||||||
.setName(
|
|
||||||
EmojiCompat.get().process(
|
|
||||||
decryptedPushMessage!!.notificationUser.name
|
|
||||||
)
|
|
||||||
)
|
|
||||||
.setBot(decryptedPushMessage!!.notificationUser.type == "bot")
|
|
||||||
notificationBuilder.setOnlyAlertOnce(true)
|
|
||||||
if (decryptedPushMessage!!.notificationUser.type == "user" || decryptedPushMessage!!.notificationUser.type == "guest") {
|
|
||||||
var avatarUrl: String? = ApiUtils.getUrlForAvatarWithName(
|
|
||||||
signatureVerification!!.userEntity.baseUrl,
|
|
||||||
decryptedPushMessage!!.notificationUser.id,
|
|
||||||
dimen.avatar_size
|
|
||||||
)
|
|
||||||
if (decryptedPushMessage!!.notificationUser.type == "guest") {
|
|
||||||
avatarUrl = ApiUtils.getUrlForAvatarWithNameForGuests(
|
|
||||||
signatureVerification!!.userEntity.baseUrl,
|
|
||||||
decryptedPushMessage!!.notificationUser.name,
|
|
||||||
dimen.avatar_size
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val target = object : Target {
|
|
||||||
override fun onSuccess(result: Drawable) {
|
|
||||||
super.onSuccess(result)
|
|
||||||
person.setIcon(IconCompat.createWithBitmap(result.toBitmap()))
|
|
||||||
notificationBuilder.setStyle(
|
|
||||||
getStyle(
|
|
||||||
person.build(),
|
|
||||||
style
|
|
||||||
)
|
|
||||||
)
|
|
||||||
sendNotificationWithId(notificationId, notificationBuilder.build())
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onError(error: Drawable?) {
|
|
||||||
super.onError(error)
|
|
||||||
notificationBuilder.setStyle(getStyle(person.build(), style))
|
|
||||||
sendNotificationWithId(notificationId, notificationBuilder.build())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val request = Images().getRequestForUrl(
|
|
||||||
Coil.loader(), context!!, avatarUrl!!, signatureVerification!!.userEntity,
|
|
||||||
target, null, CircleCropTransformation()
|
|
||||||
)
|
|
||||||
|
|
||||||
Coil.loader()
|
|
||||||
.load(request)
|
|
||||||
} else {
|
|
||||||
notificationBuilder.setStyle(getStyle(person.build(), style))
|
|
||||||
sendNotificationWithId(notificationId, notificationBuilder.build())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sendNotificationWithId(notificationId, notificationBuilder.build())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun sendNotificationWithId(
|
|
||||||
notificationId: Int,
|
|
||||||
notification: Notification
|
|
||||||
) {
|
|
||||||
val notificationManager =
|
|
||||||
NotificationManagerCompat.from(context!!)
|
|
||||||
notificationManager.notify(notificationId, notification)
|
|
||||||
if (notification.category != Notification.CATEGORY_CALL) {
|
|
||||||
val ringtonePreferencesString: String?
|
|
||||||
val soundUri: Uri?
|
|
||||||
ringtonePreferencesString = appPreferences.messageRingtoneUri
|
|
||||||
soundUri = if (TextUtils.isEmpty(ringtonePreferencesString)) {
|
|
||||||
Uri.parse(
|
|
||||||
"android.resource://" + context!!.packageName +
|
|
||||||
"/raw/librem_by_feandesign_message"
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
val ringtoneSettings: RingtoneSettings =
|
|
||||||
LoganSquare.parse(
|
|
||||||
ringtonePreferencesString, RingtoneSettings::class.java
|
|
||||||
)
|
|
||||||
ringtoneSettings.ringtoneUri
|
|
||||||
} catch (exception: IOException) {
|
|
||||||
Uri.parse(
|
|
||||||
"android.resource://" + context!!.packageName +
|
|
||||||
"/raw/librem_by_feandesign_message"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (soundUri != null && (shouldPlaySound(importantConversation))
|
|
||||||
) {
|
|
||||||
val audioAttributesBuilder: AudioAttributes.Builder =
|
|
||||||
AudioAttributes.Builder()
|
|
||||||
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
|
|
||||||
if (decryptedPushMessage!!.type == "chat" || (decryptedPushMessage!!.type
|
|
||||||
== "room")
|
|
||||||
) {
|
|
||||||
audioAttributesBuilder.setUsage(
|
|
||||||
AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
audioAttributesBuilder.setUsage(
|
|
||||||
AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val mediaPlayer = MediaPlayer()
|
|
||||||
try {
|
|
||||||
mediaPlayer.setDataSource(context!!, soundUri)
|
|
||||||
mediaPlayer.setAudioAttributes(audioAttributesBuilder.build())
|
|
||||||
mediaPlayer.setOnPreparedListener { mp: MediaPlayer? -> mediaPlayer.start() }
|
|
||||||
mediaPlayer.setOnCompletionListener { obj: MediaPlayer -> obj.release() }
|
|
||||||
mediaPlayer.prepareAsync()
|
|
||||||
} catch (e: IOException) {
|
|
||||||
Log.e(TAG, "Failed to set data source")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (shouldVibrate(appPreferences.shouldVibrateSetting)
|
|
||||||
) {
|
|
||||||
val vibrator =
|
|
||||||
context!!.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator
|
|
||||||
if (VERSION.SDK_INT >= VERSION_CODES.O) {
|
|
||||||
vibrator.vibrate(
|
|
||||||
VibrationEffect.createOneShot(
|
|
||||||
500, VibrationEffect.DEFAULT_AMPLITUDE
|
|
||||||
)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
vibrator.vibrate(500)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun doWork(): Result {
|
|
||||||
context = applicationContext
|
|
||||||
val data = inputData
|
|
||||||
val subject =
|
|
||||||
data.getString(KEY_NOTIFICATION_SUBJECT)
|
|
||||||
val signature =
|
|
||||||
data.getString(KEY_NOTIFICATION_SIGNATURE)
|
|
||||||
val base64DecodedSubject: ByteArray = Base64.decode(subject, Base64.DEFAULT)
|
|
||||||
val base64DecodedSignature: ByteArray = Base64.decode(signature, Base64.DEFAULT)
|
|
||||||
val pushUtils = PushUtils(usersRepository)
|
|
||||||
val privateKey = pushUtils.readKeyFromFile(false) as PrivateKey
|
|
||||||
try {
|
|
||||||
signatureVerification = pushUtils.verifySignature(
|
|
||||||
base64DecodedSignature,
|
|
||||||
base64DecodedSubject
|
|
||||||
)
|
|
||||||
if (signatureVerification!!.signatureValid) {
|
|
||||||
val cipher: Cipher = Cipher.getInstance("RSA/None/PKCS1Padding")
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, privateKey)
|
|
||||||
val decryptedSubject: ByteArray? = cipher.doFinal(base64DecodedSubject)
|
|
||||||
decryptedPushMessage =
|
|
||||||
LoganSquare.parse(
|
|
||||||
decryptedSubject!!.toString(Charsets.UTF_8),
|
|
||||||
DecryptedPushMessage::class.java
|
|
||||||
)
|
|
||||||
decryptedPushMessage!!.timestamp = System.currentTimeMillis()
|
|
||||||
if (decryptedPushMessage!!.delete) {
|
|
||||||
cancelExistingNotificationWithId(
|
|
||||||
context,
|
|
||||||
signatureVerification!!.userEntity, decryptedPushMessage!!.notificationId
|
|
||||||
)
|
|
||||||
} else if (decryptedPushMessage!!.deleteAll) {
|
|
||||||
cancelAllNotificationsForAccount(
|
|
||||||
context,
|
|
||||||
signatureVerification!!.userEntity
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
credentials = signatureVerification!!.userEntity.getCredentials()
|
|
||||||
|
|
||||||
ncApi = retrofit.newBuilder()
|
|
||||||
.client(
|
|
||||||
okHttpClient.newBuilder().cookieJar(
|
|
||||||
JavaNetCookieJar(CookieManager())
|
|
||||||
).build()
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
.create(
|
|
||||||
NcApi::class.java
|
|
||||||
)
|
|
||||||
val hasChatSupport =
|
|
||||||
signatureVerification!!.userEntity.hasSpreedFeatureCapability("chat-v2")
|
|
||||||
val shouldShowNotification = decryptedPushMessage!!.app == "spreed"
|
|
||||||
if (shouldShowNotification) {
|
|
||||||
val intent: Intent
|
|
||||||
val bundle = Bundle()
|
|
||||||
val startACall =
|
|
||||||
decryptedPushMessage!!.type == "call" || !hasChatSupport
|
|
||||||
intent = if (startACall) {
|
|
||||||
Intent(
|
|
||||||
context, MagicCallActivity::class.java
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Intent(
|
|
||||||
context, MainActivity::class.java
|
|
||||||
)
|
|
||||||
}
|
|
||||||
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK
|
|
||||||
if (!signatureVerification!!.userEntity.hasSpreedFeatureCapability("no-ping")) {
|
|
||||||
bundle.putString(
|
|
||||||
KEY_ROOM_ID,
|
|
||||||
decryptedPushMessage!!.id
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
bundle.putString(
|
|
||||||
KEY_CONVERSATION_TOKEN,
|
|
||||||
decryptedPushMessage!!.id
|
|
||||||
)
|
|
||||||
}
|
|
||||||
bundle.putParcelable(
|
|
||||||
KEY_USER_ENTITY,
|
|
||||||
signatureVerification!!.userEntity
|
|
||||||
)
|
|
||||||
bundle.putBoolean(
|
|
||||||
KEY_FROM_NOTIFICATION_START_CALL,
|
|
||||||
startACall
|
|
||||||
)
|
|
||||||
intent.putExtras(bundle)
|
|
||||||
when (decryptedPushMessage!!.type) {
|
|
||||||
"call" -> if (!bundle.containsKey(
|
|
||||||
KEY_CONVERSATION_TOKEN
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
context!!.startActivity(intent)
|
|
||||||
} else {
|
|
||||||
showNotificationForCallWithNoPing(intent)
|
|
||||||
}
|
|
||||||
"room" -> if (bundle.containsKey(
|
|
||||||
KEY_CONVERSATION_TOKEN
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
showNotificationWithObjectData(intent)
|
|
||||||
}
|
|
||||||
"chat" -> if (decryptedPushMessage!!.notificationId != Long.MIN_VALUE) {
|
|
||||||
showNotificationWithObjectData(intent)
|
|
||||||
} else {
|
|
||||||
showNotification(intent)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e1: NoSuchAlgorithmException) {
|
|
||||||
Log.d(
|
|
||||||
TAG,
|
|
||||||
"No proper algorithm to decrypt the message " + e1.localizedMessage
|
|
||||||
)
|
|
||||||
} catch (e1: NoSuchPaddingException) {
|
|
||||||
Log.d(
|
|
||||||
TAG,
|
|
||||||
"No proper padding to decrypt the message " + e1.localizedMessage
|
|
||||||
)
|
|
||||||
} catch (e1: InvalidKeyException) {
|
|
||||||
Log.d(
|
|
||||||
TAG, "Invalid private key " + e1.localizedMessage
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return Result.success()
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TAG = "NotificationWorker"
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user