Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@
public val activeCall: StateFlow<Call?> = _activeCall

public val callConfigRegistry = (client as StreamVideoClient).callServiceConfigRegistry
private val serviceLauncher = ServiceLauncher(client.context)
internal val serviceLauncher = ServiceLauncher(streamVideoClient)

internal val clientEventReporter = (client as StreamVideoClient).analytics.clientEventReporter

Expand Down Expand Up @@ -171,7 +171,7 @@
/**
* Transition incoming/outgoing call to active on the same service
*/
fun setActiveCall(call: Call) {

Check failure on line 174 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Refactor this method to reduce its Cognitive Complexity from 16 to the 15 allowed.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaBsLnJkhxKMScg8KrdZ&open=AaBsLnJkhxKMScg8KrdZ&pullRequest=1807
this._activeCall.value = call
val serviceTransitionDelayMs = 500L
val ringingState = call.state.ringingState.value
Expand All @@ -196,7 +196,7 @@
val serviceClass = callServiceConfig.serviceClass
val isServiceRunning = ServiceIntentBuilder()
.isServiceRunning(this.client.context, serviceClass)
if (callServiceConfig.runCallServiceInForeground) {

Check warning on line 199 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/ClientState.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Merge this "if" statement with the nested one.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaBsLnJkhxKMScg8Krda&open=AaBsLnJkhxKMScg8Krda&pullRequest=1807
if (!isServiceRunning) {
logger.e { "Outgoing call service should already be running" }
}
Expand Down Expand Up @@ -293,13 +293,11 @@
CallService.TRIGGER_ONGOING_CALL -> serviceLauncher.showOnGoingCall(
call,
trigger,
streamVideoClient,
)

CallService.TRIGGER_OUTGOING_CALL -> serviceLauncher.showOutgoingCall(
call,
trigger,
streamVideoClient,
)

else -> {}
Expand All @@ -312,10 +310,7 @@
internal fun maybeStopForegroundService(call: Call) {
val callConfig = streamVideoClient.callServiceConfigRegistry.get(call.type)
if (callConfig.runCallServiceInForeground) {
val context = streamVideoClient.context

logger.d { "Building stop intent for call_id: ${call.cid}" }
val serviceLauncher = ServiceLauncher(context)
serviceLauncher.stopService(call)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import android.os.Bundle
import io.getstream.log.taggedLogger
import io.getstream.result.Result
import io.getstream.video.android.core.model.RejectReason
import io.getstream.video.android.core.notifications.internal.service.ServiceLauncher
import io.getstream.video.android.core.notifications.internal.telecom.TelecomCallController
import io.getstream.video.android.model.StreamCallId

Expand Down Expand Up @@ -51,9 +50,7 @@ internal class ExternalCallRejectionHandler() {
}
logger.d { "[onRejectCall] source:$source, #ringing; callId: ${call.id}, action: ${intent.action}" }

val serviceLauncher = ServiceLauncher(context)
serviceLauncher.removeIncomingCall(
context,
StreamVideo.instance().state.serviceLauncher.removeIncomingCall(
StreamCallId.fromCallCid(call.cid),
StreamVideo.instance().state.callConfigRegistry.get(call.type),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ import io.getstream.video.android.core.notifications.NotificationHandler.Compani
import io.getstream.video.android.core.notifications.NotificationHandler.Companion.ACTION_NOTIFICATION
import io.getstream.video.android.core.notifications.dispatchers.DefaultNotificationDispatcher
import io.getstream.video.android.core.notifications.dispatchers.NotificationDispatcher
import io.getstream.video.android.core.notifications.internal.service.ServiceLauncher
import io.getstream.video.android.core.notifications.medianotifications.MediaNotificationConfig
import io.getstream.video.android.core.notifications.medianotifications.MediaNotificationContent
import io.getstream.video.android.core.notifications.medianotifications.MediaNotificationVisuals
Expand Down Expand Up @@ -88,7 +87,6 @@ public open class DefaultNotificationHandler(
private val logger by taggedLogger("Call:NotificationHandler")
val intentResolver =
DefaultStreamIntentResolver(application, DefaultNotificationIntentBundleResolver())
private val serviceLauncher = ServiceLauncher(application)

protected val notificationManager: NotificationManagerCompat by lazy {
NotificationManagerCompat.from(application).also {
Expand All @@ -114,14 +112,12 @@ public open class DefaultNotificationHandler(
) {
logger.d { "[onRingingCall] #ringing; callId: ${callId.id}" }
val streamVideo = StreamVideo.instance()
serviceLauncher.showIncomingCall(
application,
streamVideo.state.serviceLauncher.showIncomingCall(
callId,
callDisplayName,
streamVideo.state.callConfigRegistry.get(callId.type),
isVideo = isVideoCall(callId, payload),
payload = payload,
streamVideo,
notification = getRingingCallNotification(
RingingState.Incoming(),
callId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
import io.getstream.video.android.core.notifications.dispatchers.NotificationDispatcher
import io.getstream.video.android.core.notifications.extractor.DefaultNotificationContentExtractor
import io.getstream.video.android.core.notifications.internal.service.CallService.Companion.TRIGGER_INCOMING_CALL
import io.getstream.video.android.core.notifications.internal.service.ServiceLauncher
import io.getstream.video.android.core.notifications.style.StyleProvider
import io.getstream.video.android.core.utils.BackgroundRestrictions
import io.getstream.video.android.core.utils.isAppInForeground
Expand Down Expand Up @@ -149,7 +148,6 @@
NotificationPermissionHandler by notificationPermissionHandler {

private val logger by taggedLogger("Video:StreamNotificationHandler")
private val serviceLauncher = ServiceLauncher(application)
private val styleProvider = StyleProvider(application)
private val batteryRestrictions = BackgroundRestrictions(application)

Expand Down Expand Up @@ -177,14 +175,12 @@
val canRunService =
streamVideo.callServiceConfigRegistry.get(callId.type).runCallServiceInForeground
if (canRunService) {
serviceLauncher.showIncomingCall(
application,
streamVideo.state.serviceLauncher.showIncomingCall(
callId,
callDisplayName,
streamVideo.state.callConfigRegistry.get(callId.type),
isVideo = isVideoCall(callId, payload),
payload = payload,
streamVideo,
notification = getRingingCallNotification(
RingingState.Incoming(),
callId,
Expand All @@ -203,7 +199,7 @@
payload: Map<String, Any?>,
) {
logger.d { "[onLiveCall] callId: ${callId.id}, callDisplayName: $callDisplayName" }
// TODO: Replace StreamCallId.hashCode with StreamCallId.getNotificationId(appropriateType)

Check warning on line 202 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaBsLnGPhxKMScg8KrdU&open=AaBsLnGPhxKMScg8KrdU&pullRequest=1807
val notificationId = callId.hashCode()
val liveCallPendingIntent =
intentResolver.searchLiveCallPendingIntent(callId, notificationId, payload)
Expand Down Expand Up @@ -254,7 +250,7 @@
payload: Map<String, Any?>,
) {
logger.d { "[onNotification] callId: ${callId.id}, callDisplayName: $callDisplayName" }
// TODO: Replace StreamCallId.hashCode with StreamCallId.getNotificationId(appropriateType)

Check warning on line 253 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaBsLnGPhxKMScg8KrdV&open=AaBsLnGPhxKMScg8KrdV&pullRequest=1807
val notificationId = callId.hashCode()
val intent = intentResolver.searchNotificationCallPendingIntent(
callId,
Expand Down Expand Up @@ -574,7 +570,7 @@
override fun getSettingUpCallNotification(trigger: String, callId: StreamCallId): Notification? {
return when (trigger) {
/**
* TODO: This logic is duplicated with getIncomingCallNotificationInternal.

Check warning on line 573 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaBsLnGPhxKMScg8KrdW&open=AaBsLnGPhxKMScg8KrdW&pullRequest=1807
* Update it soon
*/

Expand Down Expand Up @@ -747,7 +743,7 @@
logger.d {
"[getSimpleOngoingCallNotification] callId: ${callId.id}, callDisplayName: $callDisplayName, isOutgoingCall: $isOutgoingCall, remoteParticipantCount: $remoteParticipantCount"
}
// TODO: Replace StreamCallId.hashCode with StreamCallId.getNotificationId(appropriateType)

Check warning on line 746 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaBsLnGPhxKMScg8KrdX&open=AaBsLnGPhxKMScg8KrdX&pullRequest=1807
val notificationId = callId.hashCode() // Notification ID

// Intents
Expand Down Expand Up @@ -1183,7 +1179,7 @@
},
): Notification {
logger.d { "[getMinimalMediaStyleNotification] callId: ${callId.id}" }
// TODO: Replace StreamCallId.hashCode with StreamCallId.getNotificationId(appropriateType)

Check warning on line 1182 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/handlers/StreamDefaultNotificationHandler.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaBsLnGPhxKMScg8KrdY&open=AaBsLnGPhxKMScg8KrdY&pullRequest=1807
val notificationId = callId.hashCode() // Notification ID
// Intents
val onClickIntent = intentResolver.searchOngoingCallPendingIntent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import io.getstream.video.android.core.utils.safeCallWithResult
import io.getstream.video.android.model.StreamCallId

internal class IncomingCallPresenter(private val serviceIntentBuilder: ServiceIntentBuilder) {
internal class IncomingCallPresenter(private val client: StreamVideo, private val serviceIntentBuilder: ServiceIntentBuilder) {
private val logger by taggedLogger("IncomingCallPresenter")

fun showIncomingCall(
Expand Down Expand Up @@ -103,7 +103,7 @@
context: Context,
notification: Notification?,
callId: StreamCallId,
error: Any?,

Check warning on line 106 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/IncomingCallPresenter.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this unused function parameter "error".

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaCGkTIMfhhhv61__Qm2&open=AaCGkTIMfhhhv61__Qm2&pullRequest=1807
): ShowIncomingCallResult {
if (!hasNotificationPermission(context) || notification == null) {
logger.w {
Expand All @@ -114,9 +114,9 @@
return ShowIncomingCallResult.ERROR
}

StreamVideo.instanceOrNull()
?.getStreamNotificationDispatcher()
?.notify(
client
.getStreamNotificationDispatcher()
.notify(
callId,
callId.getNotificationId(NotificationType.Incoming),
notification,
Expand All @@ -131,7 +131,7 @@

private fun hasNoActiveCall(): Boolean {
val hasActiveCall =
StreamVideo.instanceOrNull()?.state?.activeCall?.value != null
client.state.activeCall?.value != null

Check warning on line 134 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/service/IncomingCallPresenter.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless null-safe access ?., it always succeeds.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaCGkTIMfhhhv61__Qm3&open=AaCGkTIMfhhhv61__Qm3&pullRequest=1807
logger.d { "[showIncomingCall] hasActiveCall: $hasActiveCall" }
return !hasActiveCall
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@

package io.getstream.video.android.core.notifications.internal.service

import android.content.Context
import android.os.Build
import androidx.annotation.RequiresApi
import androidx.core.telecom.CallsManager
Expand All @@ -25,20 +24,30 @@ import io.getstream.video.android.core.notifications.internal.telecom.IncomingCa
import io.getstream.video.android.core.notifications.internal.telecom.jetpack.JetpackTelecomRepository
import io.getstream.video.android.model.StreamCallId

internal class JetpackTelecomRepositoryProvider(private val context: Context) {
internal class JetpackTelecomRepositoryProvider(private val streamVideo: StreamVideo) {

private val context = streamVideo.context.applicationContext ?: streamVideo.context
private val registrationLock = Any()
private lateinit var callsManager: CallsManager

@RequiresApi(Build.VERSION_CODES.O)
fun get(callId: StreamCallId): JetpackTelecomRepository {
val callsManager = CallsManager(context).apply {
registerAppWithTelecom(
capabilities = CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING and
CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING,
)
}

val streamVideo = StreamVideo.instance()
val callsManager = getOrRegisterCallsManager()
val incomingCallTelecomAction =
IncomingCallTelecomAction(streamVideo)
return JetpackTelecomRepository(callsManager, callId, incomingCallTelecomAction)
}

@RequiresApi(Build.VERSION_CODES.O)
private fun getOrRegisterCallsManager(): CallsManager = synchronized(registrationLock) {
if (!::callsManager.isInitialized) {
callsManager = CallsManager(context).also { manager ->
manager.registerAppWithTelecom(
capabilities = CallsManager.CAPABILITY_SUPPORTS_CALL_STREAMING or
CallsManager.CAPABILITY_SUPPORTS_VIDEO_CALLING,
)
}
}
callsManager
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,12 @@ package io.getstream.video.android.core.notifications.internal.service

import android.annotation.SuppressLint
import android.app.Notification
import android.content.Context
import android.os.Bundle
import androidx.core.app.NotificationManagerCompat
import androidx.core.content.ContextCompat
import androidx.core.net.toUri
import io.getstream.log.taggedLogger
import io.getstream.video.android.core.Call
import io.getstream.video.android.core.StreamVideo
import io.getstream.video.android.core.StreamVideoClient
import io.getstream.video.android.core.notifications.NotificationType
import io.getstream.video.android.core.notifications.internal.Throttler
Expand All @@ -57,25 +55,25 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

internal class ServiceLauncher(val context: Context) {
internal class ServiceLauncher(private val client: StreamVideoClient) {

private val logger by taggedLogger("ServiceTriggers")

private val context = client.context
private val serviceIntentBuilder = ServiceIntentBuilder()
private val incomingCallPresenter = IncomingCallPresenter(serviceIntentBuilder)
private val incomingCallPresenter = IncomingCallPresenter(client, serviceIntentBuilder)
private val telecomHelper = TelecomHelper()
private val telecomPermissions = TelecomPermissions()
private val jetpackTelecomRepositoryProvider = JetpackTelecomRepositoryProvider(context)
private val jetpackTelecomRepositoryProvider = JetpackTelecomRepositoryProvider(client)
private val throttler = Throttler()

@SuppressLint("MissingPermission", "NewApi")
fun showIncomingCall(
context: Context,
callId: StreamCallId,
callDisplayName: String?,
callServiceConfiguration: CallServiceConfig,
isVideo: Boolean,
payload: Map<String, Any?>,
streamVideo: StreamVideo,
notification: Notification?,
) {
val result = incomingCallPresenter.showIncomingCall(
Expand All @@ -90,15 +88,15 @@ internal class ServiceLauncher(val context: Context) {
if (telecomHelper.canUseJetpackTelecom()) {
when (result) {
ShowIncomingCallResult.FG_SERVICE -> {
updateIncomingCallNotification(notification, streamVideo, callId)
updateIncomingCallNotification(notification, callId)

val jetpackTelecomRepository = jetpackTelecomRepositoryProvider.get(callId)

val appSchema = (streamVideo as StreamVideoClient).telecomConfig?.schema
val appSchema = client.telecomConfig?.schema
val addressUri = "$appSchema:${callId.id}".toUri()
val formattedCallDisplayName = callDisplayName?.takeIf { it.isNotBlank() } ?: DEFAULT_CALL_TEXT

val call = streamVideo.call(callId.type, callId.id)
val call = client.call(callId.type, callId.id)

call.state.jetpackTelecomRepository = (jetpackTelecomRepository)

Expand All @@ -117,14 +115,12 @@ internal class ServiceLauncher(val context: Context) {
}
}

fun showOnGoingCall(call: Call, trigger: String, streamVideo: StreamVideo) {
val client = streamVideo as StreamVideoClient
fun showOnGoingCall(call: Call, trigger: String) {
val callConfig = client.callServiceConfigRegistry.get(call.type)
if (!callConfig.runCallServiceInForeground) {
return
}
val callId = StreamCallId.fromCallCid(call.cid)
val context = client.context
val serviceIntent = ServiceIntentBuilder().buildStartIntent(
context,
StartServiceParam(
Expand All @@ -137,8 +133,8 @@ internal class ServiceLauncher(val context: Context) {
}

@SuppressLint("NewApi")
fun showOutgoingCall(call: Call, trigger: String, streamVideo: StreamVideo) {
val callConfig = (streamVideo as StreamVideoClient).callServiceConfigRegistry.get(call.type)
fun showOutgoingCall(call: Call, trigger: String) {
val callConfig = client.callServiceConfigRegistry.get(call.type)
if (!callConfig.runCallServiceInForeground) {
return
}
Expand All @@ -159,13 +155,11 @@ internal class ServiceLauncher(val context: Context) {
*/
val callDisplayName = "NOT SET YET"

val telecomPermissions = TelecomPermissions()
val telecomHelper = TelecomHelper()
if (telecomPermissions.canUseTelecom(callConfig, context)) {
if (telecomHelper.canUseJetpackTelecom()) {
val jetpackTelecomRepository = jetpackTelecomRepositoryProvider.get(callId)

val appSchema = streamVideo.telecomConfig?.schema
val appSchema = client.telecomConfig?.schema
val addressUri = "$appSchema:${callId.id}".toUri()
val formattedCallDisplayName =
callDisplayName?.takeIf { it.isNotBlank() } ?: DEFAULT_CALL_TEXT
Expand Down Expand Up @@ -199,18 +193,16 @@ internal class ServiceLauncher(val context: Context) {
*/
private fun updateIncomingCallNotification(
notification: Notification?,
streamVideo: StreamVideo,
callId: StreamCallId,
) {
notification?.let {
val notificationId = callId.getNotificationId(NotificationType.Incoming)
streamVideo.call(callId.type, callId.id)
client.call(callId.type, callId.id)
.state.updateNotification(notificationId, notification)
}
}

fun removeIncomingCall(
context: Context,
callId: StreamCallId,
config: CallServiceConfig = DefaultCallConfigurations.default,
) {
Expand Down Expand Up @@ -249,25 +241,18 @@ internal class ServiceLauncher(val context: Context) {

private fun stopCallServiceInternal(call: Call) {
logger.d { "[stopCallServiceInternal]" }
val streamVideo = StreamVideo.instanceOrNull() as? StreamVideoClient
streamVideo?.let { streamVideoClient ->
val callConfig = streamVideoClient.callServiceConfigRegistry.get(call.type)
if (callConfig.runCallServiceInForeground) {
val context = streamVideoClient.context

val serviceIntent = serviceIntentBuilder.buildStopIntent(
context,
StopServiceParam(call, callConfig),
)
serviceIntent?.let {
logger.d {
"Building stop intent, class: ${serviceIntent.component?.className} for call_id: ${call.cid}"
}
serviceIntent.extras?.let {
logBundle(it)
}
context.startService(serviceIntent)
val callConfig = client.callServiceConfigRegistry.get(call.type)
if (callConfig.runCallServiceInForeground) {
val serviceIntent = serviceIntentBuilder.buildStopIntent(
context,
StopServiceParam(call, callConfig),
)
serviceIntent?.let {
logger.d {
"Building stop intent, class: ${serviceIntent.component?.className} for call_id: ${call.cid}"
}
serviceIntent.extras?.let { logBundle(it) }
Comment thread
coderabbitai[bot] marked this conversation as resolved.
context.startService(serviceIntent)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import android.os.Build
import io.getstream.video.android.core.StreamVideo

// TODO pass StreamVideo instance in constructor on v2

Check warning on line 22 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/telecom/TelecomHelper.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaCGkTOZfhhhv61__Qm5&open=AaCGkTOZfhhhv61__Qm5&pullRequest=1807
internal class TelecomHelper {

fun canUseJetpackTelecom(): Boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import io.getstream.video.android.core.StreamVideoClient
import io.getstream.video.android.core.notifications.internal.service.CallServiceConfig

// TODO pass StreamVideo instance in constructor on v2

Check warning on line 30 in stream-video-android-core/src/main/kotlin/io/getstream/video/android/core/notifications/internal/telecom/TelecomPermissions.kt

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this TODO comment.

See more on https://sonarcloud.io/project/issues?id=GetStream_stream-video-android&issues=AaCGkTN9fhhhv61__Qm4&open=AaCGkTN9fhhhv61__Qm4&pullRequest=1807
class TelecomPermissions {

private val logger: TaggedLogger by taggedLogger("TelecomPermissions")
Expand Down
Loading
Loading