Up to Android 7.1 it was possible to end an incoming call by using the ITelephony.endCall()
method and giving your app the permissions android.permission.CALL_PHONE
and android.permission.READ_PHONE_STATE
.
When doing the same on Android 8.0 Oreo (API 26)
, i get this error
12-09 18:11:25.195 16833-16833/li.doerf.leavemealone E/TelephonyServiceCallHangup: Missing permission MODIFY_PHONE_STATE, cannot hangup call
Since MODIFY_PHONE_STATE
is a protected permission, my app cannot get it. Is there a way to programmatically end an incoming call on Android 8.0+
?
Changed App Target and Compile level to 28.
And following permissions.
<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />
<uses-permission android:name="android.permission.READ_CALL_LOG"/>
Add the following code on onCallStateChanged method of MyPhoneStateListener class.
public void endCall() {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
TelecomManager tm = (TelecomManager) mcontext.getSystemService(Context.TELECOM_SERVICE);
if (tm != null) {
boolean success = tm.endCall();
}
// success == true if call was terminated.
} else {
if (mcontext != null) {
TelephonyManager telephony = (TelephonyManager) mcontext
.getSystemService(Context.TELEPHONY_SERVICE);
try {
Class c = Class.forName(telephony.getClass().getName());
Method m = c.getDeclaredMethod("getITelephony");
m.setAccessible(true);
telephonyService = (ITelephony) m.invoke(telephony);
// telephonyService.silenceRinger();
telephonyService.endCall();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
There is a solution that I found. It requires registering as a NotificationListenerService, then parsing the actions and and sending the proper PendingIntents:
public class NotificationListener extends NotificationListenerService {
private static final String TAG = "NotificationListener";
private PendingIntent answerIntent;
private PendingIntent hangupIntent;
@Override
public void onNotificationPosted(StatusBarNotification sbn) {
String packageName = sbn.getPackageName();
if ("com.google.android.dialer".equals(packageName)) {
Notification notification = sbn.getNotification();
for (Notification.Action action : notification.actions) {
String title = String.valueOf(action.title);
if ("hang up".equalsIgnoreCase(title) || "decline".equalsIgnoreCase(title)) {
hangupIntent = action.actionIntent;
} else if ("answer".equalsIgnoreCase(title)) {
answerIntent = action.actionIntent;
}
}
}
}
@Override
public void onListenerConnected() {
Log.i(TAG, "Listener connected");
for (StatusBarNotification sbn : getActiveNotifications()) {
onNotificationPosted(sbn);
}
}
public void answerCall() {
try {
answerIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
public void endCall() {
try {
hangupIntent.send();
} catch (PendingIntent.CanceledException e) {
e.printStackTrace();
}
}
}
Then declare the following in AndroidManifest.xml:
<service
android:name=".NotificationListener"
android:label="@string/app_name"
android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
<intent-filter>
<action android:name="android.service.notification.NotificationListenerService" />
</intent-filter>
</service>
There is one more step: The user has to manually enable your app as a notification listener. You can present a dialog with instructions, then send the user to the settings page using this code:
Intent intent = new Intent(android.provider.Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS);
startActivity(intent);
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