I want to get hold of phone number Programmatically as the phone is ringing in android

237 Views Asked by At

I want the caller's number as the phone is ringing in android. Since "EXTRA_INCOMING_NUMBER" constant of "TelephonyManager" is deprecated now I don't know how to get the same functionality. I google it and came to know about "Call log" context but it can't do the same job as it gives you access to the number from the call log but I want the number as the phone is ringing.

1

There are 1 best solutions below

0
Wang Peiming On

For Android >= 29, you can use CallScreeningService instead. Official docs:

Here are the steps which works for me:

  1. Declare a MyCallScreeningService extending CallScreeningService
class MyCallScreeningService : CallScreeningService() {
    override fun onScreenCall(callDetails: Call.Details) {
        // Check if call is incoming and get the phone number
        Log.d("MyCallScreeningService", "onScreenCall")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            if (callDetails.callDirection == Call.Details.DIRECTION_INCOMING) {
                // Extract the incoming phone number
                val incomingNumber = extractPhoneNumber(callDetails)
                Log.d("MyCallScreeningService", "Incoming Call = $incomingNumber")
                val callResponse = CallResponse.Builder()
                    .setDisallowCall(false)
                    .setRejectCall(false)
                    .setSkipCallLog(false)
                    .setSkipNotification(false)
                    .build()
                // call this to notify user immediately, otherwise there will be a delay
                respondToCall(callDetails, callResponse)
            }
        }
    }

    private fun extractPhoneNumber(callDetails: Call.Details): String? {
        val handle = callDetails.handle
        if (handle != null) {
            // Attempt to extract phone number from the handle
            return handle.schemeSpecificPart
        } else {
            // Handle is null, try other methods if available
            val gatewayInfo = callDetails.gatewayInfo
            if (gatewayInfo != null) {
                return gatewayInfo.originalAddress.schemeSpecificPart
            }
        }
        return null
    }

}
  1. Add MyCallScreeningService to AndroidManifest.xml
<service android:name=".MyCallScreeningService"
    android:exported="true"
    android:permission="android.permission.BIND_SCREENING_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.CallScreeningService" />
    </intent-filter>
</service>
  1. Request role and bind service at your MainActivity or other Activity:
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val roleManager = getSystemService(ROLE_SERVICE) as RoleManager
            val intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING)
            val startForRequestRoleResult = registerForActivityResult(
                ActivityResultContracts.StartActivityForResult()
            ) { result: androidx.activity.result.ActivityResult ->
                if (result.resultCode == Activity.RESULT_OK) {
                    //  you will get result here in result.data
                    bindMyService()
                }
            }
            startForRequestRoleResult.launch(intent)
        }
    }

    private fun bindMyService(){
        Log.i("MainActivity", "binding my service")
        val mCallServiceIntent = Intent("android.telecom.CallScreeningService")
        mCallServiceIntent.setPackage(applicationContext.packageName)
        val mServiceConnection: ServiceConnection = object : ServiceConnection {
            override fun onServiceConnected(componentName: ComponentName, iBinder: IBinder) {
                // iBinder is an instance of CallScreeningService.CallScreenBinder
                // CallScreenBinder is an inner class present inside CallScreenService
            }
            override fun onServiceDisconnected(componentName: ComponentName) {}
            override fun onBindingDied(name: ComponentName) {}
        }
        bindService(mCallServiceIntent, mServiceConnection, BIND_AUTO_CREATE)
    }
}