diff --git a/tutorials/tutorial-ringing/src/main/kotlin/io/getstream/video/android/tutorial/ringing/MainActivity.kt b/tutorials/tutorial-ringing/src/main/kotlin/io/getstream/video/android/tutorial/ringing/MainActivity.kt index ad36870459..9c79b03c18 100644 --- a/tutorials/tutorial-ringing/src/main/kotlin/io/getstream/video/android/tutorial/ringing/MainActivity.kt +++ b/tutorials/tutorial-ringing/src/main/kotlin/io/getstream/video/android/tutorial/ringing/MainActivity.kt @@ -21,6 +21,7 @@ import android.content.Context import android.content.pm.PackageManager import android.os.Build import android.os.Bundle +import android.util.Log import android.widget.Toast import androidx.activity.ComponentActivity import androidx.activity.compose.setContent @@ -73,6 +74,8 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.launch +import org.json.JSONException +import java.io.IOException import java.util.UUID /** @@ -91,11 +94,21 @@ class MainActivity : ComponentActivity() { var selectedUser by remember { mutableStateOf(RingingApp.currentUser) } when (selectedUser) { null -> LoginScreen(onUserSelected = { user -> - RingingApp.login(applicationContext, user) - // For the simplicity of the tutorial, we are requesting the required permissions here. - // In a real app, you should request the permissions when needed. - resultLauncher.requestDefaultPermissions() - selectedUser = user + lifecycleScope.launch { + try { + RingingApp.login(applicationContext, user) + } catch (e: IOException) { + Log.e("MainActivity", "Login failed", e) + return@launch + } catch (e: JSONException) { + Log.e("MainActivity", "Login failed", e) + return@launch + } + // For the simplicity of the tutorial, we are requesting the required permissions here. + // In a real app, you should request the permissions when needed. + resultLauncher.requestDefaultPermissions() + selectedUser = user + } }) else -> HomeScreen( diff --git a/tutorials/tutorial-ringing/src/main/kotlin/io/getstream/video/android/tutorial/ringing/RingingApp.kt b/tutorials/tutorial-ringing/src/main/kotlin/io/getstream/video/android/tutorial/ringing/RingingApp.kt index c7d3888f98..82e462caac 100644 --- a/tutorials/tutorial-ringing/src/main/kotlin/io/getstream/video/android/tutorial/ringing/RingingApp.kt +++ b/tutorials/tutorial-ringing/src/main/kotlin/io/getstream/video/android/tutorial/ringing/RingingApp.kt @@ -28,8 +28,13 @@ import io.getstream.video.android.core.StreamVideoBuilder import io.getstream.video.android.core.notifications.NotificationConfig import io.getstream.video.android.model.Device import io.getstream.video.android.model.User +import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import kotlinx.coroutines.tasks.await +import kotlinx.coroutines.withContext +import org.json.JSONObject +import java.net.HttpURLConnection +import java.net.URL class RingingApp : Application() { @@ -42,6 +47,8 @@ class RingingApp : Application() { companion object { + private const val TOKEN_URL = "https://pronto.getstream.io/api/auth/create-token" + var currentUser: TutorialUser? = null val caller get() = currentUser ?: error("#caller; user not logged in") @@ -61,16 +68,16 @@ class RingingApp : Application() { } } - fun login(context: Context, user: TutorialUser) { + suspend fun login(context: Context, user: TutorialUser) { if (!StreamVideo.isInstalled) { - currentUser = user + val (apiKey, token) = fetchCredentials(user.id) // Initialize StreamVideo. For a production app we recommend adding // the client to your Application class or di module. StreamVideoBuilder( context = context.applicationContext, - apiKey = "mmhfdzb5evj2", + apiKey = apiKey, user = user.delegate, - token = user.token, + token = token, notificationConfig = NotificationConfig( // Make the notification low priority if the app is in foreground, so its not visible as a popup, since we want to handle // the incoming call in full screen when app is running. @@ -87,9 +94,24 @@ class RingingApp : Application() { ), ), ).build() + currentUser = user } } + // Credentials come from Stream's demo token generator; use your own backend in production. + private suspend fun fetchCredentials(userId: String): Pair = + withContext(Dispatchers.IO) { + val url = URL("$TOKEN_URL?environment=demo&user_id=$userId") + val connection = url.openConnection() as HttpURLConnection + try { + val body = connection.inputStream.bufferedReader().use { it.readText() } + val json = JSONObject(body) + json.getString("apiKey") to json.getString("token") + } finally { + connection.disconnect() + } + } + suspend fun logout() { if (StreamVideo.isInstalled) { with(StreamVideo.instance()) { @@ -114,7 +136,6 @@ class RingingApp : Application() { data class TutorialUser( val delegate: User, - val token: String, val checked: Boolean = false, ) { val id: String get() = delegate.id @@ -128,21 +149,18 @@ data class TutorialUser( id = "android-tutorial-1", name = "User 1", ), - token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYW5kcm9pZC10dXRvcmlhbC0xIn0.3qB-FI6OAqf5ZEETtgs0XhaMmiaRF2jDJOqCVRsqqbc", ), TutorialUser( User( id = "android-tutorial-2", name = "User 2", ), - token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYW5kcm9pZC10dXRvcmlhbC0yIn0.ksOq5ahC0745oZdPDKr2hyLp0j9exfwLE-AQITc9ZSc", ), TutorialUser( User( id = "android-tutorial-3", name = "User 3", ), - token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiYW5kcm9pZC10dXRvcmlhbC0zIn0.g5h8coX8J1XUNHagPFoGBI0D7bN6P0w2Sd2rui89puE", ), ) }