33

I hope to block some crank call, so I need to hang up some call programmatically in android.

The following fragment is from How to hang up outgoing call in Android?
Does it mean the technique of hang up call will be block at any time in further Android version?
Does it mean I can't write an app to hang up a call?

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.

Community
  • 1
  • 1
HelloCW
  • 843
  • 22
  • 125
  • 310

5 Answers5

76

First, you need to declare this permission in AndroidManifest.xml

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

Then you setup a BroadcastReceiver service for android.intent.action.PHONE_STATE (incoming calls) and android.intent.action.NEW_OUTGOING_CALL (outgoing calls) by adding the following to AndroidManifest.xml

AndroidManifest.xml

<receiver android:name=".PhoneStateReceiver">
    <intent-filter android:priority="0">
        <action android:name="android.intent.action.PHONE_STATE" />
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
    </intent-filter>
</receiver>

PhoneStateReceiver.JAVA

import java.lang.reflect.Method;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;

public class PhoneStateReceiver extends BroadcastReceiver {

    public static String TAG="PhoneStateReceiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.PHONE_STATE")) { 
            String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
            Log.d(TAG,"PhoneStateReceiver**Call State=" + state);

            if (state.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
                Log.d(TAG,"PhoneStateReceiver**Idle");
            } else if (state.equals(TelephonyManager.EXTRA_STATE_RINGING)) { 
                // Incoming call
                String incomingNumber = 
                        intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
                Log.d(TAG,"PhoneStateReceiver**Incoming call " + incomingNumber);

                if (!killCall(context)) { // Using the method defined earlier
                    Log.d(TAG,"PhoneStateReceiver **Unable to kill incoming call");
                }

            } else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
                Log.d(TAG,"PhoneStateReceiver **Offhook");
            }
        } else if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) { 
            // Outgoing call
            String outgoingNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
            Log.d(TAG,"PhoneStateReceiver **Outgoing call " + outgoingNumber);

            setResultData(null); // Kills the outgoing call

        } else {
            Log.d(TAG,"PhoneStateReceiver **unexpected intent.action=" + intent.getAction());
        }
    }

    public boolean killCall(Context context) {
        try {
            // Get the boring old TelephonyManager
            TelephonyManager telephonyManager =
                    (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

            // Get the getITelephony() method
            Class classTelephony = Class.forName(telephonyManager.getClass().getName());
            Method methodGetITelephony = classTelephony.getDeclaredMethod("getITelephony");

            // Ignore that the method is supposed to be private
            methodGetITelephony.setAccessible(true);

            // Invoke getITelephony() to get the ITelephony interface
            Object telephonyInterface = methodGetITelephony.invoke(telephonyManager);

            // Get the endCall method from ITelephony
            Class telephonyInterfaceClass =  
                    Class.forName(telephonyInterface.getClass().getName());
            Method methodEndCall = telephonyInterfaceClass.getDeclaredMethod("endCall");

            // Invoke endCall()
            methodEndCall.invoke(telephonyInterface);

        } catch (Exception ex) { // Many things can go wrong with reflection calls
            Log.d(TAG,"PhoneStateReceiver **" + ex.toString());
            return false;
        }
        return true;
    }

}

You can also use the following code from https://android.googlesource.com/platform/frameworks/base/+blame/71c2c37554ae53dffdf8e210f484d92af30620fa/docs/html/preview/features/runtime-permissions.jd?pli=1#548

MainActivity.JAVA

import android.Manifest; import android.content.pm.PackageManager;
import android.support.v4.app.ActivityCompat; import
android.support.v4.content.ContextCompat; import
android.support.v7.app.AppCompatActivity; import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

public static final int MY_PERMISSIONS_REQUEST_READ_PHONE_STATE = 101;
@Override protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.READ_PHONE_STATE)
            != PackageManager.PERMISSION_GRANTED) {

        // Should we show an explanation?
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.READ_PHONE_STATE)) {

            // Show an explanation to the user *asynchronously* -- don't block
            // this thread waiting for the user's response! After the user
            // sees the explanation, try again to request the permission.

        } else {

            // No explanation needed, we can request the permission.

            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.READ_PHONE_STATE},
                    MY_PERMISSIONS_REQUEST_READ_PHONE_STATE);

            // MY_PERMISSIONS_REQUEST_READ_PHONE_STATE is an
            // app-defined int constant. The callback method gets the
            // result of the request.
        }
    } }

@Override public void onRequestPermissionsResult(int requestCode,
                                       String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_PHONE_STATE: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                    && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay!

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    } } }
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
Kanaiya Katarmal
  • 5,974
  • 4
  • 30
  • 56
  • Thanks! Your code work well! There is a only problem. Normally, a warning information "missed call" will be displayed in notification bar when I miss a call. but the warning information "missed call" won't be displayed when I invoke the function killCall(Context context), how can I make the information to be displayed even if invoke the function killCall(Context context)? – HelloCW Apr 22 '14 at 08:00
  • @HelloCW you need to write contain provide DB of call log app manually in that above case – dharmendra Apr 25 '14 at 05:14
  • Can this solve you problem? Have you tried setting you phone to blocking mode? Link http://www.techrepublic.com/article/get-the-most-out-of-samsungs-blocking-mode/#. or just set it programatically – izbrannick Apr 25 '14 at 06:52
  • This works. Just tried the killCall method only on Android KitKat 4.4.4 – Fraggle Aug 17 '14 at 00:38
  • On adding the `android.intent.action.PHONE_STATE` and `android.intent.action.NEW_OUTGOING_CALL` to `AndroidManifest.xml`, it says `cannot resolve symbol PhoneStateReceiver`. Any workaround for that? – rrrocky Jan 13 '15 at 18:05
  • Edit: I guess we have to manually create the class PhoneStateReceiver. I have a sample [here](http://aprogrammersday.blogspot.in/2014/06/how-to-create-phonestatereceiver-get.html?showComment=1421172909215#c4892041050381603310) – rrrocky Jan 13 '15 at 18:19
  • 1
    Tested on Nexus 6P running 6.0.1 and killCall methods works OK – pelotasplus Sep 07 '16 at 22:19
  • for ending out going calls TelephonyManager.EXTRA_STATE_OFFHOOK is called not android.intent.action.NEW_OUTGOING_CALL – shakil.k Nov 20 '16 at 17:10
  • 1
    PhoneStateReceiver **java.lang.reflect.InvocationTargetException – Zax Aug 06 '17 at 12:47
  • Does this work on Android 8? java.lang.reflect.InvocationTargetException too! – Karl-John Chow Feb 08 '18 at 09:27
  • @Karl-John Chow did you find out some solution for 8.0 ? If yes kindly share it .Thanks – Ali Akram May 09 '18 at 05:57
  • @Zax did you find out some solution for 8.0 ? If yes kindly share it .Thanks – Ali Akram May 09 '18 at 05:57
  • @AliAkram: No. It doesn't allow. Pls do tag me if you get an answer for this. – Zax May 09 '18 at 07:14
  • @AliAkram it is just ignoring my method call. So no, not yet. – Karl-John Chow May 15 '18 at 07:55
  • If you're still looking for a solution for this and are targeting API level 21+, you should check out [TelecomManager](https://developer.android.com/reference/android/telecom/TelecomManager.html#endCall()). No Hacky BS. – spicy.dll Oct 19 '18 at 16:32
  • Worked perfectly for me – Stevie Feb 26 '20 at 06:50
  • TelecomManager tm = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) { tm = (TelecomManager) context.getSystemService(Context.TELECOM_SERVICE); if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ANSWER_PHONE_CALLS) != PackageManager.PERMISSION_GRANTED) { Log.d(TAG, "Permission denied"); return false; } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { tm.endCall(); } } – Ankit Kumar Mar 24 '21 at 21:46
4

Other answers are not working after changes to android API >= 26 (ANDROID_O)

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

Then

requestPermissions(new String[] {
   Manifest.permission.ANSWER_PHONE_CALLS
 }, PERMISSION_RQUEST);

Then

TelecomManager mgr = (TelecomManager) getSystemService(TELECOM_SERVICE);
mgr.endCall();
FindOutIslamNow
  • 1,169
  • 1
  • 14
  • 33
3

Does it mean the technique of hang up call will be block at any time in further Android version?

There's a possibility that Android Team would turn everything upside down for this concrete service. As for me, I think such possibility is pretty negligible.

Does it mean I can't write an app to hang up a call?

If the proposed approach works, why not? Just do it, keeping in mind (somewhere in background of your mind, yeah :)) that somewhere in the distant future something could get complicated, and you'll have to look for another dirty hack breaking through the rustless API, which does not allow you to hang a call.

Drew
  • 3,307
  • 22
  • 33
2

This is completely without testing but couldn't you just turn airplane mode off and on when a call that matches your blacklist appears?

Other than that, this seemed to work in pre kitkat http://androidsourcecode.blogspot.in/2010/10/blocking-incoming-call-android.html

dave
  • 1,410
  • 1
  • 16
  • 42
  • 1
    link mentioned by @dave works perfectly fine . i myself have tried it out. That example blocks all the incoming calls. – Gautami Apr 22 '14 at 11:45
0

If you are in JUnit test then this is how;

mInstrumentation = InstrumentationRegistry.getInstrumentation();
mInstrumentation.getUiAutomation().executeShellCommand( "input keyevent " + KeyEvent.KEYCODE_ENDCALL );

It may work also from outside the test but I haven't tried it.

bmilovanovic
  • 149
  • 1
  • 5