Dismiss notification via action

Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
Mario Danic 2020-02-23 17:41:51 +01:00
parent 8252240b3b
commit aff8595224
No known key found for this signature in database
GPG Key ID: CDE0BBD2738C4CC0
14 changed files with 220 additions and 134 deletions

View File

@ -71,7 +71,7 @@ class MagicCallActivity : BaseActivity() {
val hideIncomingCallNotificationIntent = Intent(applicationContext, CallService::class.java)
hideIncomingCallNotificationIntent.action = BundleKeys.KEY_SHOW_INCOMING_CALL
hideIncomingCallNotificationIntent.putExtra(BundleKeys.KEY_NOTIFICATION_ID, intent.getLongExtra(BundleKeys.KEY_NOTIFICATION_ID, -1))
applicationContext?.startService(hideIncomingCallNotificationIntent)
//applicationContext?.startService(hideIncomingCallNotificationIntent)
router!!.setRoot(
RouterTransaction.with(CallNotificationController(intent.extras!!))

View File

@ -21,18 +21,14 @@
package com.nextcloud.talk.controllers
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Color
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.ColorDrawable
import android.media.AudioAttributes
import android.media.MediaPlayer
import android.net.Uri
import android.os.*
import android.text.TextUtils
import android.util.Log
import android.os.Bundle
import android.os.Handler
import android.os.Vibrator
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -40,7 +36,6 @@ import android.widget.ImageView
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.content.ContextCompat
import butterknife.BindView
import butterknife.OnClick
import coil.api.load
@ -51,28 +46,21 @@ import coil.transform.BlurTransformation
import coil.transform.CircleCropTransformation
import com.bluelinelabs.conductor.RouterTransaction
import com.bluelinelabs.conductor.changehandler.HorizontalChangeHandler
import com.bluelinelabs.logansquare.LoganSquare
import com.nextcloud.talk.R
import com.nextcloud.talk.api.NcApi
import com.nextcloud.talk.controllers.base.BaseController
import com.nextcloud.talk.events.ConfigurationChangeEvent
import com.nextcloud.talk.models.RingtoneSettings
import com.nextcloud.talk.models.database.ArbitraryStorageEntity
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.RoomsOverall
import com.nextcloud.talk.models.json.participants.Participant
import com.nextcloud.talk.models.json.participants.ParticipantsOverall
import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.newarch.local.models.getCredentials
import com.nextcloud.talk.newarch.services.CallService
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DoNotDisturbUtils
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.database.arbitrarystorage.ArbitraryStorageUtils
import com.nextcloud.talk.utils.singletons.AvatarStatusCodeHolder
import com.uber.autodispose.AutoDispose
import io.reactivex.Observer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.Dispatchers
@ -83,7 +71,6 @@ import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.koin.android.ext.android.inject
import org.michaelevans.colorart.library.ColorArt
import java.io.IOException
class CallNotificationController(private val originalBundle: Bundle) : BaseController() {
@ -116,6 +103,7 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr
private val conversationToken: String
private val userBeingCalled: UserNgEntity?
private val credentials: String?
private val notificationId: Long?
private var currentConversation: Conversation? = null
private var mediaPlayer: MediaPlayer? = null
private var leavingScreen = false
@ -125,6 +113,7 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr
init {
this.conversationToken = originalBundle.getString(BundleKeys.KEY_CONVERSATION_TOKEN)!!
this.userBeingCalled = originalBundle.getParcelable(BundleKeys.KEY_USER_ENTITY)!!
this.notificationId = originalBundle.getLong(BundleKeys.KEY_NOTIFICATION_ID)
credentials = userBeingCalled.getCredentials()
}
@ -233,43 +222,14 @@ class CallNotificationController(private val originalBundle: Bundle) : BaseContr
})
}
private fun handleFromNotification() {
ncApi.getRooms(credentials, ApiUtils.getUrlForRoomEndpoint(userBeingCalled!!.baseUrl))
.subscribeOn(Schedulers.io())
.retry(3)
.observeOn(AndroidSchedulers.mainThread())
.`as`(AutoDispose.autoDisposable(scopeProvider))
.subscribe(object : Observer<RoomsOverall> {
override fun onSubscribe(d: Disposable) {}
override fun onNext(roomsOverall: RoomsOverall) {
for (conversation in roomsOverall.ocs.data) {
if (roomId == conversation.conversationId) {
currentConversation = conversation
runAllThings()
break
}
}
}
override fun onError(e: Throwable) {
}
override fun onComplete() {
}
})
}
private fun runAllThings() {
if (conversationNameTextView != null) {
/*if (conversationNameTextView != null) {
conversationNameTextView!!.text = currentConversation!!.displayName
}
loadAvatar()
checkIfAnyParticipantsRemainInRoom()
showAnswerControls()
showAnswerControls()*/
}
@SuppressLint("LongLogTag")

View File

@ -55,7 +55,7 @@ import com.nextcloud.talk.newarch.domain.usecases.GetNotificationUseCase
import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse
import com.nextcloud.talk.newarch.utils.Images
import com.nextcloud.talk.newarch.utils.MagicJson
import com.nextcloud.talk.newarch.utils.NextcloudRepositoryWithNoCookies
import com.nextcloud.talk.newarch.utils.ComponentsWithEmptyCookieJar
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.bundle.BundleKeys
@ -73,7 +73,7 @@ class MessageNotificationWorker(
workerParams: WorkerParameters
) : CoroutineWorker(context, workerParams), KoinComponent {
val appPreferences: AppPreferences by inject()
private val nextcloudRepositoryWithNoCookies: NextcloudRepositoryWithNoCookies by inject()
private val componentsWithEmptyCookieJar: ComponentsWithEmptyCookieJar by inject()
private val apiErrorHandler: ApiErrorHandler by inject()
override suspend fun doWork(): Result = coroutineScope {
@ -107,7 +107,7 @@ class MessageNotificationWorker(
}
private fun showNotificationWithObjectData(coroutineScope: CoroutineScope, decryptedPushMessage: DecryptedPushMessage, signatureVerification: SignatureVerification, intent: Intent) {
val nextcloudTalkRepository = nextcloudRepositoryWithNoCookies.getRepository()
val nextcloudTalkRepository = componentsWithEmptyCookieJar.getRepository()
val getNotificationUseCase = GetNotificationUseCase(nextcloudTalkRepository, apiErrorHandler)
getNotificationUseCase.invoke(coroutineScope, parametersOf(signatureVerification.userEntity, decryptedPushMessage.notificationId.toString()), object : UseCaseResponse<NotificationOverall> {
override suspend fun onSuccess(result: NotificationOverall) {
@ -193,7 +193,6 @@ class MessageNotificationWorker(
else -> {
// one to one and unknown
BitmapFactory.decodeResource(applicationContext.resources, R.drawable.ic_chat_black_24dp)
}
}

View File

@ -99,7 +99,8 @@ class ConversationsRepositoryImpl(val conversationsDao: ConversationsDao) :
override suspend fun saveConversationsForUser(
userId: Long,
conversations: List<Conversation>
conversations: List<Conversation>,
deleteOutdated: Boolean
): List<Long> {
val map = conversations.map {
it.toConversationEntity()
@ -108,7 +109,8 @@ class ConversationsRepositoryImpl(val conversationsDao: ConversationsDao) :
return conversationsDao
.updateConversationsForUser(
userId,
map.toTypedArray()
map.toTypedArray(),
deleteOutdated
)
}

View File

@ -62,7 +62,7 @@ class NextcloudTalkRepositoryImpl(private val apiService: ApiService) : Nextclou
}
override suspend fun getConversationForUser(user: UserNgEntity, conversationToken: String): ConversationOverall {
return apiService.getConversation(user.getCredentials(), conversationToken)
return apiService.getConversation(user.getCredentials(), ApiUtils.getRoom(user.baseUrl, conversationToken))
}
override suspend fun joinConversationForUser(user: UserNgEntity, conversationToken: String, conversationPassword: String?): ConversationOverall {

View File

@ -46,7 +46,7 @@ import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkReposito
import com.nextcloud.talk.newarch.utils.NetworkUtils
import com.nextcloud.talk.newarch.utils.NetworkUtils.GetProxyRunnable
import com.nextcloud.talk.newarch.utils.NetworkUtils.MagicAuthenticator
import com.nextcloud.talk.newarch.utils.NextcloudRepositoryWithNoCookies
import com.nextcloud.talk.newarch.utils.ComponentsWithEmptyCookieJar
import com.nextcloud.talk.utils.LoggingUtils
import com.nextcloud.talk.utils.preferences.AppPreferences
import com.nextcloud.talk.utils.singletons.AvatarStatusCodeHolder
@ -88,13 +88,13 @@ val NetworkModule = module {
single { createOkHttpClient(androidContext(), get(), get(), get(), get(), get(), get(), get()) }
factory { createApiErrorHandler() }
single { createNextcloudTalkRepository(get()) }
single { createNexcloudRepositoryWithNoCookies(get(), get()) }
single { createComponentsWithEmptyCookieJar(get(), get(), androidApplication()) }
single { createImageLoader(androidApplication(), get()) }
}
fun createNexcloudRepositoryWithNoCookies(okHttpClient: OkHttpClient, retrofit: Retrofit): NextcloudRepositoryWithNoCookies {
return NextcloudRepositoryWithNoCookies(okHttpClient, retrofit)
fun createComponentsWithEmptyCookieJar(okHttpClient: OkHttpClient, retrofit: Retrofit, androidApplication: Application): ComponentsWithEmptyCookieJar {
return ComponentsWithEmptyCookieJar(okHttpClient, retrofit, androidApplication)
}
fun createCookieManager(): CookieManager {

View File

@ -28,12 +28,12 @@ import com.nextcloud.talk.models.json.conversations.Conversation
interface ConversationsRepository {
fun getConversationsForUser(userId: Long, filter: CharSequence?): LiveData<List<Conversation>>
fun getShortcutTargetConversations(userId: Long): LiveData<List<Conversation>>
suspend fun getConversationForUserWithToken(userId: Long, token: String): Conversation?
suspend fun clearConversationsForUser(userId: Long)
suspend fun saveConversationsForUser(
userId: Long,
conversations: List<Conversation>
conversations: List<Conversation>,
deleteOutdated: Boolean
): List<Long>
suspend fun setChangingValueForConversation(

View File

@ -203,7 +203,7 @@ class ConversationsListViewModel constructor(
conversationsRepository.saveConversationsForUser(
internalUserId,
mutableList)
mutableList, true)
messageData = ""
conversationsLoadingLock.unlock()
}

View File

@ -86,7 +86,8 @@ abstract class ConversationsDao {
@Transaction
open suspend fun updateConversationsForUser(
userId: Long,
newConversations: Array<ConversationEntity>
newConversations: Array<ConversationEntity>,
deleteOutdated: Boolean
): List<Long> {
val timestamp = System.currentTimeMillis()
@ -96,7 +97,9 @@ abstract class ConversationsDao {
}
val list = saveConversationsWithInsert(*conversationsWithTimestampApplied.toTypedArray())
deleteConversationsForUserWithTimestamp(userId, timestamp)
if (deleteOutdated) {
deleteConversationsForUserWithTimestamp(userId, timestamp)
}
return list
}
}

View File

@ -4,6 +4,8 @@ import android.app.Notification
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.graphics.BitmapFactory
import android.graphics.drawable.Drawable
import android.media.AudioAttributes
import android.media.AudioManager
import android.net.Uri
@ -13,32 +15,47 @@ import android.util.Base64
import android.util.Log
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.emoji.text.EmojiCompat
import androidx.work.Data
import androidx.work.OneTimeWorkRequest
import androidx.work.WorkManager
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.jobs.MessageNotificationWorker
import com.nextcloud.talk.models.SignatureVerification
import com.nextcloud.talk.models.json.conversations.Conversation
import com.nextcloud.talk.models.json.conversations.ConversationOverall
import com.nextcloud.talk.models.json.push.DecryptedPushMessage
import com.nextcloud.talk.newarch.data.model.ErrorModel
import com.nextcloud.talk.newarch.data.source.remote.ApiErrorHandler
import com.nextcloud.talk.newarch.domain.repository.offline.ConversationsRepository
import com.nextcloud.talk.newarch.domain.repository.offline.UsersRepository
import com.nextcloud.talk.newarch.domain.usecases.GetConversationUseCase
import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse
import com.nextcloud.talk.newarch.local.models.UserNgEntity
import com.nextcloud.talk.newarch.utils.ComponentsWithEmptyCookieJar
import com.nextcloud.talk.newarch.utils.Images
import com.nextcloud.talk.newarch.utils.MagicJson
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.PushUtils
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.preferences.AppPreferences
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.coroutines.*
import kotlinx.serialization.json.Json
import kotlinx.serialization.toUtf8Bytes
import org.koin.core.KoinComponent
import org.koin.core.inject
import org.koin.core.parameter.parametersOf
import retrofit2.Retrofit
import java.security.InvalidKeyException
import java.security.NoSuchAlgorithmException
import java.security.PrivateKey
import java.util.zip.CRC32
import javax.crypto.Cipher
import javax.crypto.NoSuchPaddingException
import kotlin.coroutines.CoroutineContext
@ -51,15 +68,19 @@ class CallService : Service(), KoinComponent, CoroutineScope {
val appPreferences: AppPreferences by inject()
val usersRepository: UsersRepository by inject()
val conversationsRepository: ConversationsRepository by inject()
val retrofit: Retrofit by inject()
val componentsWithEmptyCookieJar: ComponentsWithEmptyCookieJar by inject()
val apiErrorHandler: ApiErrorHandler by inject()
var currentlyActiveNotificationId = 0L
private var activeNotification = ""
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
intent?.let {
if (intent.action == BundleKeys.KEY_INCOMING_PUSH_MESSSAGE) {
decryptMessage(intent.getStringExtra(BundleKeys.KEY_ENCRYPTED_SUBJECT), intent.getStringExtra(BundleKeys.KEY_ENCRYPTED_SIGNATURE))
} else if (intent.action == BundleKeys.KEY_REJECT_INCOMING_CALL || intent.action == BundleKeys.KEY_SHOW_INCOMING_CALL) {
if (intent.getLongExtra(BundleKeys.KEY_NOTIFICATION_ID, -1L) == currentlyActiveNotificationId) {
if (it.action == BundleKeys.KEY_INCOMING_PUSH_MESSSAGE) {
decryptMessage(it.getStringExtra(BundleKeys.KEY_ENCRYPTED_SUBJECT), it.getStringExtra(BundleKeys.KEY_ENCRYPTED_SIGNATURE))
} else if (it.action == BundleKeys.KEY_REJECT_INCOMING_CALL || it.action == BundleKeys.KEY_SHOW_INCOMING_CALL) {
if (it.getStringExtra(BundleKeys.KEY_ACTIVE_NOTIFICATION) == activeNotification) {
stopForeground(true)
} else {
// do nothing? :D
@ -89,6 +110,8 @@ class CallService : Service(), KoinComponent, CoroutineScope {
cipher.init(Cipher.DECRYPT_MODE, privateKey)
val decryptedSubject = cipher.doFinal(base64DecodedSubject)
decryptedPushMessage = LoganSquare.parse(String(decryptedSubject), DecryptedPushMessage::class.java)
val conversation = getConversationForTokenAndUser(signatureVerification.userEntity!!, decryptedPushMessage.id!!)
decryptedPushMessage.apply {
when {
delete -> {
@ -98,71 +121,112 @@ class CallService : Service(), KoinComponent, CoroutineScope {
NotificationUtils.cancelAllNotificationsForAccount(applicationContext, signatureVerification.userEntity!!)
}
type == "call" -> {
val timestamp = System.currentTimeMillis()
if (conversation != null) {
val generatedActiveNotificationId = signatureVerification.userEntity!!.id.toString() + "@" + decryptedPushMessage.notificationId!!.toString()
val fullScreenIntent = Intent(applicationContext, MagicCallActivity::class.java)
fullScreenIntent.action = BundleKeys.KEY_OPEN_INCOMING_CALL
val bundle = Bundle()
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, decryptedPushMessage.id)
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, signatureVerification.userEntity)
bundle.putString(BundleKeys.KEY_ACTIVE_NOTIFICATION, generatedActiveNotificationId)
fullScreenIntent.putExtras(bundle)
val fullScreenIntent = Intent(applicationContext, MagicCallActivity::class.java)
fullScreenIntent.action = BundleKeys.KEY_OPEN_INCOMING_CALL
val bundle = Bundle()
bundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, decryptedPushMessage.id)
bundle.putParcelable(BundleKeys.KEY_USER_ENTITY, signatureVerification.userEntity)
bundle.putLong(BundleKeys.KEY_NOTIFICATION_ID, timestamp)
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)
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 audioAttributesBuilder = AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
audioAttributesBuilder.setUsage(AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST)
val soundUri = NotificationUtils.getCallSoundUri(applicationContext, appPreferences)
val vibrationEffect = NotificationUtils.getVibrationEffect(appPreferences)
val soundUri = NotificationUtils.getCallSoundUri(applicationContext, appPreferences)
val vibrationEffect = NotificationUtils.getVibrationEffect(appPreferences)
val notificationChannelId = NotificationUtils.getNotificationChannelId(applicationContext, applicationContext.resources
.getString(R.string.nc_notification_channel_calls), applicationContext.resources
.getString(R.string.nc_notification_channel_calls_description), true,
NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!,
audioAttributesBuilder.build(), vibrationEffect, false, null)
val notificationChannelId = NotificationUtils.getNotificationChannelId(applicationContext, applicationContext.resources
.getString(R.string.nc_notification_channel_calls), applicationContext.resources
.getString(R.string.nc_notification_channel_calls_description), true,
NotificationManagerCompat.IMPORTANCE_HIGH, soundUri!!,
audioAttributesBuilder.build(), vibrationEffect, false, null)
val userBaseUrl = Uri.parse(signatureVerification.userEntity!!.baseUrl).toString()
val userBaseUrl = Uri.parse(signatureVerification.userEntity!!.baseUrl).toString()
var largeIcon = when (conversation.type) {
Conversation.ConversationType.PUBLIC_CONVERSATION -> {
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)
}
}
val rejectCallIntent = Intent(this@CallService, CallService::class.java)
rejectCallIntent.action = BundleKeys.KEY_REJECT_INCOMING_CALL
rejectCallIntent.putExtra(BundleKeys.KEY_NOTIFICATION_ID, timestamp)
val rejectCallPendingIntent = PendingIntent.getService(this@CallService, 0, rejectCallIntent, 0)
val notificationBuilder = NotificationCompat.Builder(this@CallService, notificationChannelId)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setSmallIcon(R.drawable.ic_call_black_24dp)
.setSubText(userBaseUrl)
.setShowWhen(true)
.setWhen(timestamp)
.setContentTitle(EmojiCompat.get().process(decryptedPushMessage.subject.toString()))
.setAutoCancel(true)
.setOngoing(true)
.addAction(R.drawable.ic_call_end_white_24px, resources.getString(R.string.reject_call), rejectCallPendingIntent)
//.setTimeoutAfter(45000L)
.setFullScreenIntent(fullScreenPendingIntent, true)
.setSound(NotificationUtils.getCallSoundUri(applicationContext, appPreferences), AudioManager.STREAM_RING)
val rejectCallIntent = Intent(this@CallService, CallService::class.java)
rejectCallIntent.action = BundleKeys.KEY_REJECT_INCOMING_CALL
rejectCallIntent.putExtra(BundleKeys.KEY_ACTIVE_NOTIFICATION, generatedActiveNotificationId)
val rejectCallPendingIntent = PendingIntent.getService(this@CallService, 0, rejectCallIntent, PendingIntent.FLAG_UPDATE_CURRENT)
val notificationBuilder = NotificationCompat.Builder(this@CallService, notificationChannelId)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_CALL)
.setSmallIcon(R.drawable.ic_call_black_24dp)
.setLargeIcon(largeIcon)
.setSubText(userBaseUrl)
.setShowWhen(true)
.setWhen(System.currentTimeMillis())
.setContentTitle(EmojiCompat.get().process(decryptedPushMessage.subject.toString()))
.setAutoCancel(true)
.setOngoing(true)
.addAction(R.drawable.ic_call_end_white_24px, resources.getString(R.string.reject_call), rejectCallPendingIntent)
//.setTimeoutAfter(45000L)
.setContentIntent(fullScreenPendingIntent)
.setFullScreenIntent(fullScreenPendingIntent, true)
.setSound(NotificationUtils.getCallSoundUri(applicationContext, appPreferences), AudioManager.STREAM_RING)
if (vibrationEffect != null) {
notificationBuilder.setVibrate(vibrationEffect)
if (vibrationEffect != null) {
notificationBuilder.setVibrate(vibrationEffect)
}
//checkIfCallIsActive(signatureVerification, decryptedPushMessage)
if (conversation.type == Conversation.ConversationType.ONE_TO_ONE_CONVERSATION) {
val target = object : Target {
override fun onSuccess(result: Drawable) {
super.onSuccess(result)
largeIcon = result.toBitmap()
notificationBuilder.setLargeIcon(largeIcon)
showNotification(notificationBuilder, signatureVerification.userEntity!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId)
}
override fun onError(error: Drawable?) {
super.onError(error)
showNotification(notificationBuilder, signatureVerification.userEntity!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId)
}
}
val avatarUrl = ApiUtils.getUrlForAvatarWithName(signatureVerification.userEntity!!.baseUrl, conversation.name, R.dimen.avatar_size)
val imageLoader = componentsWithEmptyCookieJar.getImageLoader()
val request = Images().getRequestForUrl(
imageLoader, applicationContext, avatarUrl, signatureVerification.userEntity,
target, null, CircleCropTransformation())
imageLoader.load(request)
} else {
showNotification(notificationBuilder, signatureVerification.userEntity!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId)
}
}
val notification = notificationBuilder.build()
notification.flags = notification.flags or Notification.FLAG_INSISTENT
//checkIfCallIsActive(signatureVerification, decryptedPushMessage)
currentlyActiveNotificationId = timestamp
startForeground(timestamp.toInt(), notification)
}
else -> {
val json = Json(MagicJson.customJsonConfiguration)
if (conversation != null) {
val json = Json(MagicJson.customJsonConfiguration)
val messageData = Data.Builder()
.putString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE, LoganSquare.serialize(decryptedPushMessage))
.putString(BundleKeys.KEY_SIGNATURE_VERIFICATION, json.stringify(SignatureVerification.serializer(), signatureVerification))
.build()
val pushNotificationWork = OneTimeWorkRequest.Builder(MessageNotificationWorker::class.java).setInputData(messageData).build()
WorkManager.getInstance().enqueue(pushNotificationWork)
val messageData = Data.Builder()
.putString(BundleKeys.KEY_DECRYPTED_PUSH_MESSAGE, LoganSquare.serialize(decryptedPushMessage))
.putString(BundleKeys.KEY_SIGNATURE_VERIFICATION, json.stringify(SignatureVerification.serializer(), signatureVerification))
.build()
val pushNotificationWork = OneTimeWorkRequest.Builder(MessageNotificationWorker::class.java).setInputData(messageData).build()
WorkManager.getInstance().enqueue(pushNotificationWork)
}
}
}
}
@ -182,6 +246,37 @@ class CallService : Service(), KoinComponent, CoroutineScope {
}
}
private suspend fun getConversationForTokenAndUser(user: UserNgEntity, conversationToken: String): Conversation? {
var conversation = conversationsRepository.getConversationForUserWithToken(user.id, conversationToken)
if (conversation == null) {
val getConversationUseCase = GetConversationUseCase(componentsWithEmptyCookieJar.getRepository(), apiErrorHandler)
runBlocking {
getConversationUseCase.invoke(this, parametersOf(user, conversationToken), object : UseCaseResponse<ConversationOverall> {
override suspend fun onSuccess(result: ConversationOverall) {
val internalConversation = result.ocs.data
conversationsRepository.saveConversationsForUser(user.id, listOf(internalConversation), false)
conversation = result.ocs.data
}
override suspend fun onError(errorModel: ErrorModel?) {
conversation = null
}
})
}
}
return conversation
}
private fun showNotification(builder: NotificationCompat.Builder, user: UserNgEntity, internalNotificationId: Long, generatedNotificationId: String) {
activeNotification = generatedNotificationId
val notification = builder.build()
notification.extras.putLong(BundleKeys.KEY_INTERNAL_USER_ID, user.id)
notification.extras.putLong(BundleKeys.KEY_NOTIFICATION_ID, internalNotificationId)
notification.flags = notification.flags or Notification.FLAG_INSISTENT
startForeground(generatedNotificationId.hashCode(), notification)
}
override fun onBind(intent: Intent?): IBinder? {
return null
}

View File

@ -71,7 +71,7 @@ class GlobalService constructor(usersRepository: UsersRepository,
object : UseCaseResponse<ConversationOverall> {
override suspend fun onSuccess(result: ConversationOverall) {
currentUser?.let {
conversationsRepository.saveConversationsForUser(it.id, listOf(result.ocs.data))
conversationsRepository.saveConversationsForUser(it.id, listOf(result.ocs.data), false)
globalServiceInterface.gotConversationInfoForUser(it, result.ocs.data, GlobalServiceInterface.OperationStatus.STATUS_OK)
}
}
@ -94,7 +94,7 @@ class GlobalService constructor(usersRepository: UsersRepository,
object : UseCaseResponse<ConversationOverall> {
override suspend fun onSuccess(result: ConversationOverall) {
currentUser?.let {
conversationsRepository.saveConversationsForUser(it.id, listOf(result.ocs.data))
conversationsRepository.saveConversationsForUser(it.id, listOf(result.ocs.data), false)
currentConversation = conversationsRepository.getConversationForUserWithToken(it.id, result.ocs!!.data!!.token!!)
globalServiceInterface.joinedConversationForUser(it, currentConversation, GlobalServiceInterface.OperationStatus.STATUS_OK)
}

View File

@ -22,6 +22,12 @@
package com.nextcloud.talk.newarch.utils
import android.app.Application
import android.os.Build
import coil.ImageLoader
import coil.decode.GifDecoder
import coil.decode.ImageDecoderDecoder
import coil.decode.SvgDecoder
import com.nextcloud.talk.newarch.data.repository.online.NextcloudTalkRepositoryImpl
import com.nextcloud.talk.newarch.data.source.remote.ApiService
import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkRepository
@ -31,14 +37,35 @@ import org.koin.core.KoinComponent
import retrofit2.Retrofit
import java.net.CookieManager
class NextcloudRepositoryWithNoCookies(
class ComponentsWithEmptyCookieJar(
private val okHttpClient: OkHttpClient,
private val retrofit: Retrofit
private val retrofit: Retrofit,
private val androidApplication: Application
) : KoinComponent {
fun getRepository(): NextcloudTalkRepository {
return NextcloudTalkRepositoryImpl(retrofit.newBuilder().client(
okHttpClient.newBuilder().cookieJar(JavaNetCookieJar(CookieManager())).build())
return NextcloudTalkRepositoryImpl(retrofit.newBuilder().client(getOkHttpClient())
.build().create(ApiService::class.java))
}
fun getOkHttpClient(): OkHttpClient {
return okHttpClient.newBuilder().cookieJar(JavaNetCookieJar(CookieManager())).build()
}
fun getImageLoader(): ImageLoader {
return ImageLoader(androidApplication) {
availableMemoryPercentage(0.5)
bitmapPoolPercentage(0.5)
crossfade(false)
okHttpClient(getOkHttpClient())
componentRegistry {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
add(ImageDecoderDecoder())
} else {
add(GifDecoder())
}
add(SvgDecoder(androidApplication))
}
}
}
}

View File

@ -187,8 +187,7 @@ object NotificationUtils {
if (notification != null && !notification.extras.isEmpty) {
if (conversationUser.id == notification.extras.getLong(
BundleKeys.KEY_INTERNAL_USER_ID
) && notificationId == notification.extras.getLong(BundleKeys.KEY_NOTIFICATION_ID)
BundleKeys.KEY_INTERNAL_USER_ID) && notificationId == notification.extras.getLong(BundleKeys.KEY_NOTIFICATION_ID)
) {
notificationManager.cancel(statusBarNotification.id)
}

View File

@ -59,6 +59,7 @@ object BundleKeys {
val KEY_ACCOUNT = "KEY_ACCOUNT"
val KEY_FILE_ID = "KEY_FILE_ID"
val KEY_NOTIFICATION_ID = "KEY_NOTIFICATION_ID"
val KEY_ACTIVE_NOTIFICATION = "KEY_ACTIVE_NOTIFICATION"
val KEY_CONVERSATION_ID = "KEY_CONVERSATION_ID"
val KEY_ENCRYPTED_SUBJECT = "KEY_ENCRYPTED_SUBJECT"