Android Q has introduced CallRedirectionService
API - seems like one of the way 3rd party apps can use it is to cancel calls and reroute them over VoIP - essentially intercepting the phone calls.
I was trying to implement this class as below
public class CallMonitorService extends CallRedirectionService {
private static final String TAG = "CallMonitorService";
public CallMonitorService() {
}
@Override
public void onPlaceCall(Uri uri, PhoneAccountHandle phoneAccountHandle, boolean b) {
Log.e(TAG, "onPlaceCall:### ");
}
}
As you can see I am overriding onPlaceCall
which is abstract method in the CallRedirectionService
and simply keeping a log statement to check/test if this callback method hook is invoked by Android framework.
I added this service in my Manifest.xml as well as below, which is what is documented in the Source code of CallRedirectionService
class
<service
android:name=".CallMonitorService"
android:permission="android.permission.BIND_REDIRECTION_SERVICE"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.telecom.CallRedirectionService"/>
</intent-filter>
</service>
My Guess is that when Android system places a outgoing call this onPlaceCall
will be invoked and then we can write our custom code to do further action on the outgoing call. Am not 100% sure if this is how CallRedirectionService
is supposed to work - By the way there is no example available in developer.android.com for how to implement CallRedirectionService
as of this writing. I set both minSdkVersion 29
targetSdkVersion 29
in my build.gradle
However when the call is made - the onPlaceCall
inside my Service is not getting invoked.
I am using Android Q Emulator for testing as i do not have Android phone running Android Q to test this - can this be not tested on Android emulator by placing a emulated phone call or What else Am I missing?
android.telecom.CallRedirectionService. This service can be implemented to interact between Telecom and its implementor for making outgoing call with optional redirection/cancellation purposes.
permission. PROCESS_OUTGOING_CALLS. Allows the app to process outgoing calls and change the number to be dialed. This permission allows the app to monitor, redirect, or prevent outgoing calls.
The problem is that at the moment documentation is not full and sample in documentation is not correct. To fix this, in your AndroidManifest it is needed to change
android:permission="android.permission.BIND_REDIRECTION_SERVICE"
to
android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE"
This permission is incorrectly written inside the google documentation for https://developer.android.com/reference/android/telecom/CallRedirectionService.html currently.
Also, it is required to ask user to allow your application play this role. In google documentation this part missing at the moment :
RoleManager roleManager = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.Q) {
roleManager = (RoleManager) getSystemService(Context.ROLE_SERVICE);
Intent intent = roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_REDIRECTION);
startActivityForResult(intent, 1);}
Got it working (looking here). The next code will block all outgoing calls (it's just a sample...) :
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (!isRedirection())
roleAcquire(RoleManager.ROLE_CALL_REDIRECTION)
}
private fun isRedirection(): Boolean {
return isRoleHeldByApp(RoleManager.ROLE_CALL_REDIRECTION)
}
private fun isRoleHeldByApp(roleName: String): Boolean {
val roleManager: RoleManager?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
roleManager = getSystemService(RoleManager::class.java)
return roleManager.isRoleHeld(roleName)
}
return false
}
private fun roleAcquire(roleName: String) {
val roleManager: RoleManager?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
if (roleAvailable(roleName)) {
roleManager = getSystemService(RoleManager::class.java)
val intent = roleManager.createRequestRoleIntent(roleName)
startActivityForResult(intent, ROLE_ACQUIRE_REQUEST_CODE)
} else {
Toast.makeText(this, "Redirection call with role in not available", Toast.LENGTH_SHORT).show()
}
}
}
private fun roleAvailable(roleName: String): Boolean {
val roleManager: RoleManager?
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
roleManager = getSystemService(RoleManager::class.java)
return roleManager.isRoleAvailable(roleName)
}
return false
}
companion object {
private const val ROLE_ACQUIRE_REQUEST_CODE = 4378
}
}
MyCallRedirectionService.kt
class MyCallRedirectionService : CallRedirectionService() {
override fun onPlaceCall(handle: Uri, initialPhoneAccount: PhoneAccountHandle, allowInteractiveResponse: Boolean) {
Log.d("AppLog", "handle:$handle , initialPhoneAccount:$initialPhoneAccount , allowInteractiveResponse:$allowInteractiveResponse")
cancelCall()
}
}
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.callredirectionservicesample">
<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">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyCallRedirectionService"
android:permission="android.permission.BIND_CALL_REDIRECTION_SERVICE">
<intent-filter>
<action android:name="android.telecom.CallRedirectionService" />
</intent-filter>
</service>
</application>
</manifest>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With