Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ITelephony.endCall() doesn't work anymore for blocking calls in Android 8/Android O/API 26

I have an app that uses the following code to block calls:

TelephonyManager telephonyManager = 
    (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);

try {
    Class<?> telephonyManagerClass = 
        Class.forName(telephonyManager.getClass().getName());
    Method getITelephonyMethod = 
        telephonyManagerClass.getDeclaredMethod("getITelephony");
    getITelephonyMethod.setAccessible(true);
    Object iTelephony = getITelephonyMethod.invoke(telephonyManager);
    Class<?> iTelephonyClass = Class.forName(iTelephony.getClass().getName());
    Method endCallMethod = iTelephonyClass.getDeclaredMethod("endCall");
    endCallMethod.setAccessible(true);
    endCallMethod.invoke(iTelephony);
} catch (ClassNotFoundException e) {
    // ClassNotFoundException
} catch (NoSuchMethodException e) {
    // NoSuchMethodException
} catch (IllegalAccessException e) {
    // IllegalAccessException
} catch (InvocationTargetException e) {
    // InvocationTargetException
} catch (Exception e) {
    // Some other exception
}

To work, this required android.permission.MODIFY_PHONE_STATE in AndroidManifest.xml. In Android M and N, I also had to ask the user for permission Manifest.permission.CALL_PHONE.

But now in Android 8/Android O, the above code fails with InvocationTargetException: MODIFY_PHONE_STATE permission required

I found this related StackOverflow post: Android - Why does endCall method work but answerRingingCall doesn't work?

Here it is suggested that I might be able to use reflection on PhoneInterfaceManager (instead of ITelephony, like I have done above) and use the private method sendRequestAsync(int command) with the end call command, and by doing this getting around the security measure inside the endCall() method.

Has anyone tried something like this? Is it possible? How would I even get the PhoneInterfaceManager object/class instead of ITelephony?

I think this is the source code in question: https://android.googlesource.com/platform/packages/services/Telephony/+/oreo-release/src/com/android/phone/PhoneInterfaceManager.java

I can't see any difference between this and the code for Android N when it comes to ending calls, so I might be mistaken: https://android.googlesource.com/platform/packages/services/Telephony/+/nougat-release/src/com/android/phone/PhoneInterfaceManager.java

like image 959
Bjarte Aune Olsen Avatar asked Jun 08 '18 11:06

Bjarte Aune Olsen


1 Answers

Thanks to Nikola Brežnjak's blog, I found an answer: https://dev.to/hitman666/how-to-make-a-native-android-app-that-can-block-phone-calls--4e15

Basically, you need to include the ITelephony interface in your project. Create a file ITelephony.class with the following code (keep the namespace):

package com.android.internal.telephony;

public interface ITelephony {
    boolean endCall();
    void answerRingingCall();
    void silenceRinger();
}

Then from your code, use the following code to end a phone call:

// This is only useful on Android O and older
// Needs permission CALL_PHONE
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O
    || checkSelfPermission(Manifest.permission.CALL_PHONE)
        == PackageManager.PERMISSION_DENIED) {
    return;
}

try {
    ITelephony telephonyService;

    TelephonyManager telephonyManager = (TelephonyManager)
            getSystemService(Context.TELEPHONY_SERVICE);

    Method getITelephony = telephonyManager
            .getClass()
            .getDeclaredMethod("getITelephony");

    getITelephony.setAccessible(true);

    telephonyService = (ITelephony) getITelephony.invoke(telephonyManager);

    telephonyService.endCall();

} catch (Exception ignored) {
}
like image 68
Bjarte Aune Olsen Avatar answered Nov 08 '22 10:11

Bjarte Aune Olsen