如何在onCallAdded回调中获取当前设备的phone号码和SIM卡槽?

How to get the phone number and SIM card slot for the current device, on the callback of onCallAdded?

背景

我正在开发一个实现 InCallService 的应用程序,因此它可以处理 phone 个调用

问题

在具有多 SIM 卡的设备上,我需要显示使用了哪个 SIM 卡和关联的 phone 号码(当前设备)的信息。

问题是,我找不到从哪里获得这些信息。

我发现了什么

  1. 鉴于我达到了像 onCallAdded, I get an instance of Call class 这样的功能,所以我需要将我从那里得到的东西关联到 sim 插槽和 phone 号码.

  2. 使用 call.getDetails().getHandle() ,我可以获得一个 Uri,它只包含另一个呼叫者的 phone 号码(谁呼叫了当前用户,或者当前用户有谁称为)。

  3. 我可以遍历所有 SIM 卡,但找不到我可以用来在它们和当前通话之间进行映射的内容:

final TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
final SubscriptionManager subscriptionManager = SubscriptionManager.from(context);
for (final SubscriptionInfo subscriptionInfo : subscriptionManager.getActiveSubscriptionInfoList()) {
    final TelephonyManager subscriptionId = telephonyManager.createForSubscriptionId(subscriptionInfo.getSubscriptionId());
}
  1. 有一个旧代码不再有效,它使用 call.getDetails().getAccountHandle().getId()SubscriptionManager.from(context)getActiveSubscriptionInfoList().getActiveSubscriptionInfoList()

  2. 我想我可以使用 telephonyManager.getSubscriptionId(callDetails.getAccountHandle()) ,但它需要 API 30,这是相当新的...

问题

鉴于我从此回调(可能还有其他回调)收到的 phone 电话,我如何才能获得相关联的 SIM 插槽和它的 phone 号码?

我更想知道如何为尽可能广泛的 Android 版本做到这一点,因为 InCallService 来自 API 23...在 API 之前应该是可能的30 岁吧?

使用call.getDetails().getAccountHandle()得到PhoneAccountHandle

然后使用TelecomManager.getPhoneAccount() to get PhoneAccount实例。


针对 API 级别 31+ 的应用程序需要权限 Manifest.permission.READ_PHONE_NUMBERS


免责声明:我不是 Android 专家,所以请验证我的想法。


编辑:因此 API 30 之前和 API 30 之后的解决方案可能是这样的:

@RequiresApi(Build.VERSION_CODES.M)
fun handleCall(context: Context, call: Call) {
    var foundAndSetSimDetails = false
    val callDetailsAccountHandle = callDetails.accountHandle
    val subscriptionManager = context
        .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
    val telephonyManager =
        context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
    val telecomManager =
        context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
    val hasReadPhoneStatePermission =
        ActivityCompat.checkSelfPermission(context, Manifest.permission.READ_PHONE_STATE) == android.content.pm.PackageManager.PERMISSION_GRANTED
    val phoneAccount = telecomManager.getPhoneAccount(callDetailsAccountHandle)
    //TODO when targeting API 31, we might need to check for a new permission here, of READ_PHONE_NUMBERS
    //find SIM by phone account
    if (!foundAndSetSimDetails && phoneAccount != null && hasReadPhoneStatePermission) {
        val callCapablePhoneAccounts = telecomManager.callCapablePhoneAccounts
        run {
            callCapablePhoneAccounts?.forEachIndexed { index, phoneAccountHandle ->
                if (phoneAccountHandle != callDetailsAccountHandle)
                    return@forEachIndexed
                if (!phoneAccount.hasCapabilities(PhoneAccount.CAPABILITY_SIM_SUBSCRIPTION))
                    return@run
                //found the sim card index
                simName = phoneAccount.label?.toString().orEmpty()
                simIndex = index + 1
                foundAndSetSimDetails = true
                return@run
            }
        }
    }
    //find SIM by subscription ID
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && hasReadPhoneStatePermission) {
        try {
            val callSubscriptionId: Int =
                telephonyManager.getSubscriptionId(callDetailsAccountHandle!!)
            for (subscriptionInfo: SubscriptionInfo in subscriptionManager.activeSubscriptionInfoList) {
                val activeSubscriptionId: Int = subscriptionInfo.subscriptionId
                if (activeSubscriptionId == callSubscriptionId) {
                    setSimDetails(telephonyManager, subscriptionInfo)
                    foundAndSetSimDetails = true
                    break
                }
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
    }
    //find SIM by phone number
    if (!foundAndSetSimDetails && hasReadPhoneStatePermission) {
        try {
            val simPhoneNumber: String? = phoneAccount?.address?.schemeSpecificPart
            if (!simPhoneNumber.isNullOrBlank()) {
                for (subscriptionInfo in subscriptionManager.activeSubscriptionInfoList) {
                    if (simPhoneNumber == subscriptionInfo.number) {
                        setSimDetails(telephonyManager, subscriptionInfo)
                        foundAndSetSimDetails = true
                        break
                    }
                }
                if (!foundAndSetSimDetails)
            }
        } catch (e: Throwable) {
            e.printStackTrace()
        }
    }

    private fun setSimDetails(telephonyManager: TelephonyManager, subscriptionInfo: SubscriptionInfo) {
        var foundSimName: String? = null
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            val telephonyManagerForSubscriptionId =
                telephonyManager.createForSubscriptionId(subscriptionInfo.subscriptionId)
            foundSimName = telephonyManagerForSubscriptionId.simOperatorName
        }
        if (foundSimName.isNullOrBlank())
            foundSimName = subscriptionInfo.carrierName?.toString()
        simName = if (foundSimName.isNullOrBlank())
            ""
        else foundSimName
        simIndex = subscriptionInfo.simSlotIndex + 1
    }