Tilek
Tilek

Reputation: 636

How to hang up outgoing call in Android?

I am developing an application where one of the things we need is to control the outgoing call, at least to be able to stop it from our application.

I've tried using Intent.ACTION_CALL from an existing activity:

Intent callIntent = new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + phoneNumber)); 
startActivity(callIntent); 

But stopping the call seems to be disallowed through the API.

Can you suggest some workaround?

For example: enabling airplane mode during the call? Just an example; this hack didn't work for me.

Upvotes: 48

Views: 48646

Answers (8)

Felipe
Felipe

Reputation: 17181

EDIT: To Android P or newer, please see: https://stackoverflow.com/a/51121175/450148

Try this:

(I used Reflection to access advanced telephony features and modify somethings)

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

try {
    //String serviceManagerName = "android.os.IServiceManager";
    String serviceManagerName = "android.os.ServiceManager";
    String serviceManagerNativeName = "android.os.ServiceManagerNative";
    String telephonyName = "com.android.internal.telephony.ITelephony";

    Class telephonyClass;
    Class telephonyStubClass;
    Class serviceManagerClass;
    Class serviceManagerStubClass;
    Class serviceManagerNativeClass;
    Class serviceManagerNativeStubClass;

    Method telephonyCall;
    Method telephonyEndCall;
    Method telephonyAnswerCall;
    Method getDefault;

    Method[] temps;
    Constructor[] serviceManagerConstructor;

    // Method getService;
    Object telephonyObject;
    Object serviceManagerObject;

    telephonyClass = Class.forName(telephonyName);
    telephonyStubClass = telephonyClass.getClasses()[0];
    serviceManagerClass = Class.forName(serviceManagerName);
    serviceManagerNativeClass = Class.forName(serviceManagerNativeName);

    Method getService = // getDefaults[29];
    serviceManagerClass.getMethod("getService", String.class);

    Method tempInterfaceMethod = serviceManagerNativeClass.getMethod(
                "asInterface", IBinder.class);

    Binder tmpBinder = new Binder();
    tmpBinder.attachInterface(null, "fake");

    serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder);
    IBinder retbinder = (IBinder) getService.invoke(serviceManagerObject, "phone");
    Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class);

    telephonyObject = serviceMethod.invoke(null, retbinder);
    //telephonyCall = telephonyClass.getMethod("call", String.class);
    telephonyEndCall = telephonyClass.getMethod("endCall");
    //telephonyAnswerCall = telephonyClass.getMethod("answerRingingCall");

    telephonyEndCall.invoke(telephonyObject);

} catch (Exception e) {
    e.printStackTrace();
    Log.error(DialerActivity.this,
                "FATAL ERROR: could not connect to telephony subsystem");
    Log.error(DialerActivity.this, "Exception object: " + e);
}

Upvotes: 28

android developer
android developer

Reputation: 116322

Here's the most updated code, which will work for Android P too, because it has an official API for it (here) :

in manifest, add this:

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

In code, use this:

Java:

@SuppressLint("PrivateApi")
public static boolean endCall(Context context) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        final TelecomManager telecomManager = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE);
        if (telecomManager != null && ContextCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
            telecomManager.endCall();
            return true;
        }
        return false;
    }
    //use unofficial API for older Android versions, as written here: https://stackoverflow.com/a/8380418/878126
    try {
        final Class<?> telephonyClass = Class.forName("com.android.internal.telephony.ITelephony");
        final Class<?> telephonyStubClass = telephonyClass.getClasses()[0];
        final Class<?> serviceManagerClass = Class.forName("android.os.ServiceManager");
        final Class<?> serviceManagerNativeClass = Class.forName("android.os.ServiceManagerNative");
        final Method getService = serviceManagerClass.getMethod("getService", String.class);
        final Method tempInterfaceMethod = serviceManagerNativeClass.getMethod("asInterface", IBinder.class);
        final Binder tmpBinder = new Binder();
        tmpBinder.attachInterface(null, "fake");
        final Object serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder);
        final IBinder retbinder = (IBinder) getService.invoke(serviceManagerObject, "phone");
        final Method serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder.class);
        final Object telephonyObject = serviceMethod.invoke(null, retbinder);
        final Method telephonyEndCall = telephonyClass.getMethod("endCall");
        telephonyEndCall.invoke(telephonyObject);
        return true;
    } catch (Exception e) {
        e.printStackTrace();
        LogManager.e(e);
    }
    return false;
}

or in Kotlin:

