From f017b0f0528edee057e06d433021555f13c8652a Mon Sep 17 00:00:00 2001 From: Oussama Hassine Date: Fri, 21 Feb 2025 11:51:23 +0100 Subject: [PATCH] feat: open ongoing call screen when answering an incoming call (WPB-15555) (#3875) --- .../notification/CallNotificationManager.kt | 12 +---- .../android/notification/PendingIntents.kt | 45 ++++++++++--------- .../IncomingCallActionReceiver.kt | 21 +++------ .../wire/android/ui/calling/CallActivity.kt | 1 + .../ui/calling/ongoing/OngoingCallActivity.kt | 18 ++++++++ 5 files changed, 50 insertions(+), 47 deletions(-) diff --git a/app/src/main/kotlin/com/wire/android/notification/CallNotificationManager.kt b/app/src/main/kotlin/com/wire/android/notification/CallNotificationManager.kt index 308ff7a5b4e..9433369820f 100644 --- a/app/src/main/kotlin/com/wire/android/notification/CallNotificationManager.kt +++ b/app/src/main/kotlin/com/wire/android/notification/CallNotificationManager.kt @@ -50,7 +50,6 @@ import kotlinx.coroutines.flow.scan import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch import org.jetbrains.annotations.VisibleForTesting -import java.util.concurrent.TimeUnit import javax.inject.Inject import javax.inject.Singleton @@ -143,12 +142,6 @@ class CallNotificationManager @Inject constructor( private fun StatusBarNotification.hideIncomingCallNotification() { appLogger.i("$TAG: hiding incoming call") - - // This delay is just so when the user receives two calling signals one straight after the other [INCOMING -> CANCEL] - // Due to the signals being one after the other we are creating a notification when we are trying to cancel it, it wasn't - // properly cancelling vibration as probably when we were cancelling, the vibration object was still being created and started - // and thus never stopped. - TimeUnit.MILLISECONDS.sleep(CANCEL_CALL_NOTIFICATION_DELAY) notificationManager.cancel(tag, id) } @@ -167,7 +160,6 @@ class CallNotificationManager @Inject constructor( companion object { private const val TAG = "CallNotificationManager" - private const val CANCEL_CALL_NOTIFICATION_DELAY = 300L @VisibleForTesting internal const val DEBOUNCE_TIME = 200L @@ -278,7 +270,7 @@ class CallNotificationBuilder @Inject constructor( ) ) .setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE) - .setContentIntent(openOngoingCallPendingIntent(context, conversationIdString)) + .setContentIntent(openOngoingCallPendingIntent(context, conversationIdString, userIdString)) .build() } @@ -330,8 +322,6 @@ class CallNotificationBuilder @Inject constructor( data class IncomingCallsForUser(val userId: UserId, val userName: String, val incomingCalls: List) -data class CallNotificationIds(val userIdString: String, val conversationIdString: String) - data class CallNotificationData( val userId: QualifiedID, val userName: String, diff --git a/app/src/main/kotlin/com/wire/android/notification/PendingIntents.kt b/app/src/main/kotlin/com/wire/android/notification/PendingIntents.kt index 0ff48c95e71..1f51291fefd 100644 --- a/app/src/main/kotlin/com/wire/android/notification/PendingIntents.kt +++ b/app/src/main/kotlin/com/wire/android/notification/PendingIntents.kt @@ -36,6 +36,8 @@ import com.wire.android.notification.broadcastreceivers.StopAudioMessageReceiver import com.wire.android.ui.WireActivity import com.wire.android.ui.calling.CallActivity.Companion.EXTRA_CONVERSATION_ID import com.wire.android.ui.calling.CallActivity.Companion.EXTRA_SCREEN_TYPE +import com.wire.android.ui.calling.CallActivity.Companion.EXTRA_SHOULD_ANSWER_CALL +import com.wire.android.ui.calling.CallActivity.Companion.EXTRA_USER_ID import com.wire.android.ui.calling.StartingCallActivity import com.wire.android.ui.calling.StartingCallScreenType import com.wire.android.ui.calling.getIncomingCallIntent @@ -80,10 +82,6 @@ fun otherUserProfilePendingIntent(context: Context, destinationUserId: String, u ) } -// TODO -fun callMessagePendingIntent(context: Context, conversationId: String, userId: String?): PendingIntent = - messagePendingIntent(context, conversationId, userId) - fun summaryMessagePendingIntent(context: Context): PendingIntent = openAppPendingIntent(context) fun replyMessagePendingIntent(context: Context, conversationId: String, userId: String?): PendingIntent = PendingIntent.getBroadcast( @@ -93,9 +91,13 @@ fun replyMessagePendingIntent(context: Context, conversationId: String, userId: PendingIntent.FLAG_MUTABLE ) -fun openOngoingCallPendingIntent(context: Context, conversationId: String): PendingIntent { - val intent = openOngoingCallIntent(context, conversationId) - +fun openOngoingCallPendingIntent( + context: Context, + conversationId: String, + userId: String, + shouldAnswerCall: Boolean = false +): PendingIntent { + val intent = ongoingCallIntent(context, conversationId, userId, shouldAnswerCall) return PendingIntent.getActivity( context.applicationContext, OPEN_ONGOING_CALL_REQUEST_CODE, @@ -140,21 +142,15 @@ fun answerCallPendingIntent(context: Context, conversationId: String, userId: St } != null val shouldAnswerCallFromNotificationButton = !isAlreadyHavingACall && (ContextCompat.checkSelfPermission(context, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) - if (shouldAnswerCallFromNotificationButton) { - val intent = IncomingCallActionReceiver.newIntent( + return if (shouldAnswerCallFromNotificationButton) { + openOngoingCallPendingIntent( context = context, conversationId = conversationId, userId = userId, - action = IncomingCallActionReceiver.ACTION_ANSWER_CALL - ) - return PendingIntent.getBroadcast( - context.applicationContext, - getRequestCode(ANSWER_CALL_REQUEST_CODE, userId, conversationId), - intent, - PendingIntent.FLAG_IMMUTABLE + shouldAnswerCall = true ) } else { - return fullScreenIncomingCallPendingIntent(context, conversationId, userId) + fullScreenIncomingCallPendingIntent(context, conversationId, userId) } } @@ -186,10 +182,16 @@ private fun openOutgoingCallIntent(context: Context, conversationId: String) = putExtra(EXTRA_SCREEN_TYPE, StartingCallScreenType.Outgoing.name) } -private fun openOngoingCallIntent(context: Context, conversationId: String) = - Intent(context.applicationContext, OngoingCallActivity::class.java).apply { - putExtra(EXTRA_CONVERSATION_ID, conversationId) - } +private fun ongoingCallIntent( + context: Context, + conversationId: String, + userId: String, + shouldAnswerCall: Boolean +) = Intent(context.applicationContext, OngoingCallActivity::class.java).apply { + putExtra(EXTRA_CONVERSATION_ID, conversationId) + putExtra(EXTRA_USER_ID, userId) + putExtra(EXTRA_SHOULD_ANSWER_CALL, shouldAnswerCall) +} private fun openMigrationLoginIntent(context: Context, userHandle: String) = Intent(context.applicationContext, WireActivity::class.java).apply { @@ -246,7 +248,6 @@ fun stopAudioPendingIntent(context: Context): PendingIntent { private const val MESSAGE_NOTIFICATIONS_SUMMARY_REQUEST_CODE = 0 private const val DECLINE_CALL_REQUEST_CODE = "decline_call_" -private const val ANSWER_CALL_REQUEST_CODE = "answer_call_" private const val FULL_SCREEN_REQUEST_CODE = "incoming_call_" private const val OPEN_ONGOING_CALL_REQUEST_CODE = 4 private const val OPEN_MIGRATION_LOGIN_REQUEST_CODE = 5 diff --git a/app/src/main/kotlin/com/wire/android/notification/broadcastreceivers/IncomingCallActionReceiver.kt b/app/src/main/kotlin/com/wire/android/notification/broadcastreceivers/IncomingCallActionReceiver.kt index 4c7ca4cea9c..64c4f312b85 100644 --- a/app/src/main/kotlin/com/wire/android/notification/broadcastreceivers/IncomingCallActionReceiver.kt +++ b/app/src/main/kotlin/com/wire/android/notification/broadcastreceivers/IncomingCallActionReceiver.kt @@ -26,7 +26,6 @@ import com.wire.android.di.ApplicationScope import com.wire.android.di.KaliumCoreLogic import com.wire.android.di.NoSession import com.wire.android.notification.CallNotificationManager -import com.wire.android.services.ServicesManager import com.wire.android.util.dispatchers.DispatcherProvider import com.wire.kalium.logger.obfuscateId import com.wire.kalium.logic.CoreLogic @@ -60,9 +59,6 @@ class IncomingCallActionReceiver : BroadcastReceiver() { @Inject lateinit var callNotificationManager: CallNotificationManager - @Inject - lateinit var servicesManager: ServicesManager - @Suppress("ReturnCount") override fun onReceive(context: Context, intent: Intent) { val conversationIdString: String = intent.getStringExtra(EXTRA_CONVERSATION_ID) ?: run { @@ -82,9 +78,8 @@ class IncomingCallActionReceiver : BroadcastReceiver() { coroutineScope.launch(Dispatchers.Default) { with(coreLogic.getSessionScope(userId)) { val conversationId = qualifiedIdMapper.fromStringToQualifiedID(conversationIdString) - when (action) { - ACTION_DECLINE_CALL -> calls.rejectCall(conversationId) - ACTION_ANSWER_CALL -> servicesManager.startCallServiceToAnswer(userId, conversationId) + if (action == ACTION_DECLINE_CALL) { + calls.rejectCall(conversationId) } } callNotificationManager.hideIncomingCallNotification(userId.toString(), conversationIdString) @@ -97,18 +92,16 @@ class IncomingCallActionReceiver : BroadcastReceiver() { private const val EXTRA_ACTION = "action_extra" const val ACTION_DECLINE_CALL = "action_decline_call" - const val ACTION_ANSWER_CALL = "action_answer_call" fun newIntent( context: Context, conversationId: String, userId: String, action: String - ): Intent = - Intent(context, IncomingCallActionReceiver::class.java).apply { - putExtra(EXTRA_CONVERSATION_ID, conversationId) - putExtra(EXTRA_RECEIVER_USER_ID, userId) - putExtra(EXTRA_ACTION, action) - } + ): Intent = Intent(context, IncomingCallActionReceiver::class.java).apply { + putExtra(EXTRA_CONVERSATION_ID, conversationId) + putExtra(EXTRA_RECEIVER_USER_ID, userId) + putExtra(EXTRA_ACTION, action) + } } } diff --git a/app/src/main/kotlin/com/wire/android/ui/calling/CallActivity.kt b/app/src/main/kotlin/com/wire/android/ui/calling/CallActivity.kt index 5c47a9ea4bd..30bb299a2bc 100644 --- a/app/src/main/kotlin/com/wire/android/ui/calling/CallActivity.kt +++ b/app/src/main/kotlin/com/wire/android/ui/calling/CallActivity.kt @@ -40,6 +40,7 @@ abstract class CallActivity : AppCompatActivity() { const val EXTRA_CONVERSATION_ID = "conversation_id" const val EXTRA_USER_ID = "user_id" const val EXTRA_SCREEN_TYPE = "screen_type" + const val EXTRA_SHOULD_ANSWER_CALL = "should_answer_call" } private val callActivityViewModel: CallActivityViewModel by viewModels() diff --git a/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/OngoingCallActivity.kt b/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/OngoingCallActivity.kt index a0e4f7e1c17..b27a78f1bc0 100644 --- a/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/OngoingCallActivity.kt +++ b/app/src/main/kotlin/com/wire/android/ui/calling/ongoing/OngoingCallActivity.kt @@ -42,7 +42,9 @@ import androidx.compose.ui.semantics.testTagsAsResourceId import com.wire.android.R import com.wire.android.appLogger import com.wire.android.navigation.style.TransitionAnimationType +import com.wire.android.notification.CallNotificationManager import com.wire.android.notification.endOngoingCallPendingIntent +import com.wire.android.services.ServicesManager import com.wire.android.ui.LocalActivity import com.wire.android.ui.calling.CallActivity import com.wire.android.ui.calling.CallActivity.Companion.EXTRA_CONVERSATION_ID @@ -69,12 +71,20 @@ class OngoingCallActivity : CallActivity() { @Inject lateinit var proximitySensorManager: ProximitySensorManager + @Inject + lateinit var servicesManager: ServicesManager + + @Inject + lateinit var callNotificationManager: CallNotificationManager + var conversationId: String? by mutableStateOf(null) var userId: String? by mutableStateOf(null) + private var shouldAnswerCall: Boolean by mutableStateOf(false) private fun handleNewIntent(intent: Intent) { conversationId = intent.extras?.getString(EXTRA_CONVERSATION_ID) userId = intent.extras?.getString(EXTRA_USER_ID) + shouldAnswerCall = intent.extras?.getBoolean(EXTRA_SHOULD_ANSWER_CALL) ?: false switchAccountIfNeeded(userId) } @@ -94,6 +104,14 @@ class OngoingCallActivity : CallActivity() { handleNewIntent(intent) + if (shouldAnswerCall && userId != null && conversationId != null) { + callNotificationManager.hideIncomingCallNotification(userId!!, conversationId!!) + servicesManager.startCallServiceToAnswer( + qualifiedIdMapper.fromStringToQualifiedID(userId!!), + qualifiedIdMapper.fromStringToQualifiedID(conversationId!!), + ) + } + appLogger.i("$TAG Initializing proximity sensor..") proximitySensorManager.initialize()