Tuesday, March 29, 2011

Call Control in Android

This tutorial is for those who want to control Phone Call in Android OS. Programmatic approach to Accept or Reject call without user intervention.
Kindly note, this approach uses Java Reflection to call methods of an internal class of Android Telephony Framework and might not work with all versions of Android OS. The core concept has been explained in this open code
1st thing 1st, Give the permission...
You need to define 3 User Permissions to handle call related functionality- (due to limitation of Blogger XML Tag marking has been replaced with “[“ and “]”)
[uses-permission android:name="android.permission.READ_PHONE_STATE"/]
[uses-permission android:name="android.permission.MODIFY_PHONE_STATE"/] (For answerRingingCall() method)
[uses-permission android:name="android.permission.CALL_PHONE"/] (For endCall() method)
Define a Receiver...
Create a Receiver which accepts broadcasts with intent action android.intent.action.PHONE_STATE, define following in the Manifest,
 [receiver android:name=".PhoneCall"]
        [intent-filter]
            [action android:name="android.intent.action.PHONE_STATE"/]  
        [/intent-filter]
[/receiver]


Handle Broadcast inside your Receiver...
Override onReceive() method and using Java Reflection try to get the Instance of one of hidden class of Android Telephony Framework- com.android.internal.telephony.ITelephony
ITelephony defines a set of useful methods to control the Call state, which are hidden from general Android API.
private void getTeleService() {
        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);
        }
}
Now, you can use telephonyService (which is an instance of com.android.internal.telephony.ITelephony) to "Accept"/"Reject" call and many other operations.
// Accept Call
telephonyService.answerRingingCall();
// Reject Call
telephonyService.endCall();


Sample Flow for Call Barring Application
1.     Define a set of numbers to be blocked-
String[] blockedNumbers = {" +919811284018 ", " +919811284012 "};
2.     Read incoming phone number
String incommingNumber;
@Override
public void onReceive(Context context, Intent intent) {
Bundle b = intent.getExtras();
incommingNumber = b.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
// Additional Step
// Check whether this number matches with your defined Block List
// If yes, Reject the Call
}
3.     Reject this Call
telephonyService.endCall();
Hope it helps! You can find the APK here...



Update: 

To mute an ongoing call, you can use com.android.internal.telephony.ITelephony.setMute(boolean ). You need to make sure the Call State is CALL_STATE_OFFHOOK

e.g.

continuing above code base-

if(tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK){

  // mute the call

  telephonyService.setMute(true);

}





Kindly note: I couldn't test properly the above code. Please let me know if the Mute functionality works.




56
comments:






Anonymous
said...
Hi there, How to mute an incoming call by clicking a mute button which i placed on screen when i get an incoming call? How to do it programatically? Please, if you can, write on your blog. Thanks, Mark


Prasanta
said...
Mark, i'll definitely give a try and let you know. -Prasanta




Anonymous
said...
Hi there, How to do outgoing call barring in android programatically? Please, if you can, write on your blog. Thanks, David




Anonymous
said...
Hi, With which version of OS have you tested the solution ? Anyone can please post any results ? Thanks, Karlos


Prasanta
said...
Hi Karlos, this sample is tested with Android 2.1. Are you facing problem ? Thanks, Prasanta


Derek
said...
Good stuff, I've been looking for info on how to do this through reflection. Have you played around with placing a call on hold?




Jaison
said...
Prasanta, am in error on that line. com.android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(tm); The Andriod not find the class ITelephony This class does not exist in the SDK 2.1!


Prasanta
said...
Jaison, you need to have an internal framework JAR file to run this- framework_intermediates-classes-full-debug.jar This JAR you will get when you do complete build of Android OS.


Sai Srinivas
said...
prasanta.., Can u tell me how to get jar u have specified to access , can u please help me ? com.android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(tm);


Prasanta
said...
You can get the JAR from here-FW_JAR You need to use this as Eclipse User Library.


Sai Srinivas
said...
hi Prasanta , I copied ITelephony.aidl from google open source , and i h got how to reject and accept calls . Thank u much for ur input . I need one more help i.e; can u please tell me how to send mms directly from code , i mean with no further user input. Thank u


wangpeng
said...
i cannot understand,i am beginer,could you give me this example thank you




