I'm working on an app that implements InCallService, so it can handle phone calls
On devices with multi-SIM, I need to show information of which SIM and associated phone number is used (of the current device).
Thing is, I can't find where to get this information.
Given that I reach a function like onCallAdded, I get an instance of Call class, so I need to associate something I get from there, to a sim slot and phone number.
Using call.getDetails().getHandle()
, I can get a Uri consisting only the phone number of the other person that called (who called the current user, or who the current user has called).
I can iterate over all SIM cards, but can't find what I can use to map between them and the current call:
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());
}
There was an old code that doesn't work anymore that uses call.getDetails().getAccountHandle().getId()
and SubscriptionManager.from(context)getActiveSubscriptionInfoList().getActiveSubscriptionInfoList()
.
I think I can use telephonyManager.getSubscriptionId(callDetails.getAccountHandle())
, but it requires API 30, which is quite new...
Given a phone call that I get from this callback (and probably others), how can I get the associated SIM slot and phone number of it?
I prefer to know how to do it for as wide range of Android versions as possible, because InCallService is from API 23... It should be possible before API 30, right?
Use call.getDetails().getAccountHandle()
to get PhoneAccountHandle.
Then use TelecomManager.getPhoneAccount() to get PhoneAccount instance.
Permission Manifest.permission.READ_PHONE_NUMBERS
is needed for applications targeting API level 31+.
Disclaimer: I am no Android expert, so please do validate my thoughts.
EDIT: So solution for both before API 30 and from API 30 could be as such:
@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
}