diff --git a/app/src/main/java/com/nextcloud/talk/jobs/MessageNotificationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/MessageNotificationWorker.kt index 67e72697d..f76458bb7 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/MessageNotificationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/MessageNotificationWorker.kt @@ -251,7 +251,7 @@ class MessageNotificationWorker( var notificationId = decryptedPushMessage.timestamp.toInt() val notificationInfoBundle = Bundle() - notificationInfoBundle.putLong(BundleKeys.KEY_INTERNAL_USER_ID, signatureVerification.userEntity!!.id!!) + notificationInfoBundle.putLong(BundleKeys.KEY_INTERNAL_USER_ID, signatureVerification.userEntity!!.id) notificationInfoBundle.putString(BundleKeys.KEY_CONVERSATION_TOKEN, decryptedPushMessage.id) notificationInfoBundle.putLong(BundleKeys.KEY_NOTIFICATION_ID, decryptedPushMessage.notificationId!!) notificationBuilder.extras = notificationInfoBundle diff --git a/app/src/main/java/com/nextcloud/talk/newarch/data/repository/offline/ConversationsRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/newarch/data/repository/offline/ConversationsRepositoryImpl.kt index 0ac61c2c6..35b733a20 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/data/repository/offline/ConversationsRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/data/repository/offline/ConversationsRepositoryImpl.kt @@ -83,8 +83,8 @@ class ConversationsRepositoryImpl(val conversationsDao: ConversationsDao) : } } - override suspend fun getConversationForUserWithToken(userId: Long, token: String): Conversation? { - val conversationEntity = conversationsDao.getConversationForUserWithToken(userId, token) + override suspend fun getConversationForUserWithToken(internalUserId: Long, token: String): Conversation? { + val conversationEntity = conversationsDao.getConversationForUserWithToken(internalUserId, token) if (conversationEntity != null) { return conversationEntity.toConversation() } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/data/repository/online/NextcloudTalkRepositoryImpl.kt b/app/src/main/java/com/nextcloud/talk/newarch/data/repository/online/NextcloudTalkRepositoryImpl.kt index 188d1d6aa..b56fd90bc 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/data/repository/online/NextcloudTalkRepositoryImpl.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/data/repository/online/NextcloudTalkRepositoryImpl.kt @@ -99,7 +99,7 @@ class NextcloudTalkRepositoryImpl(private val apiService: ApiService) : Nextclou return apiService.getNotification(user.getCredentials(), ApiUtils.getUrlForNotificationWithId(user.baseUrl, notificationId)) } - override suspend fun getPeersForCall(user: UserNgEntity, conversationToken: String): ParticipantsOverall { + override suspend fun getParticipantsForCall(user: UserNgEntity, conversationToken: String): ParticipantsOverall { return apiService.getPeersForCall(user.getCredentials(), ApiUtils.getUrlForCall(user.baseUrl, conversationToken)) } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/di/module/UseCasesModule.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/di/module/UseCasesModule.kt index 9f6fcf6a7..ce54ff5f1 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/domain/di/module/UseCasesModule.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/di/module/UseCasesModule.kt @@ -51,7 +51,7 @@ val UseCasesModule = module { single { createCreateConversationUseCase(get(), get()) } single { createAddParticipantToConversationUseCase(get(), get()) } single { setConversationPasswordUseCase(get(), get()) } - factory { getPeersForCallUseCase(get(), get()) } + factory { getParticipantsForCallUseCase(get(), get()) } factory { getNotificationUseCase(get(), get()) } factory { createChatViewModelFactory(get(), get(), get(), get(), get(), get()) } } @@ -61,9 +61,9 @@ fun getNotificationUseCase(nextcloudTalkRepository: NextcloudTalkRepository, return GetNotificationUseCase(nextcloudTalkRepository, apiErrorHandler) } -fun getPeersForCallUseCase(nextcloudTalkRepository: NextcloudTalkRepository, - apiErrorHandler: ApiErrorHandler): GetPeersForCallUseCase { - return GetPeersForCallUseCase(nextcloudTalkRepository, apiErrorHandler) +fun getParticipantsForCallUseCase(nextcloudTalkRepository: NextcloudTalkRepository, + apiErrorHandler: ApiErrorHandler): GetParticipantsForCallUseCase { + return GetParticipantsForCallUseCase(nextcloudTalkRepository, apiErrorHandler) } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/offline/ConversationsRepository.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/offline/ConversationsRepository.kt index e70ff7602..8f58a55e8 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/offline/ConversationsRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/offline/ConversationsRepository.kt @@ -28,7 +28,7 @@ import com.nextcloud.talk.models.json.conversations.Conversation interface ConversationsRepository { fun getConversationsForUser(userId: Long, filter: CharSequence?): LiveData> fun getShortcutTargetConversations(userId: Long): LiveData> - suspend fun getConversationForUserWithToken(userId: Long, token: String): Conversation? + suspend fun getConversationForUserWithToken(internalUserId: Long, token: String): Conversation? suspend fun clearConversationsForUser(userId: Long) suspend fun saveConversationsForUser( userId: Long, diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/online/NextcloudTalkRepository.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/online/NextcloudTalkRepository.kt index 62a1fc45b..53180db27 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/online/NextcloudTalkRepository.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/repository/online/NextcloudTalkRepository.kt @@ -37,7 +37,7 @@ import com.nextcloud.talk.newarch.local.models.UserNgEntity interface NextcloudTalkRepository { suspend fun getNotificationForUser(user: UserNgEntity, notificationId: String): NotificationOverall - suspend fun getPeersForCall(user: UserNgEntity, conversationToken: String): ParticipantsOverall + suspend fun getParticipantsForCall(user: UserNgEntity, conversationToken: String): ParticipantsOverall suspend fun setPasswordForConversation(user: UserNgEntity, conversationToken: String, password: String): GenericOverall suspend fun addParticipantToConversation(user: UserNgEntity, conversationToken: String, participantId: String, source: String): AddParticipantOverall suspend fun createConversationForUser(user: UserNgEntity, conversationType: Int, invite: String?, source: String?, conversationName: String?): ConversationOverall diff --git a/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetPeersForCallUseCase.kt b/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetParticipantsForCallUseCase.kt similarity index 90% rename from app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetPeersForCallUseCase.kt rename to app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetParticipantsForCallUseCase.kt index 488f1a98a..22724c980 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetPeersForCallUseCase.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/domain/usecases/GetParticipantsForCallUseCase.kt @@ -28,12 +28,12 @@ import com.nextcloud.talk.newarch.domain.repository.online.NextcloudTalkReposito import com.nextcloud.talk.newarch.domain.usecases.base.UseCase import org.koin.core.parameter.DefinitionParameters -class GetPeersForCallUseCase constructor( +class GetParticipantsForCallUseCase constructor( private val nextcloudTalkRepository: NextcloudTalkRepository, apiErrorHandler: ApiErrorHandler? ) : UseCase(apiErrorHandler) { override suspend fun run(params: Any?): ParticipantsOverall { val definitionParameters = params as DefinitionParameters - return nextcloudTalkRepository.getPeersForCall(definitionParameters[0], definitionParameters[1]) + return nextcloudTalkRepository.getParticipantsForCall(definitionParameters[0], definitionParameters[1]) } } diff --git a/app/src/main/java/com/nextcloud/talk/newarch/local/dao/ConversationsDao.kt b/app/src/main/java/com/nextcloud/talk/newarch/local/dao/ConversationsDao.kt index 923ed9ede..586004fca 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/local/dao/ConversationsDao.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/local/dao/ConversationsDao.kt @@ -80,8 +80,8 @@ abstract class ConversationsDao { timestamp: Long ) - @Query("SELECT * FROM conversations where id = :userId AND token = :token") - abstract suspend fun getConversationForUserWithToken(userId: Long, token: String): ConversationEntity? + @Query("SELECT * FROM conversations where id = :internalUserId AND token = :token") + abstract suspend fun getConversationForUserWithToken(internalUserId: Long, token: String): ConversationEntity? @Transaction open suspend fun updateConversationsForUser( diff --git a/app/src/main/java/com/nextcloud/talk/newarch/services/CallService.kt b/app/src/main/java/com/nextcloud/talk/newarch/services/CallService.kt index ac7de5018..dc07afcb1 100644 --- a/app/src/main/java/com/nextcloud/talk/newarch/services/CallService.kt +++ b/app/src/main/java/com/nextcloud/talk/newarch/services/CallService.kt @@ -10,6 +10,7 @@ import android.media.AudioAttributes import android.media.AudioManager import android.net.Uri import android.os.Bundle +import android.os.Handler import android.os.IBinder import android.util.Base64 import android.util.Log @@ -30,12 +31,16 @@ 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.participants.Participant +import com.nextcloud.talk.models.json.participants.ParticipantsOverall 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.GetParticipantsForCallUseCase +import com.nextcloud.talk.newarch.domain.usecases.base.UseCase import com.nextcloud.talk.newarch.domain.usecases.base.UseCaseResponse import com.nextcloud.talk.newarch.local.models.UserNgEntity import com.nextcloud.talk.newarch.utils.ComponentsWithEmptyCookieJar @@ -57,8 +62,10 @@ import retrofit2.Retrofit import java.security.InvalidKeyException import java.security.NoSuchAlgorithmException import java.security.PrivateKey +import java.util.* import javax.crypto.Cipher import javax.crypto.NoSuchPaddingException +import kotlin.concurrent.timerTask import kotlin.coroutines.CoroutineContext class CallService : Service(), KoinComponent, CoroutineScope { @@ -83,12 +90,7 @@ class CallService : Service(), KoinComponent, CoroutineScope { 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.DISMISS_CALL_NOTIFICATION) { if (it.getStringExtra(BundleKeys.KEY_ACTIVE_NOTIFICATION) == activeNotification) { - stopForeground(true) - if (it.action != BundleKeys.DISMISS_CALL_NOTIFICATION) { - eventBus.post(CallEvent()) - } else { - // do nothing - } + endIncomingConversation(it.action != BundleKeys.DISMISS_CALL_NOTIFICATION) } else { // do nothing? :D } @@ -184,7 +186,6 @@ class CallService : Service(), KoinComponent, CoroutineScope { .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) @@ -193,20 +194,18 @@ class CallService : Service(), KoinComponent, CoroutineScope { 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) + showNotification(notificationBuilder, signatureVerification.userEntity!!, conversation.token!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId) } override fun onError(error: Drawable?) { super.onError(error) - showNotification(notificationBuilder, signatureVerification.userEntity!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId) + showNotification(notificationBuilder, signatureVerification.userEntity!!, conversation.token!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId) } } @@ -219,7 +218,7 @@ class CallService : Service(), KoinComponent, CoroutineScope { imageLoader.load(request) } else { - showNotification(notificationBuilder, signatureVerification.userEntity!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId) + showNotification(notificationBuilder, signatureVerification.userEntity!!, conversation.token!!, decryptedPushMessage.notificationId!!, generatedActiveNotificationId) } } } @@ -253,6 +252,41 @@ class CallService : Service(), KoinComponent, CoroutineScope { } } + private fun checkIsConversationActive(user: UserNgEntity, conversationToken: String, activeNotificationArgument: String) { + if (activeNotificationArgument == activeNotification) { + val getParticipantsForCallUseCase = GetParticipantsForCallUseCase(componentsWithEmptyCookieJar.getRepository(), apiErrorHandler) + getParticipantsForCallUseCase.invoke(this, parametersOf(user, conversationToken), object : UseCaseResponse { + override suspend fun onSuccess(result: ParticipantsOverall) { + val participants = result.ocs.data + if (participants.size > 0 && activeNotificationArgument == activeNotification) { + val activeParticipants = participants.filter { it.participantFlags != Participant.ParticipantFlags.NOT_IN_CALL } + val activeOnAnotherDevice = activeParticipants.filter { it.userId == user.userId } + if (activeParticipants.isNotEmpty() && activeOnAnotherDevice.isEmpty()) { + delay(5000) + checkIsConversationActive(user, conversationToken, activeNotificationArgument) + } else { + endIncomingConversation(true) + } + } else if (activeNotificationArgument == activeNotification) { + endIncomingConversation(true) + } + } + + override suspend fun onError(errorModel: ErrorModel?) { + endIncomingConversation(true) + } + }) + } + } + + private fun endIncomingConversation(triggerEventBus : Boolean) { + activeNotification = "" + stopForeground(true) + if (triggerEventBus) { + eventBus.post(CallEvent()) + } + } + private suspend fun getConversationForTokenAndUser(user: UserNgEntity, conversationToken: String): Conversation? { var conversation = conversationsRepository.getConversationForUserWithToken(user.id, conversationToken) if (conversation == null) { @@ -275,13 +309,15 @@ class CallService : Service(), KoinComponent, CoroutineScope { return conversation } - private fun showNotification(builder: NotificationCompat.Builder, user: UserNgEntity, internalNotificationId: Long, generatedNotificationId: String) { + private fun showNotification(builder: NotificationCompat.Builder, user: UserNgEntity, conversationToken: String, internalNotificationId: Long, generatedNotificationId: String) { + endIncomingConversation(true) 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) + checkIsConversationActive(user, conversationToken, generatedNotificationId) } override fun onBind(intent: Intent?): IBinder? {