问题
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.
回答1:
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)
回答2:
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
}
}
}
回答3:
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}
来源:https://stackoverflow.com/questions/56987962/how-to-bind-callscreeningservice