androidkotlintelephonymanager

Get info about incoming call from selected sim


I use a broadcast receiver to intercept calls coming to the phone and send them and then process them. I need to receive calls only from a certain SIM card in a two-key phone. I can try to do it like this

    override fun onReceive(context: Context, intent: Intent) {

        if (intent.getAction().equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
            try {
                val number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
                intent.extras
                if (number != null) {
                    val now = Date()
                    val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
                    Log.d(TAG, "stateName: $state number: $number")
                    Handler(Looper.getMainLooper()).postDelayed({
                        val c: Cursor? = context.contentResolver.query(
                            CallLog.Calls.CONTENT_URI,
                            null,
                            null,
                            null,
                            CallLog.Calls.DATE + " DESC"
                        )
                        var duration: Int? = null
                        var id: Int? = null
                        var num: String? = null
                        var type: Int = -100
                        var date: Date? = null
                        var iccId: String = ""
                        if (c?.columnCount?:0 > 0) {
                            c?.moveToFirst()
                            num = c?.getString(c.getColumnIndex(CallLog.Calls.NUMBER))
                            duration = c?.getInt(c.getColumnIndex(CallLog.Calls.DURATION))
                            type = (c?.getString(c.getColumnIndex(CallLog.Calls.TYPE)) ?: "-100").toInt()
                            iccId = c?.getString(c.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID))?:""
                            id = c?.getInt(c.getColumnIndex(CallLog.Calls._ID))
                            date = c?.getLong(c.getColumnIndex(CallLog.Calls.DATE))?.let { Date(it) }
                        }
                        c?.close()

                        if (id != null && number.equals(num, true)
                            && duration != null && date != null
                            && abs(now.time - duration - date.time) < 5_000) {
                            id = null
                            date = null
                            duration = null
                            iccId = ""
                        }

                        if (!SettingsStore(context).findEnabledFilters().contains(iccId)) {
                            sendToHandlers(context, number, state, duration, id, date)
                        }
                    }, 1_500)
                }
            } catch (e: Exception) {
                CrashMonitor.trackWarning(e.message, e.stackTraceToString())
                e.printStackTrace()
            }
        }
    }

I'm trying to filter calls by iccId, but I always get in intent from receiver the iccId of the PREVIOUS telephony status. Is there a way to somehow get the current iccID of the call, or perhaps there is another more correct and working way to get information only about calls to a specific SIM card?


Solution

  • I went the other way and started using a custom PhoneStateListener, creating inside broadcast receiver a telephonymanager subscription by the subscription id of the desired SIM card in the desired slot.

    Below is a slightly unfinished, but already working implementation example

    BroadcastReceiver

    class CallReceiver : BroadcastReceiver() {
    
        private val TAG = this::class.java.simpleName
    
        var telephony: TelephonyManager? = null
    
        @SuppressLint("Range", "UnsafeProtectedBroadcastReceiver")
        override fun onReceive(context: Context, intent: Intent) {
            val number: String?
            if (intent.action.equals(TelephonyManager.ACTION_PHONE_STATE_CHANGED)) {
                try {
                    number = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
                    intent.extras
                    if (number != null) {
                        val phoneListener = MyPhoneStateListener(context, number)
                        telephony = context
                            .getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager
                        val sm =
                            context.getSystemService(TELEPHONY_SUBSCRIPTION_SERVICE) as SubscriptionManager
                        if (ActivityCompat.checkSelfPermission(
                                context,
                                Manifest.permission.READ_PHONE_STATE
                            ) != PackageManager.PERMISSION_GRANTED
                        ) {
                            // TODO: Consider calling
                            //    ActivityCompat#requestPermissions
                            return
                        }
    
                        val mSim0TelephonyManager = telephony!!.createForSubscriptionId(1)
                        mSim0TelephonyManager!!.listen(
                            phoneListener,
                            PhoneStateListener.LISTEN_CALL_STATE
                        )
                    }
    
    
                } catch (e: Exception) {
                }
            }
        }
    
        fun onDestroy() {
            telephony!!.listen(null, PhoneStateListener.LISTEN_NONE)
        }
    
    
    }
    

    PhoneStateListener

    class MyPhoneStateListener(val context: Context, var number: String?) : PhoneStateListener() {
        private var stateName = ""
        override fun onCallStateChanged(state: Int, incomingNumber: String) {
            when (state) {
                TelephonyManager.CALL_STATE_IDLE -> {
                    Log.d("DEBUG", "IDLE")
                    phoneRinging = false
                    stateName = "IDLE"
                }
    
                TelephonyManager.CALL_STATE_OFFHOOK -> {
                    Log.d("DEBUG", "OFFHOOK")
                    phoneRinging = false
                    stateName = "OFFHOOK"
                }
    
                TelephonyManager.CALL_STATE_RINGING -> {
                    Log.d("DEBUG", "RINGING")
                    phoneRinging = true
                    stateName = "RINGING"
                }
            }
    
            number?.let { hand(context = context, number = it, duration = 1, id=10, state = stateName  ) }
        }
    
        companion object {
            var phoneRinging = false
        }
    }