diff --git a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt index a25927dd4..e56f4f898 100644 --- a/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/activities/MainActivity.kt @@ -28,7 +28,6 @@ import com.nextcloud.talk.account.ServerSelectionActivity import com.nextcloud.talk.account.WebViewLoginActivity import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication -import com.nextcloud.talk.callnotification.CallNotificationActivity import com.nextcloud.talk.chat.ChatActivity import com.nextcloud.talk.conversationlist.ConversationsListActivity import com.nextcloud.talk.data.user.model.User @@ -245,19 +244,13 @@ class MainActivity : BaseActivity(), ActionBarProvider { if (user != null && userManager.setUserAsActive(user).blockingGet()) { if (intent.hasExtra(BundleKeys.KEY_REMOTE_TALK_SHARE)) { if (intent.getBooleanExtra(BundleKeys.KEY_REMOTE_TALK_SHARE, false)) { - val intent = Intent(this, InvitationsActivity::class.java) - startActivity(intent) - } - } else if (intent.hasExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL)) { - if (intent.getBooleanExtra(BundleKeys.KEY_FROM_NOTIFICATION_START_CALL, false)) { - val callNotificationIntent = Intent(this, CallNotificationActivity::class.java) - intent.extras?.let { callNotificationIntent.putExtras(it) } - startActivity(callNotificationIntent) - } else { - val chatIntent = Intent(context, ChatActivity::class.java) - chatIntent.putExtras(intent.extras!!) - startActivity(chatIntent) + val invitationsIntent = Intent(this, InvitationsActivity::class.java) + startActivity(invitationsIntent) } + } else { + val chatIntent = Intent(context, ChatActivity::class.java) + chatIntent.putExtras(intent.extras!!) + startActivity(chatIntent) } } else { if (!appPreferences.isDbRoomMigrated) { diff --git a/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt b/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt index 0533d9b22..01a2c84b3 100644 --- a/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/callnotification/CallNotificationActivity.kt @@ -18,34 +18,25 @@ import android.util.Log import android.view.View import androidx.annotation.RequiresApi import androidx.core.app.NotificationManagerCompat -import androidx.lifecycle.ViewModelProvider import autodagger.AutoInjector -import com.google.android.material.snackbar.Snackbar import com.nextcloud.talk.R import com.nextcloud.talk.activities.CallActivity import com.nextcloud.talk.activities.CallBaseActivity import com.nextcloud.talk.api.NcApi import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication -import com.nextcloud.talk.callnotification.viewmodel.CallNotificationViewModel import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.databinding.CallNotificationActivityBinding import com.nextcloud.talk.extensions.loadUserAvatar -import com.nextcloud.talk.models.domain.ConversationModel -import com.nextcloud.talk.models.domain.ConversationType import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils import com.nextcloud.talk.utils.SpreedFeatures -import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.NotificationUtils -import com.nextcloud.talk.utils.ParticipantPermissions import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY -import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CONVERSATION_NAME import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.CapabilitiesUtil.hasSpreedFeatureCapability -import io.reactivex.disposables.Disposable import okhttp3.Cache import java.io.IOException import javax.inject.Inject @@ -64,49 +55,110 @@ class CallNotificationActivity : CallBaseActivity() { @Inject lateinit var userManager: UserManager - @Inject - lateinit var viewModelFactory: ViewModelProvider.Factory - - lateinit var callNotificationViewModel: CallNotificationViewModel - - private val disposablesList: MutableList = ArrayList() - private var originalBundle: Bundle? = null private var roomToken: String? = null private var notificationTimestamp: Int? = null + private var displayName: String? = null + private var callFlag: Int = 0 + private var isOneToOneCall: Boolean = true + private var conversationName: String? = null + private var internalUserId: Long = -1 + private var userBeingCalled: User? = null - private var credentials: String? = null - var currentConversation: ConversationModel? = null private var leavingScreen = false private var handler: Handler? = null private var binding: CallNotificationActivityBinding? = null override fun onCreate(savedInstanceState: Bundle?) { - Log.d(TAG, "onCreate") super.onCreate(savedInstanceState) sharedApplication!!.componentApplication.inject(this) binding = CallNotificationActivityBinding.inflate(layoutInflater) setContentView(binding!!.root) hideNavigationIfNoPipAvailable() - val extras = intent.extras - roomToken = extras!!.getString(KEY_ROOM_TOKEN, "") - notificationTimestamp = extras.getInt(BundleKeys.KEY_NOTIFICATION_TIMESTAMP) - val internalUserId = extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) + handleExtras() userBeingCalled = userManager.getUserWithId(internalUserId).blockingGet() - originalBundle = extras - credentials = ApiUtils.getCredentials(userBeingCalled!!.username, userBeingCalled!!.token) + setupCallTypeDescription() + binding!!.conversationNameTextView.text = displayName + setupAvatar(isOneToOneCall, conversationName) + initClickListeners() + setupNotificationCanceledRoutine() + } - callNotificationViewModel = ViewModelProvider(this, viewModelFactory)[CallNotificationViewModel::class.java] + private fun handleExtras() { + val extras = intent.extras!! + roomToken = extras.getString(KEY_ROOM_TOKEN, "") + notificationTimestamp = extras.getInt(BundleKeys.KEY_NOTIFICATION_TIMESTAMP) + displayName = extras.getString(BundleKeys.KEY_CONVERSATION_DISPLAY_NAME, "") + callFlag = extras.getInt(BundleKeys.KEY_CALL_FLAG) + isOneToOneCall = extras.getBoolean(BundleKeys.KEY_ROOM_ONE_TO_ONE) + conversationName = extras.getString(BundleKeys.KEY_CONVERSATION_NAME, "") + internalUserId = extras.getLong(BundleKeys.KEY_INTERNAL_USER_ID) + } - initObservers() - - if (userManager.setUserAsActive(userBeingCalled!!).blockingGet()) { - setCallDescriptionText() - callNotificationViewModel.getRoom(userBeingCalled!!, roomToken!!) + private fun setupAvatar(isOneToOneCall: Boolean, conversationName: String?) { + if (isOneToOneCall) { + binding!!.avatarImageView.loadUserAvatar( + userBeingCalled!!, + conversationName!!, + true, + false + ) + } else { + binding!!.avatarImageView.setImageResource(R.drawable.ic_circular_group) } } + private fun setupCallTypeDescription() { + val apiVersion = ApiUtils.getConversationApiVersion( + userBeingCalled!!, + intArrayOf( + ApiUtils.API_V4, + ApiUtils.API_V3, + 1 + ) + ) + + if (apiVersion >= ApiUtils.API_V3) { + val hasCallFlags = hasSpreedFeatureCapability( + userBeingCalled?.capabilities?.spreedCapability!!, + SpreedFeatures.CONVERSATION_CALL_FLAGS + ) + if (hasCallFlags) { + if (isInCallWithVideo(callFlag)) { + binding!!.incomingCallVoiceOrVideoTextView.text = String.format( + resources.getString(R.string.nc_call_video), + resources.getString(R.string.nc_app_product_name) + ) + } else { + binding!!.incomingCallVoiceOrVideoTextView.text = String.format( + resources.getString(R.string.nc_call_voice), + resources.getString(R.string.nc_app_product_name) + ) + } + } + } else { + val callDescriptionWithoutTypeInfo = String.format( + resources.getString(R.string.nc_call_unknown), + resources.getString(R.string.nc_app_product_name) + ) + binding!!.incomingCallVoiceOrVideoTextView.text = callDescriptionWithoutTypeInfo + } + } + + private fun setupNotificationCanceledRoutine() { + val notificationHandler = Handler(Looper.getMainLooper()) + notificationHandler.post(object : Runnable { + override fun run() { + if (NotificationUtils.isNotificationVisible(context, notificationTimestamp!!.toInt())) { + notificationHandler.postDelayed(this, ONE_SECOND) + } else { + finish() + } + } + }) + } + override fun onStart() { super.onStart() if (handler == null) { @@ -122,136 +174,26 @@ class CallNotificationActivity : CallBaseActivity() { private fun initClickListeners() { binding!!.callAnswerVoiceOnlyView.setOnClickListener { Log.d(TAG, "accept call (voice only)") - originalBundle!!.putBoolean(KEY_CALL_VOICE_ONLY, true) + intent.extras!!.putBoolean(KEY_CALL_VOICE_ONLY, true) proceedToCall() } binding!!.callAnswerCameraView.setOnClickListener { Log.d(TAG, "accept call (with video)") - originalBundle!!.putBoolean(KEY_CALL_VOICE_ONLY, false) + intent.extras!!.putBoolean(KEY_CALL_VOICE_ONLY, false) proceedToCall() } binding!!.hangupButton.setOnClickListener { hangup() } } - private fun initObservers() { - val apiVersion = ApiUtils.getConversationApiVersion( - userBeingCalled!!, - intArrayOf( - ApiUtils.API_V4, - ApiUtils.API_V3, - 1 - ) - ) - - callNotificationViewModel.getRoomViewState.observe(this) { state -> - when (state) { - is CallNotificationViewModel.GetRoomSuccessState -> { - currentConversation = state.conversationModel - - binding!!.conversationNameTextView.text = currentConversation!!.displayName - if (currentConversation!!.type === ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL) { - binding!!.avatarImageView.loadUserAvatar( - userBeingCalled!!, - currentConversation!!.name!!, - true, - false - ) - } else { - binding!!.avatarImageView.setImageResource(R.drawable.ic_circular_group) - } - - val notificationHandler = Handler(Looper.getMainLooper()) - notificationHandler.post(object : Runnable { - override fun run() { - if (NotificationUtils.isNotificationVisible(context, notificationTimestamp!!.toInt())) { - notificationHandler.postDelayed(this, ONE_SECOND) - } else { - finish() - } - } - }) - - showAnswerControls() - - if (apiVersion >= ApiUtils.API_V3) { - val hasCallFlags = hasSpreedFeatureCapability( - userBeingCalled?.capabilities?.spreedCapability!!, - SpreedFeatures.CONVERSATION_CALL_FLAGS - ) - if (hasCallFlags) { - if (isInCallWithVideo(currentConversation!!.callFlag)) { - binding!!.incomingCallVoiceOrVideoTextView.text = String.format( - resources.getString(R.string.nc_call_video), - resources.getString(R.string.nc_app_product_name) - ) - } else { - binding!!.incomingCallVoiceOrVideoTextView.text = String.format( - resources.getString(R.string.nc_call_voice), - resources.getString(R.string.nc_app_product_name) - ) - } - } - } - - initClickListeners() - } - - is CallNotificationViewModel.GetRoomErrorState -> { - Snackbar.make(binding!!.root, R.string.nc_common_error_sorry, Snackbar.LENGTH_LONG).show() - } - - else -> {} - } - } - } - - private fun setCallDescriptionText() { - val callDescriptionWithoutTypeInfo = String.format( - resources.getString(R.string.nc_call_unknown), - resources.getString(R.string.nc_app_product_name) - ) - binding!!.incomingCallVoiceOrVideoTextView.text = callDescriptionWithoutTypeInfo - } - - private fun showAnswerControls() { - binding!!.callAnswerCameraView.visibility = View.VISIBLE - binding!!.callAnswerVoiceOnlyView.visibility = View.VISIBLE - } - private fun hangup() { leavingScreen = true - dispose() finish() } private fun proceedToCall() { - if (currentConversation != null) { - originalBundle!!.putString(KEY_ROOM_TOKEN, currentConversation!!.token) - originalBundle!!.putString(KEY_CONVERSATION_NAME, currentConversation!!.displayName) - - val participantPermission = ParticipantPermissions( - userBeingCalled!!.capabilities!!.spreedCapability!!, - currentConversation!! - ) - originalBundle!!.putBoolean( - BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO, - participantPermission.canPublishAudio() - ) - originalBundle!!.putBoolean( - BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO, - participantPermission.canPublishVideo() - ) - originalBundle!!.putBoolean( - BundleKeys.KEY_IS_MODERATOR, - ConversationUtils.isParticipantOwnerOrModerator(currentConversation!!) - ) - - val intent = Intent(this, CallActivity::class.java) - intent.putExtras(originalBundle!!) - startActivity(intent) - } else { - Log.w(TAG, "conversation was still null when clicked to answer call. User has to click another time.") - } + val callIntent = Intent(this, CallActivity::class.java) + callIntent.putExtras(intent.extras!!) + startActivity(callIntent) } private fun isInCallWithVideo(callFlag: Int): Boolean { @@ -270,18 +212,9 @@ class CallNotificationActivity : CallBaseActivity() { handler!!.removeCallbacksAndMessages(null) handler = null } - dispose() super.onDestroy() } - private fun dispose() { - for (disposable in disposablesList) { - if (!disposable.isDisposed) { - disposable.dispose() - } - } - } - @RequiresApi(api = Build.VERSION_CODES.O) override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig) @@ -308,7 +241,7 @@ class CallNotificationActivity : CallBaseActivity() { } companion object { - const val TAG = "CallNotificationActivity" + private val TAG = CallNotificationActivity::class.simpleName const val ONE_SECOND: Long = 1000 } } diff --git a/app/src/main/java/com/nextcloud/talk/callnotification/viewmodel/CallNotificationViewModel.kt b/app/src/main/java/com/nextcloud/talk/callnotification/viewmodel/CallNotificationViewModel.kt deleted file mode 100644 index d446e7ec8..000000000 --- a/app/src/main/java/com/nextcloud/talk/callnotification/viewmodel/CallNotificationViewModel.kt +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Nextcloud Talk - Android Client - * - * SPDX-FileCopyrightText: 2023 Marcel Hibbe - * SPDX-License-Identifier: GPL-3.0-or-later - */ -package com.nextcloud.talk.callnotification.viewmodel - -import android.util.Log -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import com.nextcloud.talk.chat.data.ChatRepository -import com.nextcloud.talk.data.user.model.User -import com.nextcloud.talk.models.domain.ConversationModel -import io.reactivex.Observer -import io.reactivex.android.schedulers.AndroidSchedulers -import io.reactivex.disposables.Disposable -import io.reactivex.schedulers.Schedulers -import javax.inject.Inject - -class CallNotificationViewModel @Inject constructor(private val repository: ChatRepository) : - ViewModel() { - - sealed interface ViewState - - object GetRoomStartState : ViewState - object GetRoomErrorState : ViewState - open class GetRoomSuccessState(val conversationModel: ConversationModel) : ViewState - - private val _getRoomViewState: MutableLiveData = MutableLiveData(GetRoomStartState) - val getRoomViewState: LiveData - get() = _getRoomViewState - - fun getRoom(user: User, token: String) { - _getRoomViewState.value = GetRoomStartState - repository.getRoom(user, token) - .subscribeOn(Schedulers.io()) - ?.observeOn(AndroidSchedulers.mainThread()) - ?.subscribe(GetRoomObserver()) - } - - inner class GetRoomObserver : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } - - override fun onNext(conversationModel: ConversationModel) { - _getRoomViewState.value = GetRoomSuccessState(conversationModel) - } - - override fun onError(e: Throwable) { - Log.e(TAG, "Error when fetching room") - _getRoomViewState.value = GetRoomErrorState - } - - override fun onComplete() { - // unused atm - } - } - - companion object { - private val TAG = CallNotificationViewModel::class.simpleName - } -} diff --git a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt index be1bf6c33..55cf99769 100644 --- a/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt +++ b/app/src/main/java/com/nextcloud/talk/dagger/modules/ViewModelModule.kt @@ -9,7 +9,6 @@ package com.nextcloud.talk.dagger.modules import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider -import com.nextcloud.talk.callnotification.viewmodel.CallNotificationViewModel import com.nextcloud.talk.chat.viewmodels.ChatViewModel import com.nextcloud.talk.conversation.viewmodel.ConversationViewModel import com.nextcloud.talk.conversation.viewmodel.RenameConversationViewModel @@ -119,11 +118,6 @@ abstract class ViewModelModule { @ViewModelKey(ChatViewModel::class) abstract fun chatViewModel(viewModel: ChatViewModel): ViewModel - @Binds - @IntoMap - @ViewModelKey(CallNotificationViewModel::class) - abstract fun callNotificationViewModel(viewModel: CallNotificationViewModel): ViewModel - @Binds @IntoMap @ViewModelKey(ConversationInfoViewModel::class) diff --git a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt index bc015687e..221f4adaa 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/NotificationWorker.kt @@ -49,9 +49,11 @@ import com.nextcloud.talk.application.NextcloudTalkApplication import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication import com.nextcloud.talk.arbitrarystorage.ArbitraryStorageManager import com.nextcloud.talk.callnotification.CallNotificationActivity +import com.nextcloud.talk.chat.data.ChatRepository import com.nextcloud.talk.models.SignatureVerification +import com.nextcloud.talk.models.domain.ConversationModel +import com.nextcloud.talk.models.domain.ConversationType import com.nextcloud.talk.models.json.chat.ChatUtils.Companion.getParsedMessage -import com.nextcloud.talk.models.json.conversations.RoomOverall import com.nextcloud.talk.models.json.notifications.NotificationOverall import com.nextcloud.talk.models.json.participants.Participant import com.nextcloud.talk.models.json.participants.ParticipantsOverall @@ -61,7 +63,9 @@ import com.nextcloud.talk.receivers.DirectReplyReceiver import com.nextcloud.talk.receivers.DismissRecordingAvailableReceiver import com.nextcloud.talk.receivers.MarkAsReadReceiver import com.nextcloud.talk.receivers.ShareRecordingToChatReceiver +import com.nextcloud.talk.users.UserManager import com.nextcloud.talk.utils.ApiUtils +import com.nextcloud.talk.utils.ConversationUtils import com.nextcloud.talk.utils.DoNotDisturbUtils.shouldPlaySound import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.NotificationUtils.cancelAllNotificationsForAccount @@ -70,6 +74,7 @@ import com.nextcloud.talk.utils.NotificationUtils.findNotificationForRoom import com.nextcloud.talk.utils.NotificationUtils.getCallRingtoneUri import com.nextcloud.talk.utils.NotificationUtils.getMessageRingtoneUri import com.nextcloud.talk.utils.NotificationUtils.loadAvatarSync +import com.nextcloud.talk.utils.ParticipantPermissions import com.nextcloud.talk.utils.PushUtils import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_DISMISS_RECORDING_URL @@ -80,6 +85,7 @@ import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_ID import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_RESTRICT_DELETION import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_NOTIFICATION_TIMESTAMP import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_REMOTE_TALK_SHARE +import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_ONE_TO_ONE import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SHARE_RECORDING_TO_CHAT_URL import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_SYSTEM_NOTIFICATION_ID @@ -119,6 +125,12 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor @Inject var retrofit: Retrofit? = null + var chatRepository: ChatRepository? = null + @Inject set + + @Inject + lateinit var userManager: UserManager + @JvmField @Inject var okHttpClient: OkHttpClient? = null @@ -209,55 +221,107 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor } private fun handleCallPushMessage() { - val fullScreenIntent = Intent(context, CallNotificationActivity::class.java) - val bundle = Bundle() - bundle.putString(KEY_ROOM_TOKEN, pushMessage.id) - bundle.putInt(KEY_NOTIFICATION_TIMESTAMP, pushMessage.timestamp.toInt()) - bundle.putLong(KEY_INTERNAL_USER_ID, signatureVerification.user!!.id!!) - bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, true) - fullScreenIntent.putExtras(bundle) - fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK + val userBeingCalled = userManager.getUserWithId(signatureVerification.user!!.id!!).blockingGet() - val requestCode = System.currentTimeMillis().toInt() + fun prepareCallNotificationScreen(conversation: ConversationModel) { + val fullScreenIntent = Intent(context, CallNotificationActivity::class.java) + val bundle = Bundle() + bundle.putString(KEY_ROOM_TOKEN, pushMessage.id) + bundle.putInt(KEY_NOTIFICATION_TIMESTAMP, pushMessage.timestamp.toInt()) + bundle.putLong(KEY_INTERNAL_USER_ID, signatureVerification.user!!.id!!) + bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, true) - val fullScreenPendingIntent = PendingIntent.getActivity( - context, - requestCode, - fullScreenIntent, - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT - } else { - PendingIntent.FLAG_UPDATE_CURRENT - } - ) + val isOneToOneCall = conversation.type === ConversationType.ROOM_TYPE_ONE_TO_ONE_CALL - val soundUri = getCallRingtoneUri(applicationContext, appPreferences) - val notificationChannelId = NotificationUtils.NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name - val uri = Uri.parse(signatureVerification.user!!.baseUrl!!) - val baseUrl = uri.host + bundle.putBoolean(KEY_ROOM_ONE_TO_ONE, isOneToOneCall) // ggf change in Activity? not necessary???? + bundle.putString(BundleKeys.KEY_CONVERSATION_NAME, conversation.name) + bundle.putString(BundleKeys.KEY_CONVERSATION_DISPLAY_NAME, conversation.displayName) + bundle.putInt(BundleKeys.KEY_CALL_FLAG, conversation.callFlag) - val notification = - NotificationCompat.Builder(applicationContext, notificationChannelId) - .setPriority(NotificationCompat.PRIORITY_HIGH) - .setCategory(NotificationCompat.CATEGORY_CALL) - .setSmallIcon(R.drawable.ic_call_black_24dp) - .setSubText(baseUrl) - .setShowWhen(true) - .setWhen(pushMessage.timestamp) - .setContentTitle(EmojiCompat.get().process(pushMessage.subject)) - // auto cancel is set to false because notification (including sound) should continue while - // CallNotificationActivity is active - .setAutoCancel(false) - .setOngoing(true) - .setContentIntent(fullScreenPendingIntent) - .setFullScreenIntent(fullScreenPendingIntent, true) - .setSound(soundUri) - .build() - notification.flags = notification.flags or Notification.FLAG_INSISTENT + val participantPermission = ParticipantPermissions( + userBeingCalled!!.capabilities!!.spreedCapability!!, + conversation + ) + bundle.putBoolean( + BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_AUDIO, + participantPermission.canPublishAudio() + ) + bundle.putBoolean( + BundleKeys.KEY_PARTICIPANT_PERMISSION_CAN_PUBLISH_VIDEO, + participantPermission.canPublishVideo() + ) + bundle.putBoolean( + BundleKeys.KEY_IS_MODERATOR, + ConversationUtils.isParticipantOwnerOrModerator(conversation) + ) - sendNotification(pushMessage.timestamp.toInt(), notification) + fullScreenIntent.putExtras(bundle) + fullScreenIntent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK - checkIfCallIsActive(signatureVerification) + val requestCode = System.currentTimeMillis().toInt() + + val fullScreenPendingIntent = PendingIntent.getActivity( + context, + requestCode, + fullScreenIntent, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT + } else { + PendingIntent.FLAG_UPDATE_CURRENT + } + ) + + val soundUri = getCallRingtoneUri(applicationContext, appPreferences) + val notificationChannelId = NotificationUtils.NotificationChannels.NOTIFICATION_CHANNEL_CALLS_V4.name + val uri = Uri.parse(signatureVerification.user!!.baseUrl!!) + val baseUrl = uri.host + + val notification = + NotificationCompat.Builder(applicationContext, notificationChannelId) + .setPriority(NotificationCompat.PRIORITY_HIGH) + .setCategory(NotificationCompat.CATEGORY_CALL) + .setSmallIcon(R.drawable.ic_call_black_24dp) + .setSubText(baseUrl) + .setShowWhen(true) + .setWhen(pushMessage.timestamp) + .setContentTitle(EmojiCompat.get().process(pushMessage.subject)) + // auto cancel is set to false because notification (including sound) should continue while + // CallNotificationActivity is active + .setAutoCancel(false) + .setOngoing(true) + .setContentIntent(fullScreenPendingIntent) + .setFullScreenIntent(fullScreenPendingIntent, true) + .setSound(soundUri) + .build() + notification.flags = notification.flags or Notification.FLAG_INSISTENT + + sendNotification(pushMessage.timestamp.toInt(), notification) + + checkIfCallIsActive(signatureVerification, conversation) + } + + chatRepository?.getRoom(userBeingCalled, roomToken = pushMessage.id!!) + ?.subscribeOn(Schedulers.io()) + ?.observeOn(AndroidSchedulers.mainThread()) + ?.subscribe(object : Observer { + override fun onSubscribe(d: Disposable) { + // unused atm + } + + override fun onNext(conversation: ConversationModel) { + if (userManager.setUserAsActive(userBeingCalled!!).blockingGet()) { + prepareCallNotificationScreen(conversation) + } + } + + override fun onError(e: Throwable) { + Log.e(TAG, "Failed to get room", e) + } + + override fun onComplete() { + // unused atm + } + }) } private fun initNcApiAndCredentials() { @@ -819,7 +883,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor notificationManager.cancel(notificationId) } - private fun checkIfCallIsActive(signatureVerification: SignatureVerification) { + private fun checkIfCallIsActive(signatureVerification: SignatureVerification, conversation: ConversationModel) { Log.d(TAG, "checkIfCallIsActive") var hasParticipantsInCall = true var inCallOnDifferentDevice = false @@ -867,7 +931,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor } if (!hasParticipantsInCall) { - showMissedCallNotification() + showMissedCallNotification(conversation) Log.d(TAG, "no participants in call") removeNotification(pushMessage.timestamp.toInt()) } @@ -881,7 +945,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor override fun onError(e: Throwable) { Log.e(TAG, "Error in getPeersForCall", e) if (isCallNotificationVisible) { - showMissedCallNotification() + showMissedCallNotification(conversation) } removeNotification(pushMessage.timestamp.toInt()) } @@ -889,7 +953,7 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor override fun onComplete() { if (isCallNotificationVisible) { // this state can be reached when call timeout is reached. - showMissedCallNotification() + showMissedCallNotification(conversation) } removeNotification(pushMessage.timestamp.toInt()) @@ -897,86 +961,50 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor }) } - fun showMissedCallNotification() { + fun showMissedCallNotification(conversation: ConversationModel) { val isOngoingCallNotificationVisible = NotificationUtils.isNotificationVisible( context, pushMessage.timestamp.toInt() ) if (isOngoingCallNotificationVisible) { - val apiVersion = ApiUtils.getConversationApiVersion( - signatureVerification.user!!, - intArrayOf( - ApiUtils.API_V4, - ApiUtils.API_V3, - 1 - ) + val notificationBuilder: NotificationCompat.Builder? + + notificationBuilder = NotificationCompat.Builder( + context!!, + NotificationUtils.NotificationChannels + .NOTIFICATION_CHANNEL_MESSAGES_V4.name ) - ncApi.getRoom( - credentials, - ApiUtils.getUrlForRoom( - apiVersion, - signatureVerification.user?.baseUrl!!, - pushMessage.id + + val notification: Notification = notificationBuilder + .setContentTitle( + String.format( + context!!.resources.getString(R.string.nc_missed_call), + conversation.displayName + ) ) - ) - .subscribeOn(Schedulers.io()) - .retry(GET_ROOM_RETRY_COUNT) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(object : Observer { - override fun onSubscribe(d: Disposable) { - // unused atm - } + .setSmallIcon(R.drawable.ic_baseline_phone_missed_24) + .setOngoing(false) + .setAutoCancel(true) + .setPriority(NotificationCompat.PRIORITY_LOW) + .setContentIntent(getIntentToOpenConversation()) + .build() - override fun onNext(roomOverall: RoomOverall) { - val currentConversation = roomOverall.ocs!!.data - val notificationBuilder: NotificationCompat.Builder? - - notificationBuilder = NotificationCompat.Builder( - context!!, - NotificationUtils.NotificationChannels - .NOTIFICATION_CHANNEL_MESSAGES_V4.name - ) - - val notification: Notification = notificationBuilder - .setContentTitle( - String.format( - context!!.resources.getString(R.string.nc_missed_call), - currentConversation!!.displayName - ) - ) - .setSmallIcon(R.drawable.ic_baseline_phone_missed_24) - .setOngoing(false) - .setAutoCancel(true) - .setPriority(NotificationCompat.PRIORITY_LOW) - .setContentIntent(getIntentToOpenConversation()) - .build() - - val notificationId: Int = SystemClock.uptimeMillis().toInt() - if (ActivityCompat.checkSelfPermission( - applicationContext, - Manifest.permission.POST_NOTIFICATIONS - ) != PackageManager.PERMISSION_GRANTED - ) { - // here to request the missing permissions, and then overriding - // public void onRequestPermissionsResult(int requestCode, String[] permissions, - // int[] grantResults) - // to handle the case where the user grants the permission. See the documentation - // for ActivityCompat#requestPermissions for more details. - return - } - notificationManager.notify(notificationId, notification) - Log.d(TAG, "'you missed a call' notification was created") - } - - override fun onError(e: Throwable) { - Log.e(TAG, "An error occurred while fetching room for the 'missed call' notification", e) - } - - override fun onComplete() { - // unused atm - } - }) + val notificationId: Int = SystemClock.uptimeMillis().toInt() + if (ActivityCompat.checkSelfPermission( + applicationContext, + Manifest.permission.POST_NOTIFICATIONS + ) != PackageManager.PERMISSION_GRANTED + ) { + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + return + } + notificationManager.notify(notificationId, notification) + Log.d(TAG, "'you missed a call' notification was created") } } @@ -986,7 +1014,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val bundle = Bundle() bundle.putString(KEY_ROOM_TOKEN, pushMessage.id) bundle.putLong(KEY_INTERNAL_USER_ID, signatureVerification.user!!.id!!) - bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, false) intent.putExtras(bundle) return intent } @@ -997,7 +1024,6 @@ class NotificationWorker(context: Context, workerParams: WorkerParameters) : Wor val bundle = Bundle() bundle.putString(KEY_ROOM_TOKEN, pushMessage.id) bundle.putLong(KEY_INTERNAL_USER_ID, signatureVerification.user!!.id!!) - bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, false) intent.putExtras(bundle) val requestCode = System.currentTimeMillis().toInt() diff --git a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt index 20eef7217..93d0b9212 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt @@ -35,13 +35,12 @@ import com.nextcloud.talk.upload.chunked.ChunkedFileUploader import com.nextcloud.talk.upload.chunked.OnDataTransferProgressListener import com.nextcloud.talk.upload.normal.FileUploader import com.nextcloud.talk.users.UserManager +import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.FileUtils import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.RemoteFileUtils -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_ROOM_TOKEN -import com.nextcloud.talk.utils.CapabilitiesUtil import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.preferences.AppPreferences import okhttp3.MediaType.Companion.toMediaTypeOrNull @@ -295,7 +294,6 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa bundle.putString(KEY_ROOM_TOKEN, roomToken) bundle.putLong(KEY_INTERNAL_USER_ID, currentUser.id!!) - bundle.putBoolean(KEY_FROM_NOTIFICATION_START_CALL, false) intent.putExtras(bundle) diff --git a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt index 57f163db5..50e8c28fd 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/bundle/BundleKeys.kt @@ -39,6 +39,7 @@ object BundleKeys { const val KEY_INVITED_GROUP = "KEY_INVITED_GROUP" const val KEY_INVITED_EMAIL = "KEY_INVITED_EMAIL" const val KEY_CONVERSATION_NAME = "KEY_CONVERSATION_NAME" + const val KEY_CONVERSATION_DISPLAY_NAME = "KEY_CONVERSATION_DISPLAY_NAME" const val KEY_RECORDING_STATE = "KEY_RECORDING_STATE" const val KEY_CALL_VOICE_ONLY = "KEY_CALL_VOICE_ONLY" const val KEY_CALL_WITHOUT_NOTIFICATION = "KEY_CALL_WITHOUT_NOTIFICATION" @@ -75,4 +76,5 @@ object BundleKeys { const val KEY_PASSWORD = "KEY_PASSWORD" const val KEY_REMOTE_TALK_SHARE = "KEY_REMOTE_TALK_SHARE" const val KEY_CHAT_API_VERSION = "KEY_CHAT_API_VERSION" + const val KEY_CALL_FLAG = "KEY_CALL_FLAG" } diff --git a/app/src/main/res/layout/call_notification_activity.xml b/app/src/main/res/layout/call_notification_activity.xml index d5b0435ab..49d823648 100644 --- a/app/src/main/res/layout/call_notification_activity.xml +++ b/app/src/main/res/layout/call_notification_activity.xml @@ -52,8 +52,6 @@ android:background="@drawable/shape_oval" android:backgroundTint="@color/nc_darkGreen" android:src="@drawable/ic_videocam_white_24px" - android:visibility="gone" - tools:visibility="visible" android:contentDescription="@string/nc_call_button_content_description_answer_video_call" />