Anonymous
said...
Hi, I having the same issue. Where did you put the file "ITelephony.aidl" ? how do i use the .jar file in eclipse ? When i go to Project/Properties/Libraries - I can see under android.jar/access rules: Forbidden: com/android/internal/** any idea ? Thanks,


Prasanta
said...
Hi, if you are using the attached JAR, you need to include that as User Library in Eclipse- Your Project Folder->Build Path->Add Libraraies...->User Library Hope it helps. -Prasanta




Anonymous
said...
Hi Pransanta, Thanks for your reply. Adding the jar caused to memory heap error. How can i add just the ITelephony.aidl


Prasanta
said...
To use ITelePhony.aidl - copy and past ITelePhony.aidl under com.android.internal.telephony package of your Eclipse Project - It should generate automatically ITelephony.java under gen folder. hope it helps.


surya
said...
hi prasanta, Conversion to Dalvik format failed: Unable to execute dex: null i got this problem after attach that JAR file. i clear my work space and rebuild it then also i got the same problem. can you please help me.


Prasanta
said...
You need to include the JAR as "User Library". In Eclipse- Your Project Folder->Build Path->Add Libraraies...->User Library


Jaison
said...
Prasanta thanks for replying. I did everything you said and bugs out, but when run the app, get the following exception: 10-16 23:26:08.375: VERBOSE/TEST CALL(1700): Get getTeleService... 10-16 23:26:08.405: WARN/System.err(1700): java.lang.NoSuchMethodException: getlTelephoney




prashantak
said...
Awesome post !! very informatory and helpful . Everything worked except telephonyService.setMute(true); . thanks a lot for this


Sai Srinivas
said...
Hai prasanta , i used ur code , to detect phone call, in ddms am getting , prasanta-phone call as tag 10-19 10:32:23.303: VERBOSE/Prasanta-PhoneCall(253): Incoming Call BroadCast received... 10-19 10:32:23.303: VERBOSE/Prasanta-PhoneCall(253): Intent: [android.intent.action.PHONE_STATE] 10-19 10:32:23.303: VERBOSE/Prasanta-PhoneCall(253): Bundle: Bundle[mParcelledData.dataSize=48] 10-19 10:32:23.303: VERBOSE/Prasanta-PhoneCall(253): Phone Number: null 10-19 10:32:23.303: VERBOSE/Prasanta-PhoneCall(253): Phone State: OFFHOOK 10-19 10:32:23.303: VERBOSE/Prasanta-PhoneCall(253): Get getTeleService... 10-19 10:32:23.303: VERBOSE/Prasanta-PhoneCall(253): answerCall... 10-19 10:32:23.303: VERBOSE/Prasanta-PhoneCall(253): silenceRinger... Over I want to change that ? i mean ddms message ? how can i change that in my code ? Thank u, Sai srinivas


Prasanta
said...
@ Jaison: pls try with the ITelePhony.aidl @ Srinivas: you need to write your own Application following the steps that i have explained.


Sai Srinivas
said...
But am not using single line of code of yours. still am getting debugging messages with name as tag. how to avoid it ?


Abhishek Akhani
said...
Boss.... Really very good stuff... its very helpul with my telephony app.... Keep it up...


Charlie
said...
Hi, great job...The telephonyService.answerRingingCall() works for me but not the telephonyService.endCall(). Is there any other permissions that need to be set or anything else that needs to be done? Thanks!


Prasanta
said...
Hi Charlie, thanks. I forgot to mention, for endCall() you need to add a User Permission- android.permission.CALL_PHONE hope it helps.




Anonymous
said...
hiiiiiii prasanta can u help me in a project of android app Tablet Application..... i have some problems in it can u help me in this concern whats ur id where i can mail u application apk file Regards Tushar SAHNI


Charlie
said...
Thanks Prasanta, the android.permission.CALL_PHONE worked for thetelephonyService.endCall(). Thanks again!!!




Anonymous
said...
Many thanks for amazing post. Keep up the good work...




Anonymous
said...
hi Prasanta, I am android beginner. I need exact usage of this ITelephony.aidl or ITelephony.jar. i totally confused. Awaiting for ur reply at earliest.




Anonymous
said...
Great post Prasanta ! It's working very well in my application. I've tested with the new Android 2.3 emulator and I get an security exception about android.permission.MODIFY_PHONE_STATE. Android is saying that this permission is missing for the current user or process. I've checked it my manifest and it's in there. Is it working for you with Android 2.3 ?


Prasanta
said...
Hi, I haven't yet tested this with Android 2.3 Tested versions 2.1, 2.2 BR, Prasanta


Enrique
said...
Great post Prasanta, quick question, this all runs fine in the emulators, however when I test them on the phone it only works after I restart the phone. Are you aware of this being a requirement? Thanks for the post again.




Anonymous
said...
Hi.. I have added the android.permission.CALL_PHONE. but its not working... Please help me...


Prasanta
said...
pls be more specific and let me know the actual problem you are facing.




Anonymous
said...
its not giving any error for "com.android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(tm);" but not implementing this line...


Prasanta
said...
pls check my implementation- http://prasanta-paul.blogspot.com/2010/12/phone-away-widget.html and make sure you are following everything correctly. hope it helps.




Anonymous
said...
Thanks prasanta....


uday_at
said...
Hi..ur post is great but am having an issue. As u said I saved my block numbers in an array and compared with number and used endcall method. But It doing nothing... Please help..


Prasanta
said...
Hi, you can look into the code base of http://prasanta-paul.blogspot.com/2010/12/phone-away-widget.html This might help you. Cheers, Prasanta


Bao Le Duc
said...
I tested on Android 2.1, 2.2, 2.3. Worked perfectly on the first two, but the last one. Any one had successfully tested on Android 2.3?