Skip to content

Commit

Permalink
[PBE 6041] Fix incoming call PN issue (#1197)
Browse files Browse the repository at this point in the history
* Reassign API instance in StreamNotificationManager.install

* Register push device only after connection.ok event

* Fix demo-app log out

---------

Co-authored-by: Aleksandar Apostolov <[email protected]>
  • Loading branch information
liviu-timar and aleksandar-apostolov authored Oct 7, 2024
1 parent e19f9d1 commit 6c62e6a
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,23 +20,25 @@ import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.google.android.gms.auth.api.signin.GoogleSignInClient
import dagger.hilt.android.lifecycle.HiltViewModel
import io.getstream.android.push.PushProvider
import io.getstream.chat.android.client.ChatClient
import io.getstream.video.android.core.Call
import io.getstream.video.android.core.StreamVideo
import io.getstream.video.android.datastore.delegate.StreamUserDataStore
import io.getstream.video.android.model.Device
import io.getstream.video.android.model.User
import io.getstream.video.android.model.mapper.isValidCallCid
import io.getstream.video.android.model.mapper.toTypeAndId
import io.getstream.video.android.util.NetworkMonitor
import io.getstream.video.android.util.StreamVideoInitHelper
import kotlinx.coroutines.delay
import io.getstream.video.android.util.fcmToken
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.launch
import java.util.UUID
Expand All @@ -49,7 +51,7 @@ class CallJoinViewModel @Inject constructor(
networkMonitor: NetworkMonitor,
) : ViewModel() {
val user: Flow<User?> = dataStore.user
val isLoggedOut = dataStore.user.map { it == null }
val isLoggedOut = MutableStateFlow(false)
var autoLogInAfterLogOut = true
val isNetworkAvailable = networkMonitor.isNetworkAvailable

Expand Down Expand Up @@ -101,12 +103,26 @@ class CallJoinViewModel @Inject constructor(

fun logOut() {
viewModelScope.launch {
googleSignInClient.signOut()
dataStore.clear()
StreamVideo.instance().logOut()
ChatClient.instance().disconnect(true).enqueue()
delay(200)
dataStore.clear() // Demo App DataStore
googleSignInClient.signOut()

StreamVideo.instanceOrNull()?.let { streamVideo ->
fcmToken?.let { fcmToken ->
streamVideo.deleteDevice(
Device(
id = fcmToken,
pushProvider = PushProvider.FIREBASE.key,
pushProviderName = "firebase",
),
)
}
streamVideo.logOut()
}

StreamVideo.removeClient()

isLoggedOut.value = true
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) 2014-2024 Stream.io Inc. All rights reserved.
*
* Licensed under the Stream License;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://github.com/GetStream/stream-video-android/blob/main/LICENSE
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.getstream.video.android.util

import android.util.Log
import com.google.firebase.messaging.FirebaseMessaging
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.tasks.await

val fcmToken: String?
get() = runBlocking {
try {
FirebaseMessaging.getInstance().token.await()
} catch (e: Exception) {
Log.e("FCM Token", "Failed to retrieve FCM token", e)
null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@ import io.getstream.video.android.core.notifications.internal.service.CallServic
import io.getstream.video.android.core.utils.safeCall
import io.getstream.video.android.model.StreamCallId
import io.getstream.video.android.model.User
import io.getstream.video.android.model.UserType
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.openapitools.client.models.CallCreatedEvent
import org.openapitools.client.models.CallRingEvent
import org.openapitools.client.models.ConnectedEvent
Expand Down Expand Up @@ -103,6 +106,8 @@ class ClientState(client: StreamVideo) {
// mark connected
if (event is ConnectedEvent) {
_connection.value = ConnectionState.Connected

registerPushDevice()
} else if (event is CallCreatedEvent) {
// what's the right thing to do here?
// if it's ringing we add it
Expand All @@ -118,6 +123,14 @@ class ClientState(client: StreamVideo) {
}
}

private fun registerPushDevice() {
with(clientImpl) {
scope.launch(CoroutineName("ClientState#registerPushDevice")) {
if (user.type == UserType.Authenticated) registerPushDevice()
}
}
}

internal fun handleError(error: Throwable) {
if (error is ConnectException) {
_connection.value = ConnectionState.Failed(error = Error(error))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,14 +239,6 @@ public class StreamVideoBuilder @JvmOverloads constructor(
// Installs Stream Video instance
StreamVideo.install(client)

// Needs to be started after the client is initialised because the VideoPushDelegate
// is accessing the StreamVideo instance
scope.launch {
if (user.type == UserType.Authenticated) {
client.registerPushDevice()
}
}

return client
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ internal class StreamNotificationManager private constructor(
private val context: Context,
private val scope: CoroutineScope,
private val notificationConfig: NotificationConfig,
private val api: ProductvideoApi,
private var api: ProductvideoApi,
internal val deviceTokenStorage: DeviceTokenStorage,
private val notificationPermissionManager: NotificationPermissionManager?,
) : NotificationHandler by notificationConfig.notificationHandler {
Expand Down Expand Up @@ -123,6 +123,7 @@ internal class StreamNotificationManager private constructor(
pushProvider = this.pushProvider.key,
pushProviderName = this.providerName ?: "",
)

private fun PushDevice.toCreateDeviceRequest(): Result<CreateDeviceRequest> =
when (pushProvider) {
PushProvider.FIREBASE -> Result.Success(CreateDeviceRequest.PushProvider.Firebase)
Expand All @@ -138,10 +139,12 @@ internal class StreamNotificationManager private constructor(
}

internal companion object {

private val logger: TaggedLogger by taggedLogger("StreamVideo:Notifications")

@SuppressLint("StaticFieldLeak")
private lateinit var internalStreamNotificationManager: StreamNotificationManager

internal fun install(
context: Context,
scope: CoroutineScope,
Expand All @@ -151,10 +154,7 @@ internal class StreamNotificationManager private constructor(
): StreamNotificationManager {
synchronized(this) {
if (Companion::internalStreamNotificationManager.isInitialized) {
logger.e {
"The $internalStreamNotificationManager is already installed but you've " +
"tried to install a new one."
}
internalStreamNotificationManager.api = api
} else {
val application = context.applicationContext as? Application
val updatedNotificationConfig =
Expand Down

0 comments on commit 6c62e6a

Please sign in to comment.