How to be notified when an outgoing phone call is

2019-04-11 19:28发布

问题:

Background

I need to get notified when a phone call is answered and hanged.

For incoming call, I use the TelephonyManager.ACTION_PHONE_STATE_CHANGED Intent with the TelephonyManager.EXTRA_STATE that comes with it.

The problem

For outgoing calls, you get a callback of TelephonyManager.ACTION_PHONE_STATE_CHANGED right after starting to dial, but not when the call was answered.

I've searched over the Internet, and all claim it's impossible to do it.

However, I've noticed that some call-recording apps (such as "Boldbeast recorder") have managed to overcome this, and somehow identify the moment that the call was answered.

What I've tried

I tried to register a ContentObserver to call logs, but this didn't help, because it only gets a callback when the call has ended.

For checking the issue, here's some code I've played with:

MainActivity.kt

class MainActivity : AppCompatActivity() {
    companion object {
        private val REQUEST_CODE = 0
        @JvmStatic
        fun getAppDeclaredPermissions(context: Context): Array<out String>? {
            val pm = context.packageManager
            try {
                val packageInfo = pm.getPackageInfo(context.packageName, PackageManager.GET_PERMISSIONS)
                return packageInfo.requestedPermissions ?: return null
            } catch (ignored: PackageManager.NameNotFoundException) {
            }
            throw RuntimeException("cannot find current app?!")
        }

    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val permissionsToRequest = getAppDeclaredPermissions(this)
            requestPermissions(permissionsToRequest, 0)
        }
    }
}

PhoneBroadcastReceiver.kt

class PhoneBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val action = intent.action
        val state = intent.getStringExtra(TelephonyManager.EXTRA_STATE)
        val incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER)
        Log.d("AppLog", "PhoneBroadcastReceiver $action $state $incomingNumber")
    }
}

manifest

<manifest package="com.example.user.myapplication" xmlns:android="http://schemas.android.com/apk/res/android"
          xmlns:tools="http://schemas.android.com/tools">

    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.READ_CALL_LOG"/>
    <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>

    <application
        android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"
        tools:ignore="GoogleAppIndexingWarning">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>

                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>


        <receiver android:name=".PhoneBroadcastReceiver">
            <intent-filter>
                <action android:name="android.intent.action.PHONE_STATE"/>
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
            </intent-filter>
        </receiver>
    </application>

</manifest>

The questions

How do those apps work? How do they get notified when an outgoing call is answered?