4

I want to get the Call Details and block the calls(if necessary). As the TelecomManager endCall method is deprecated and as per the documentation it is suggesting to use the CallScreeningService. https://developer.android.com/reference/android/telecom/CallScreeningService.html

As mentioned in the Android documentation, I am trying to bind the CallScreeningService with my application.

I have created a class

    public class CallUtil extends CallScreeningService {
      private Call.Details mDetails;
      private static CallScreeningUtil sCallScreeningUtil;

      @Override
      public void onScreenCall(Call.Details callDetails) {
        CallResponse.Builder response = new CallResponse.Builder();
        Log.e("CallBouncer", "Call screening service triggered");

        sCallScreeningUtil = this;
        mDetails = callDetails;
        respondToCall(callDetails, response.build() );
    }
}

This is a system app and I have added necessary permission in AndroidManifest.xml such as CALL_PHONE, MODIFY_PHONE_STATE, CALL_PHONE, ANSWER_PHONE_CALLS.

I have added the Service details as well like below,

 <service android:name=".CallUtil"
          android:permission="android.permission.BIND_SCREENING_SERVICE">
      <intent-filter>
          <action android:name="android.telecom.CallScreeningService"/>
      </intent-filter>
 </service>

I am kinda lost on how to bind this service with my activity or how do I bind this service with my application that will call the Overridden methods in CallUtil.

Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Perseus
  • 1,546
  • 4
  • 30
  • 55
  • Since this is a system application please tell us what Android API level your device is using. Vote up for the deprecation info. Does it mean it won't work any more or just recommending not to use it any more? – Sina Jul 29 '19 at 19:39

3 Answers3

4

Based on the documentation provided over here https://android.googlesource.com/platform/frameworks/base/+/9e1d4f86ba43e87264aba178f2bb037a3c3b26fb/telecomm/java/android/telecom/CallScreeningService.java

    Intent mCallServiceIntent = new Intent(this,"android.telecom.CallScreeningService");
        ServiceConnection mServiceConnection = new ServiceConnection(){

            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                // iBinder is an instance of CallScreeningService.CallScreenBinder
                // CallScreenBinder is an inner class present inside CallScreenService
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {

            }

            @Override
            public void onBindingDied(ComponentName name) {

            }
        }

And from an activity, to bind to the service you can use

bindService(mCallServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE)
Dinesh
  • 948
  • 6
  • 11
1

Have you request that it fills the call screening role??

Have you tried something like this as mentioned in android docs...?

public void requestRole() {
     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
     Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING");
     startActivityForResult(intent, REQUEST_ID);
 }

 @Override
 public void onActivityResult(int requestCode, int resultCode, Intent data) {
     if (requestCode == REQUEST_ID) {
         if (resultCode == android.app.Activity.RESULT_OK) {
             // Your app is now the call screening app
         } else {
             // Your app is not the call screening app
         }
     }
 }
Naitik Soni
  • 700
  • 8
  • 16
0

Here's the most basic implementation (based on sample repository from here, easier one here, if anyone wishes to check out):

MainActivity

@RequiresApi(Build.VERSION_CODES.Q)
class MainActivity : AppCompatActivity() {
    private val roleManager by lazy { getSystemService(RoleManager::class.java) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        when {
            roleManager.isRoleHeld(RoleManager.ROLE_CALL_SCREENING) ->
                Log.d("AppLog", "got role")
            roleManager.isRoleAvailable(RoleManager.ROLE_CALL_SCREENING) ->
                Log.d("AppLog", "cannot hold role")
            else ->
                startActivityForResult(roleManager.createRequestRoleIntent(RoleManager.ROLE_CALL_SCREENING), REQUEST_CALLER_ID_APP)
        }
    }

//TODO handle onActivityResult if you wish. This is just the basic stuff...

    companion object {
        private const val REQUEST_CALLER_ID_APP = 1
    }
}

BasicCallScreeningService

@RequiresApi(Build.VERSION_CODES.Q)
class BasicCallScreeningService : CallScreeningService() {
    override fun onScreenCall(callDetails: Call.Details) {
        val phoneNumber = callDetails.handle.schemeSpecificPart
        val callDirection = callDetails.callDirection
        //TODO do something with callDetails. Maybe call respondToCall(callDetails, CallResponse.Builder().build())
    }
}

manifest:

...
<service android:name=".BasicCallScreeningService"
    android:permission="android.permission.BIND_SCREENING_SERVICE">
    <intent-filter>
        <action android:name="android.telecom.CallScreeningService"/>
    </intent-filter>
</service>
...

In addition, you can have an after-call Activity being shown for phone calls you didn't block, using the ACTION_POST_CALL Intent :

<activity
    android:name=".AfterCallActivity"
    android:exported="true">
    <intent-filter>
        <action android:name="android.telecom.action.POST_CALL" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

In the Activity itself, you can have a bit of information about the phone call. Example:

{android.telecom.extra.HANDLE:tel:6505551212,android.telecom.extra.DISCONNECT_CAUSE:5,android.telecom.extra.CALL_DURATION:0}
android developer
  • 114,585
  • 152
  • 739
  • 1,270