Gabriele Bellini
Gabriele Bellini

Reputation: 31

Access phone number in TelephonyCallback - Android

PhoneStateListener's onCallStateChanged took the state of the phone call and the number being called as parameters:

val telephonyManager =
    context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

telephonyManager.listen(
    object : PhoneStateListener() {
        override fun onCallStateChanged(state: Int, phoneNumber: String) {
            super.onCallStateChanged(state, phoneNumber)
        }
    },
    PhoneStateListener.LISTEN_CALL_STATE
)

After the deprecation of listen() and PhoneStateListener, the suggested way to listen to phone calls is through registerTelephonyCallback(), that takes an Executor and a TelephonyCallback as parameters, the problem is that TelephonyCallback.CallStateListener's onCallStateChanged only takes the call state as parameter:

telephonyManager.registerTelephonyCallback(
    context.mainExecutor,
    object : TelephonyCallback(), TelephonyCallback.CallStateListener {
        override fun onCallStateChanged(state: Int) {
            // WHERE IS PHONE NUMBER?
        }
    }
)

I absolutely need to know the phone number being called in order to make my app work properly.
Does someone know how to obtain it using TelephonyCallback or, at least, without using deprecated methods?

Upvotes: 2

Views: 3931

Answers (2)

Gülsen Keskin
Gülsen Keskin

Reputation: 810

I have accessed it using intent:

val incomingNumber: String? = intent?.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)

https://github.com/gulsenkeskin/phone_call_demo/blob/main/android/app/src/main/kotlin/com/example/phone_call_demo/MainActivity.kt

Upvotes: 0

Gabriele Bellini
Gabriele Bellini

Reputation: 31

I solved it using CallScreeningService, that is available from API 24, but unusable until API 29 because of callDirection:

@RequiresApi(Build.VERSION_CODES.N)
class PhoneCallScreening : CallScreeningService() {
    override fun onScreenCall(callDetails: Call.Details) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (callDetails.callDirection == Call.Details.DIRECTION_OUTGOING) {
                val phoneNumber = callDetails.handle.schemeSpecificPart

                PreferenceManager
                    .getDefaultSharedPreferences(this)
                    .edit()
                    .putString(CALLED_PHONE_NUMBER_KEY, phoneNumber)
                    .apply()
            }
        }
    }
}

In order to use this, your app has to become the default one for call screening:

@RequiresApi(api = Build.VERSION_CODES.Q)
public void requestRole() {
    RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
    Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING);
    startActivityForResult(intent, PHONE_SCREENING_REQUEST_ID);
}

I don't know if you can access any other information about the call besides the phone number, I currently save the phone number in SharedPreferences and then access it in the new PhoneStateListener's onCallStateChanged.

As I said before, this solution is only possible from API 29, for lower API versions you have to use the deprecated way, I think is the only one to achieve this.

Upvotes: 1

Related Questions