Android – eUICC Issue while eSIM Activation with Same eSIM on Different Devices

I have a telecommunication application (written in Jetpack Compose) which helps to install eSIM with just a single click.

I’ve created an EsimHandler to do this. Here you can see:

import android.app.Activity
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
import android.telephony.TelephonyManager
import android.telephony.euicc.DownloadableSubscription
import android.telephony.euicc.EuiccManager
import android.util.Log
import androidx.annotation.RequiresApi
import kotlinx.coroutines.*

private const val ACTION_DOWNLOAD_SUBSCRIPTION = "download_subscription"
private const val TAG_ESIM = "TAG_ESIM"
class EsimHandler {
    private lateinit var onEsimDownloadListener: OnEsimDownloadListener

    private val receiver = object : BroadcastReceiver() {
        @RequiresApi(Build.VERSION_CODES.P)
        override fun onReceive(context: Context?, intent: Intent?) {
            val resultCode = resultCode

            when (resultCode) {
                EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK -> {
                    /*Download profile was successful*/
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                        // eSim is active
                        onEsimDownloadListener.onResultOK()
                    } else {
                        // eSim is inactive due to the SDK does not support this API level
                        onEsimDownloadListener.onResultError()
                    }
                }
                EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR -> {
                    /*Download profile was not successful but resolvable*/
                    onEsimDownloadListener.onResultResolvableError()
                    val mgr = context?.getSystemService(Context.EUICC_SERVICE) as EuiccManager
                    handleResolvableError(context, intent!!, mgr)
                }
                else -> { /*Download profile was not successful*/
                    onEsimDownloadListener.onResultError()
                }
            }
        }
    }

    fun init(param: OnEsimDownloadListener) {
        this.onEsimDownloadListener = param
    }

    @OptIn(DelicateCoroutinesApi::class)
    @RequiresApi(Build.VERSION_CODES.P)
    fun downloadEsim(context: Context, code: String) {
        /*
        if (!checkCarrierPrivileges(context)) {
            onEsimDownloadListener.onCheckCarrierPrivilegesFailure()
            return
        }
         */

        val mgr = context.getSystemService(Context.EUICC_SERVICE) as EuiccManager

        if (!mgr.isEnabled) {
            onEsimDownloadListener.onMgrIsEnabledFailure()
            return
        }

        // Download subscription asynchronously
        val sub = DownloadableSubscription.forActivationCode(code)
        val intent = Intent(ACTION_DOWNLOAD_SUBSCRIPTION)
        val callbackIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT)
        } else {
            PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_MUTABLE)
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            context.registerReceiver(receiver, IntentFilter(ACTION_DOWNLOAD_SUBSCRIPTION), Context.RECEIVER_NOT_EXPORTED)
        } else {
            context.registerReceiver(
                receiver, IntentFilter(ACTION_DOWNLOAD_SUBSCRIPTION),
                null, null
            )
        }

        GlobalScope.launch {
            withContext(Dispatchers.Main) {
                try {
                    mgr.downloadSubscription(sub, true, callbackIntent)
                } catch (e: Exception) {
                    onEsimDownloadListener.onResultError()
                }
            }
        }

    }

    // Checks for carrier privileges on the device
    private fun checkCarrierPrivileges(context: Context): Boolean {
        val telephonyManager =
            context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

        val isCarrier = telephonyManager.hasCarrierPrivileges()

        return if (isCarrier) {
            Log.i(TAG_ESIM, "Ready with carrier privileges")
            true
        } else {
            Log.i(TAG_ESIM, "No carrier privileges detected")
            false
        }
    }

    @RequiresApi(api = Build.VERSION_CODES.P)
    private fun handleResolvableError(context: Context, intent: Intent, mgr: EuiccManager) {
        try {
            // Resolvable error, attempt to resolve it by a user action
            val resolutionRequestCode = 3
            val callbackIntent = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
                PendingIntent.getBroadcast(context, resolutionRequestCode, Intent(ACTION_DOWNLOAD_SUBSCRIPTION), PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT)
            } else {
                PendingIntent.getBroadcast(context, resolutionRequestCode, Intent(ACTION_DOWNLOAD_SUBSCRIPTION), PendingIntent.FLAG_MUTABLE)
            }
            mgr.startResolutionActivity(
                context.activity(),
                resolutionRequestCode,
                intent,
                callbackIntent
            )
        } catch (e: Exception) {
            onEsimDownloadListener.onResultError()
            Log.d(TAG_ESIM,
                "EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR - Can't setup eSim due to Activity error "
                        + e.localizedMessage
            )
        }
    }

    private fun Context.activity(): Activity? = when {
        this is Activity -> this
        else -> (this as? ContextWrapper)?.baseContext?.activity()
    }
}

