mirror of
https://github.com/nextcloud/talk-android
synced 2025-07-17 09:45:02 +01:00
Dismiss notification via action
Signed-off-by: Mario Danic <mario@lovelyhq.com>
This commit is contained in:
parent
8252240b3b
commit
aff8595224
@ -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!!))
|
||||
|
@ -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")
|
||||
|
@ -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)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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(
|
||||
|
@ -203,7 +203,7 @@ class ConversationsListViewModel constructor(
|
||||
|
||||
conversationsRepository.saveConversationsForUser(
|
||||
internalUserId,
|
||||
mutableList)
|
||||
mutableList, true)
|
||||
messageData = ""
|
||||
conversationsLoadingLock.unlock()
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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"
|
||||
|
Loading…
Reference in New Issue
Block a user