Coverage Summary for Class: FirebaseServiceHandler (cloud.mindbox.mindbox_firebase)

Class Method, % Branch, % Line, % Instruction, %
FirebaseServiceHandler 66.7% (6/9) 85.7% (12/14) 79.5% (35/44) 86.3% (221/256)
FirebaseServiceHandler$convertToRemoteMessage$1 0% (0/1) 0% (0/1) 0% (0/4)
FirebaseServiceHandler$getToken$2$1 0% (0/1) 0% (0/1) 0% (0/12)
FirebaseServiceHandler$getToken$2$2 100% (1/1) 100% (1/1) 100% (7/7)
FirebaseServiceHandler$getToken$2$3 0% (0/1) 0% (0/1) 0% (0/9)
FirebaseServiceHandler$namedFirebaseAppName$1 100% (1/1) 100% (1/1) 100% (10/10)
FirebaseServiceHandler$sam$com_google_android_gms_tasks_OnSuccessListener$0
Total 57.1% (8/14) 85.7% (12/14) 75.5% (37/49) 79.9% (238/298)


 package cloud.mindbox.mindbox_firebase
 
 import android.content.Context
 import cloud.mindbox.mobile_sdk.logger.MindboxLogger
 import cloud.mindbox.mobile_sdk.pushes.PushServiceHandler
 import cloud.mindbox.mobile_sdk.utils.ExceptionHandler
 import com.google.android.gms.ads.identifier.AdvertisingIdClient
 import com.google.android.gms.common.ConnectionResult
 import com.google.android.gms.common.GoogleApiAvailability
 import com.google.firebase.FirebaseApp
 import com.google.firebase.messaging.FirebaseMessaging
 import com.google.firebase.messaging.RemoteMessage
 import kotlinx.coroutines.CancellationException
 import kotlinx.coroutines.suspendCancellableCoroutine
 import kotlin.coroutines.resumeWithException
 
 internal class FirebaseServiceHandler(
     private val logger: MindboxLogger,
     private val exceptionHandler: ExceptionHandler,
 ) : PushServiceHandler() {
 
     @Volatile
     private var cachedNamedAppName: String? = null
 
     override val notificationProvider: String = MindboxFirebase.tag
 
     override suspend fun initService(context: Context) {
         FirebaseApp.initializeApp(context)
         createNamedAppIfConfigured(context)
     }
 
     /**
      * If the host app configured a named FirebaseApp via the `mindbox_firebase_app_name`
      * string resource, makes sure it exists — creating it from the `[DEFAULT]` app's options (the same
      * Firebase project), or reusing one the client already created. This gives Mindbox
      * an FCM token isolated from `[DEFAULT]`, whose token third-party SDKs may churn.
      * Does nothing when no named app is configured.
      */
     private fun createNamedAppIfConfigured(context: Context) {
         val appName = namedFirebaseAppName(context)
         if (appName.isBlank()) return
         if (FirebaseApp.getApps(context).any { it.name == appName }) {
             logger.i(this, "Named FirebaseApp '$appName' already exists, reusing it")
             return
         }
         runCatching {
             FirebaseApp.initializeApp(context, FirebaseApp.getInstance().options, appName)
         }.fold(
             onSuccess = { logger.i(this, "Created isolated named FirebaseApp '$appName'") },
             onFailure = { error ->
                 logger.e(this, "Failed to create named FirebaseApp '$appName'", error)
             },
         )
     }
 
     override suspend fun getToken(
         context: Context
     ): String? = suspendCancellableCoroutine { continuation ->
         resolveFirebaseMessaging(context).token
             .addOnCanceledListener {
                 continuation.resumeWithException(CancellationException())
             }
             .addOnSuccessListener { token ->
                 continuation.resumeWith(Result.success(token))
             }
             .addOnFailureListener(continuation::resumeWithException)
     }
 
     private fun resolveFirebaseMessaging(context: Context): FirebaseMessaging {
         val appName = namedFirebaseAppName(context)
         if (appName.isBlank()) {
             return FirebaseMessaging.getInstance()
         }
         return runCatching {
             FirebaseApp.getInstance(appName).get(FirebaseMessaging::class.java)
         }.getOrElse { error ->
             logger.e(
                 this,
                 "Could not resolve named FirebaseApp '$appName', " +
                     "falling back to [DEFAULT] FirebaseApp",
                 error,
             )
             FirebaseMessaging.getInstance()
         }
     }
 
     private fun namedFirebaseAppName(context: Context): String =
         cachedNamedAppName ?: exceptionHandler.runCatching(defaultValue = "") {
             context.getString(R.string.mindbox_firebase_app_name).trim()
         }.also { cachedNamedAppName = it }
 
     override fun getAdsId(context: Context): Pair<String?, Boolean> {
         val advertisingIdInfo = AdvertisingIdClient.getAdvertisingIdInfo(context)
         val id = advertisingIdInfo.id
         val isLimitAdTrackingEnabled = advertisingIdInfo.isLimitAdTrackingEnabled
         return id to isLimitAdTrackingEnabled
     }
 
     override fun isAvailable(context: Context) = GoogleApiAvailability.getInstance()
         .isGooglePlayServicesAvailable(context) == ConnectionResult.SUCCESS
 
     override fun convertToRemoteMessage(message: Any) = if (message is RemoteMessage) {
         exceptionHandler.runCatching(null) {
             MindboxFirebase.convertToMindboxRemoteMessage(message)
         }
     } else {
         null
     }
 }