Simply, first I initialize my onEsimDownloadListener in onCreate of MainActivity. Then, in related areas, I trigger downloadEsim method via my viewmodel, then it registers a BroadcastReceiver that listens the result code of this event. When I got a result code, I listen it via my onEsimDownloadListener

I’m %100 sure that my eSIM profile has carrier privilege because I can install eSIM on my Google Pixel 7a device with Android 13 perfectly. But the problem is, I can’t install same eSIM profile to my Samsung Galaxy S23 with Android 14.

While I’m trying to install eSIM profile to Google Pixel 7a device with Android 13, after I trigger downloadEsim method, it joins resolvable error case. Then I see those logs:

EuiccController         com.android.phone                    I  isCompatChangeEnabled changeId: SOME_ID_HERE_BLABLA changeEnabled: true
EuiccController         com.android.phone                    D   downloadSubscription cardId: 0 switchAfterDownload: true portIndex: 0 forceDeactivateSim: false callingPackage: com.myapp.myapp isConsentNeededToResolvePortIndex: false shouldResolvePortIndex:true
EuiccController         com.android.phone                    I  Caller can't manage subscription on target SIM or  User consent is required for resolving port index. Ask user's consent first

then I see this on my phone:

I click Yes, then I see those logs:

EuiccController         com.android.phone                    I   continueOperation portIndex: 0 usePortIndex: true
EuiccController         com.android.phone                    D   downloadSubscriptionPrivilegedCheckMetadata cardId: 0 switchAfterDownload: true portIndex: 0 forceDeactivateSim: true

5 seconds later, I see this log:

EuiccController         com.android.phone                    I  Calling package has carrier privilege to this profile

Then after I wait 5 minutes, my eSIM profile is downloaded and installed successfully.

While I’m trying to install eSIM profile to Samsung Galaxy S23 with Android 14, after I trigger downloadEsim method, I see those logs:

EuiccController         com.android.phone                    I  isCompatChangeEnabled changeId: SOME_ID_HERE_BLABLA changeEnabled: true
EuiccController         com.android.phone                    I  No UiccSlotInfo found for cardId: 0
EuiccController         com.android.phone                    D  Switch to inactive slot, return default port index. slotIndex: -1
EuiccController         com.android.phone                    D   downloadSubscription cardId: 0 switchAfterDownload: true portIndex: 0 forceDeactivateSim: false callingPackage: com.myapp.myapp isConsentNeededToResolvePortIndex: false shouldResolvePortIndex:true
EuiccController         com.android.phone                    D  euiccController phoneId: 1
EuiccController         com.android.phone                    E  Calling package doesn't have carrier privilege to this profile
EuiccController         com.android.phone                    I  The target SIM is not an eUICC.
EuiccController         com.android.phone                    I  Caller can't manage subscription on target SIM or  User consent is required for resolving port index. Ask user's consent first
EuiccController         com.android.phone                    I  The target SIM is not an eUICC.
EuiccController         com.android.phone                    I  euiccController add EuiccService.NO_PRIVILEGED

Then nothing happens. I can’t receive nothing from my receiver. My onEsimDownloadListener doesn’t observe nothing.

I tried my chance with this official link, but nothing happens.

Those lines are already added in my Manifest file:

<!--
    Needed for Single Click eSIM Activation
    -->
    <uses-permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
        tools:ignore="ProtectedPermissions" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
        tools:ignore="ProtectedPermissions" />

<service android:name=".SampleCarrierConfigService"
            android:exported="true"
            android:permission="android.permission.BIND_CARRIER_SERVICES">
            <intent-filter>
                <action android:name="android.service.carrier.CarrierService"/></intent-filter>
        </service>

What am I missing ? How can I solve this issue on my other device ?

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật