Monday, May 12, 2014

Disconnect Block Drop calls Android 4 and above

The internet is littered with forum posts and articles that would tell you it is impossible to block drop disconnect an incoming or outgoing call using code starting Android version 4 Jelly Bean, because Google placed strict restrictions on MODIFY_PHONE_STATE permission. Only the manufacturer signing certificate can grant you MODIFY_PHONE_STATE permission.
block drop disconnect call android


Download Best Call Blocker my app based on the technique described in this post

https://play.google.com/store/apps/details?id=bestcallblocker.honestitconsultancy.com

There are a lot of call blocker type of scenarios in which we need to shield our user from a bad guy's or sour ex girl friend's telephone calls.
The good news is, you don't need to MODIFY_PHONE_STATE permission to block drop disconnect an incoming call on Google Android . The technique described here is available to drop block disconnect incoming calls without using the secretive infamous permission.

Time to disclose the secret sauce, a hint first:
Ever tried to dial a call using ADB(Android Debugger Bridge) shell?

If you've done that, it is going to be very simple to disconnect or drop a call using a similar technique.
Time to spill the secret sauce, on the internet.

Drop call on Android 4 Jelly Bean KitKat and above




The exact Java code to drop disconnect or reject an incoming call or an outgoing call on an Android 4 and above system is given below:

I'm working as a freelance programmer through ODesk.com, you may hire me thorough following link:


public int disconnectCallAndroid()
{
 Runtime runtime = Runtime.getRuntime();
 int nResp = 0;  
 try
 {    
  Log.d(Keys.LOGTAG, "service call phone 5 \n");
  runtime.exec("service call phone 5 \n");   
 }catch(Exception exc)
 {
  Log.e(Keys.LOGTAG, exc.getMessage());
  exc.printStackTrace();
 }
 return nResp;
}

UPDATE:
A reader has complained that the technique described here works through ADB Shell on their Nexus S Android smart phone but it does nothing when tried through code.
The app in which I'm using this code is basically taking input over UDP/Bluetooth Sockets and performing disconnect call action in an IntentService. Please note that IntentService is running separately in its own thread.
From Android version 4 Jelly Bean which is API level 14 Android blocks user apps to perform lengthy operations on the UI thread. In that case, you can use a SingleThreadExecutor and spin off a new thread to initiate run time in order to perform call disconnect/drop/block operation. Sample code is given below.

Executor eS = Executors.newSingleThreadExecutor();
eS.execute(new Runnable() {
 @Override
 public void run() {
  disconnectCall();
  }
});// code formatting with tohtml.com/java/

Wait a minute, what about the permissions required to do this?
Well following Android permissions are needed to mess with calls:

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

The disconnectCallAndroid method will effectively disconnect a telephone call in following states:
  1. Incoming call, which is in ringing state
  2. Outgoing call, which might be ringing on the other end or not
  3. Connected call, while you're talking be it dialled by you or the other party
Nothing will happen if an active call in any of the aforementioned states does not exist on the phone.
I have tested my code on an Android 4.1.3 smart phone QMobile A50.
Update: I tested the call disconnect/reject/drop/cut on a friend's LG G2 which has got Android KitKat 4.4 installed, and it worked like a charm.
Update: A friend tested the call disconnect/reject/drop/cut on a friend's Samsung Galaxy S 4 (SGS 4) which ahas got Android KitKat 4.4 installed, call disconnect worked on it as well ;)

Call disconnect technique is tested on following Android devices/versions

  1. Samsung Galaxy S4 Android KitKat Version 4.2.2
  2. LG G2 Android KitKat 4.4
  3. Sony Xperia Z Android 4.3 KitKat
  4. Q Mobilie A 50 Android 4.1 Jelly Bean
  5. Nexus 5 Android 4.4.2
  6. LG Optimus 4G LTE Tag Android 2.2 Froyo
  7. Samsung Galaxy S3 Android 4.3 (Contributed by user Said Dami)
  8. Samsung STARS Android 4.1 (Contributed by user Said Dami)

Older versions of Android

The commands slightly different on older versions of Android.
In order to disconnect reject drop call I had to use 8 in place of 4 on an Android 2.2 smart phone and the command became

runtime.exec("service call phone 8 \n");

Ain't that very simple? I hope the blog post is going to help a lot of troubled Android coders.

Be careful

The magic number 4 and 8 can be changed in any version of Android without a notice, you'll only wake up when your clients will come crying to you and tell that "Mommy the app is broken".

Please feel free to check my profile on Elance and ODesk, Elance widget is given on top right of the page.

I'm working as a freelance programmer through ODesk.com, you may hire me thorough following link:


42 comments:

  1. I have tried this in a Nexus 5 and is not doing anything, i tried 4, 5 and 8 with no luck.
    where can i find more info about this ?

    ReplyDelete
  2. Which Android version is running on your Nexus 5? Did you specify the appropriate permissions in manifest.xml?
    The magic numbers are subject to change without prior notice, these are defined in ITelephony.java. An example can be seen here
    http://goo.gl/hbXfie
    A quick hack is to connect to your device through adb shell and execute the service call phone command with various options. Make sure a call is in ringing, dialling, or connected state before running the command otherwise you won't know if it dropped something or not. I actually discovered that disconnecting a call was possible by hit and try :)

    ReplyDelete
  3. @Jorge I hope you will figure out the correct number some time soon, please let me know if it worked for you. For developer community this will be a very useful information, I will like to add your device/Android version into the list of tested devices. Thank you.

    ReplyDelete
  4. it does work if i do the adb shell command, but it doesn't work when i do it trough code :S

    ReplyDelete
  5. That's nasty, maybe you could perform the operation in a separate thread because Android OS 4+ does not allow certain long running tasks on the UI thread.
    One more thing, please tell the model of your phone and the Android OS version your are running I want to put it in the list of devices where this code is tested and working.

    ReplyDelete
  6. I've updated the post, please give it a try.

    ReplyDelete
  7. Let me test it and ill let you know the result, by the way i am using a Nexus 5 with 4.4.2 OS

    ReplyDelete
  8. Hello Akram

    I am struggling with this. Maybe you can please help me. I am trying to capture the incoming call and compare it with my database (that I have created of phone numbers) and take some action. I am implementing a broadcast receiver and phonestatelistener but when I keep the database access code in the call_state_ringing case, it is not working. But when I hard code the comparison of incoming number with some number in a IF statement it works. How to access database and compare the incoming number and take some action please?

    ReplyDelete
  9. Hi Anonymous :)
    Try debugging your stuff, maybe there's a string mismatch or something. I am putting together a post which describes a phone state listener, I hope it will help you.

    ReplyDelete
  10. Hey Thanks so much. I didn't mean to put it as anonymous. I am Mac here. I thought anonymous means without using email. I didn't want to use email ID because sometimes it tries to extract my email IDs in account. I got the smirk on your face :)

    I heard that the phonestatelistener doesn't let us put code directly but to use a service or an intent service. Didn't know how to do it. All I am asking is: after I find the state (for example: call_state_ringing), I need to be able to run a code (for example: a database access and then compare the incoming number) either directly or as a service or as an intent service. I hope your post which you mentioned address that. Thanks once again.

    ReplyDelete
  11. Hey Mac! I've published the post, it does not handle the intent service stuff but that is fairly simple. First, please try the phone state listener which is given in a blog post along with full code and explanation.

    http://aprogrammersday.blogspot.com/2014/06/how-to-create-phonestatereceiver-get.html

    ReplyDelete
  12. You may use executor service like this:
    Executor eS = Executors.newSingleThreadExecutor();
    eS.execute(new Runnable() {
    @Override
    public void run() {
    putStuffInDB();
    }
    });// code formatting with tohtml.com/java/

    ReplyDelete
  13. Here is what I have:Please ignore syntax. I can take care of that.

    public class PhoneCallReceiver extends BroadcastReceiver {
    SQLiteDatabase db1 = null;
    blah blah blah ...

    public void onCallStateChanged(int state, String incomingNumber) {
    super.onCallStateChanged(state, incomingNumber);

    switch (state) {
    case TelephonyManager.CALL_STATE_RINGING:

    Create a table if not exists and

    Read field mobileno array from database;


    if (mobileno contains incomingNumber) {

    Do Something;
    }

    else{}
    break:

    ReplyDelete
  14. Did you try to run you code in debug mode? And do use Log.d method call to print various information about the internals of your logic. I don't see anything wrong with your logic, maybe you should put this same stuff in a separate thread as Android OS does not like lengthy operations such as database and http reads in UI threads and broadcast receivers as well.

    ReplyDelete
  15. Excellent my friend. I will try all that you said and update you. Thank you. Mac

    ReplyDelete
  16. It is simply not letting me add the DB within the PhoneStateListener class nor letting me add a service. When I say startService(Intent) it keeps saying create a method for startService. I am almost giving up :) - Mac

    ReplyDelete
  17. context.Startservice() will work here, BTW I can look into your code and make it work for sure.

    ReplyDelete
  18. Assalam-o-Alaikum Naeem Akram ! can u plz send me a complete project because i don't know how to i use your code OR how to i block specific number through this code ?
    Regards
    Muhammad Faisal

    ReplyDelete
  19. Faisal, Walekum Salam. If you combine the post about CLI and PhoneStateReceiver along with this one, you can easily figure out how to block calls from selective telephone numbers. Link below
    http://aprogrammersday.blogspot.com/2014/06/how-to-create-phonestatereceiver-get.html

    I am thinking to make my project "Best Call Blocker" open source and make it a public repo on GitHub, in case I do that I will post the news on this blog and then you could take a look.

    ReplyDelete
  20. Help me please. I'm using this command: runtime.exec("service call phone 8 \n"), using Samsung Galaxy with Android 2.3 but not working.
    runtime.exec("service call phone 5 \n"), run fine using a Chinese phone with Android 4.2.

    ReplyDelete
  21. Try a different number, I had a rooted phone and I granted SU permissions to the ADB shell process then I started from number 1 and went up to 23. In your case maybe you could create a simple activity with a text box and button and get the value of text box on button click to replace it with "service call phone %s\n".
    Different Android versions work with different numbers. :)

    ReplyDelete
  22. Before doing that. Does anyone have a list of numbers and versions?. I would save some work.

    ReplyDelete
  23. Don't be lazy Anonymous... Move some rocks by yourself, maybe you will find something unexpected and wonderful...

    ReplyDelete
  24. ok. let's go. thanks.

    ReplyDelete
  25. thanks!!!that's work on S3 android 4.3 AND samsng STARS android 4.1

    ReplyDelete
  26. That's wonderful Said Dami, I will add these devices to the supported list as well.
    Thank you very much for the comment.

    ReplyDelete
  27. Magic number for my SGS2 with Android 4.3 (cyanogenmod) is 6. Unfortunately, "service call phone 6" picks up the call in Android 4.4 AVD :(.

    ReplyDelete
  28. Yet another cool piece of information! Thanks a lot for sharing, I will upgrade main article with this information some time. This is certainly not a very good technique, but unfortunately its the only way to disconnect a call discovered so far(for me at least). Keep up the good work...

    ReplyDelete
  29. Finally got it working with your latest update.
    nexus 5 4.4.4

    ReplyDelete
  30. That's a very good news... This technique works but unfortunately it is far from perfect... Still, I'm glad at least some people are benefiting :)

    ReplyDelete
  31. Hi, Naeem!
    Your solution works! But how to remove the missed call notification?

    ReplyDelete
    Replies
    1. buddy I responded to your comment in main comments thread, please read it there :D BTW its just a work around to take care of missed call notifications.

      Delete
  32. Hi, Naeem!
    This technique don't works in samsung w2013 and samsung i879. is anything other infomation to solve this question?

    ReplyDelete
    Replies
    1. Hi Anonymous,
      I hope you've read the comments already present on this blog post, maybe going through the comments once again will be helpful.
      The 5 in "service call phone 5" is different for different versions of Android, it is not a standard and its not documented in many cases. Maybe the version of Android on your devices is going to work with some other number to disconnect the calls.
      In that case, hit and try is your only option. Call from your phone to another phone and then run command with parameter 0, then 1, then 2 and so forth up to 30 I believe. Hopefully the tip will help :)

      Delete
  33. Hi second last Anonymous,
    You will have to remove the missed call notification separately my friend. I believe you can that right after disconnecting the call. Or maybe save the number somewhere and create an alarm that could fire after 2 seconds and cleanse the call log for the blocked number ;)

    ReplyDelete
  34. "service call phone 6" worked on rooted nexus4 (cyanogenmod 11)

    ReplyDelete
  35. Thank you Juan, I believe I shall add these comments to main post with proper commentator reference. A blog post dedicated to nuances of this approach can be helpful as well. :)

    ReplyDelete
  36. Thanks, man. Works on Samsung Galaxy Core Duos (I8262), running Jelly Bean 4.1.2.

    ReplyDelete
  37. I have launched a free online course at Udemy titled "Quick TCP/IP Socket Programming For Coders using C#.Net", it is a very informative course. Please sign-up for free, watch the course and provide your highly valued feedback. I will be very thankful.
    Link is given below:
    https://www.udemy.com/tcpip-socket-programming-for-coders-using-csharp-net/#/

    ReplyDelete
  38. doesn't work on Lollipop, even through ADB

    ReplyDelete
  39. Then I guess Google must have plugged the hole, I don't have a Lollipop device on hand to experiment so I can't say anything for sure :)

    ReplyDelete

Feel free to talk back...