@SuppressLint("PrivateApi")
fun endCall(context: Context): Boolean {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        val telecomManager = context.getSystemService(Context.TELECOM_SERVICE) as TelecomManager
        if (ContextCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) == PackageManager.PERMISSION_GRANTED) {
            telecomManager.endCall()
            return true
        }
        return false
    }
    //use unofficial API for older Android versions, as written here: https://stackoverflow.com/a/8380418/878126
    try {
        val telephonyClass = Class.forName("com.android.internal.telephony.ITelephony")
        val telephonyStubClass = telephonyClass.classes[0]
        val serviceManagerClass = Class.forName("android.os.ServiceManager")
        val serviceManagerNativeClass = Class.forName("android.os.ServiceManagerNative")
        val getService = serviceManagerClass.getMethod("getService", String::class.java)
        val tempInterfaceMethod = serviceManagerNativeClass.getMethod("asInterface", IBinder::class.java)
        val tmpBinder = Binder()
        tmpBinder.attachInterface(null, "fake")
        val serviceManagerObject = tempInterfaceMethod.invoke(null, tmpBinder)
        val retbinder = getService.invoke(serviceManagerObject, "phone") as IBinder
        val serviceMethod = telephonyStubClass.getMethod("asInterface", IBinder::class.java)
        val telephonyObject = serviceMethod.invoke(null, retbinder)
        val telephonyEndCall = telephonyClass.getMethod("endCall")
        telephonyEndCall.invoke(telephonyObject)
        return true
    } catch (e: Exception) {
        e.printStackTrace()
        return false
    }
}

Upvotes: 9

Tony
Tony

Reputation: 109

For Ilana:

public class ilanasReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) {
            if (getResultData()!=null) {
                String number = "123456";
                setResultData(number);
            }
        }
    }
}

In addition in Manifest put in package section:

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

That is all.

Upvotes: 4

Paul Lammertsma
Paul Lammertsma

Reputation: 38252

Capturing the outgoing call in a BroadcastReceiver has been mentioned and is definitely the best way to do it if you want to end the call before dialing.

Once dialing or in-call, however, that technique no longer works. The only way to hang up that I've encountered so far, is to do so through Java Reflection. As it is not part of the public API, you should be careful to use it, and not rely upon it. Any change to the internal composition of Android will effectively break your application.

Prasanta Paul's blog demonstrates how it can be accomplished, which I have summarized below.

Obtaining the ITelephony object:

TelephonyManager tm = (TelephonyManager) context
        .getSystemService(Context.TELEPHONY_SERVICE);
try {
    // Java reflection to gain access to TelephonyManager's
    // ITelephony getter
    Log.v(TAG, "Get getTeleService...");
    Class c = Class.forName(tm.getClass().getName());
    Method m = c.getDeclaredMethod("getITelephony");
    m.setAccessible(true);
    com.android.internal.telephony.ITelephony telephonyService =
            (ITelephony) m.invoke(tm);
} catch (Exception e) {
    e.printStackTrace();
    Log.e(TAG,
            "FATAL ERROR: could not connect to telephony subsystem");
    Log.e(TAG, "Exception object: " + e);
}

Ending the call:

telephonyService.endCall();

Upvotes: 31

Gung Shi Jie
Gung Shi Jie

Reputation: 81

You can try enabling then disabling airplane mode:

android.provider.Settings.System.putInt(getContentResolver(),
        android.provider.Settings.System.AIRPLANE_MODE_ON, 1);

Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", 1);
sendBroadcast(new Intent("android.intent.action.AIRPLANE_MODE"));
sendBroadcast(intent);
android.provider.Settings.System.putInt(getContentResolver(),
        android.provider.Settings.System.AIRPLANE_MODE_ON, 0);

intent.putExtra("state", 0);
sendBroadcast(new Intent("android.intent.action.AIRPLANE_MODE"));
sendBroadcast(intent);

Upvotes: 5

Ash
Ash

Reputation:

  1. Create a BroadcastReceiver with a priority of 0.
  2. In the BC intercept the ACTION_NEW_OUTGOING_CALL intent in its onReceive method
  3. call setResultData(null) in the same method

This will prevent the call from initiating (as long as your receiver is the last to process the intent I think)

Upvotes: 21

Denis Souza
Denis Souza

Reputation: 59

According to the documentation on ACTION_NEW_OUTGOING_CALL

The Intent will have the following extra value:

EXTRA_PHONE_NUMBER - the phone number originally intended to be dialed.

Once the broadcast is finished, the resultData is used as the actual number to call. If null, no call will be placed.

Upvotes: 0

Pat
Pat

Reputation: 5911

Considering the potential for wonderful mischief I would be surprised if this is allowed.

This thread says flatly that the API cannot end a call. Others have tried.

Upvotes: 3

Related Questions