Question

I see a lot of questions that it's impossible to end call programmatically in Android. At the same time, I see a lot of dialer apps in googleplay market where you can activate the call and drop it also. How do they work?

Edit: I've read somewhere that my app has to be system app. Then how to make it system, and what is the difference between system and user apps?

Was it helpful?

Solution

You do not need to be a system app. First, create package com.android.internal.telephony in your project, and put this in a file called "ITelephony.aidl":

package com.android.internal.telephony; 

interface ITelephony {      

boolean endCall();     

void answerRingingCall();      

void silenceRinger(); 

}

Once you have that, you can use this code to end a call:

TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Class clazz = Class.forName(telephonyManager.getClass().getName());
Method method = clazz.getDeclaredMethod("getITelephony");
method.setAccessible(true);
ITelephony telephonyService = (ITelephony) method.invoke(telephonyManager);
telephonyService.endCall();

You could use this inside a PhoneStateListener, for example. For this to work, you require permissions in manifest:

<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Edit: Apologies for horrible formatting, I still can't figure out how to properly do code blocks here :/

OTHER TIPS

For Android P (since Beta 2) and above, there is finally a formal API for endCall:

https://developer.android.com/reference/android/telecom/TelecomManager#endCall()

The ANSWER_PHONE_CALLS permission is required in manifest:

<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />

With the permission, for API level 28 or above:

TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);

if (tm != null) {
    boolean success = tm.endCall();
    // success == true if call was terminated.
}

At the same time the original endCall() method under TelephonyManager is now protected by MODIFY_PHONE_STATE permission, and can no longer be invoked by non-system Apps by reflection without the permission (otherwise a Security Exception will be triggered).

For Information.

May be of use in some situations. There is a potential workaround using the InCallService class. Most of the required information is here.https://developer.android.com/reference/android/telecom/InCallService.html#onCallRemoved(android.telecom.Call)

It does require setting your app as the default phone app and ensuring the following is granted.

<uses-permission android:name="android.permission.CALL_PHONE" />

If you implement your own class extending InCallService then when a call starts the call binds to your app and you get the call information through the onCallAdded() function. You can then simply call.disconnect() and the call will end.

Cut Call for the Api 28+

private void cutCall(){
    ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.READ_PHONE_STATE }, PHONE_STATE);
}

}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == PHONE_STATE) {
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ANSWER_PHONE_CALLS }, ANSWER_CALLS);
        } else if (requestCode == ANSWER_CALLS) {
            cutTheCall;
        }
    }
}

//This code will work on Android N (Api 28 and Above)

private boolean cutTheCall() {
    TelecomManager telecomManager = (TelecomManager) getApplicationContext().getSystemService(TELECOM_SERVICE);
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED || telecomManager == null) {
        return false;
    }

    if (telecomManager.isInCall()) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            callDisconnected = telecomManager.endCall();
        }
    }
    return true;
}

Along with Adding android telephony interface and a broadcast receiver, you will also need to add android manifest receiver entry with the action android.intent.action.PHONE_STATE for the reciever you want to handle intent.

You will get compile time error if you add

uses-permission android:name="android.permission.MODIFY_PHONE_STATE`

in your manifest file. But even if we remove this, it automatically rejects the incoming calls.

SilenceRinger() does not work for android 2.3+ versions. Just comment it, other code will work fine. Hope this works for you!

public static boolean isCallActive(Context context){
    AudioManager manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    if(manager.getMode()==AudioManager.MODE_IN_CALL || manager.getMode()==AudioManager.MODE_IN_COMMUNICATION){
        return true;
    }

    return false;
}

Just to add to @headuck's answer. For API 28, you also need to add:

<uses-permission android:name="android.permission.READ_CALL_LOG"/>

then request the permission in your activity. In total I requested these permissions to make it work (READ_PHONE_STATE, CALL_PHONE, ANSWER_PHONE_CALLS, READ_CONTACTS, READ_CALL_LOG)

You can end calls using Telecom manager. I tested it and it worked. You need permission ANSWER_PHONE_CALLS to do so. Even though it hints to answered calls I had it ending a call made from this phone. And this works for modern Androids.

   TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);

telecomManager.endCall();

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top