Monday, June 2, 2014

How to create PhoneStateReceiver get CLI and call events

During first 5 years of my career I luckily worked at software houses that created computer telephony related software, I had used Microsoft TAPI and Dialogic APIs to create IVR and Operator Console and Call Recorder software. When I first started Android programming in 2010, I was very curious about phone states and CLI. 





I later figured it out and came to know that a BroadcastReceiver will be the right thing to use in
this case. BroadcastReceiver is a specially designed component offered by Android OS, and
it is used to handle various broadcasts sent by apps or OS components.
The broadcasts related to telephone call states are sent by TelephonyManager which is a
component of Android OS.
The phone state receiver given below can be used in scenarios like call blocking, call tracking,
and sending information to http or cloud based servers.
This salient features of my phone state receiver are given below
  1. Get the CLI from an incoming call
  2. Get the dialled number from an outgoing call
  3. When an inbound call is connected, get informed
  4. When a call is disconnected, get notified









public class PhoneStateReceiver extends BroadcastReceiver {
public enum CallType {INCOMING, OUTGOING, NA}
private static String lastNumber = "";
private static int lastCallState = 0;
/**
* This code is provided by Naeem Akram, 
* without any warranty guarantee or liability
* This code is meant for the good of developer community
* Please don't delete this comment when reusing 
* this code, and if possible give proper
* credit to the developer.
* In case you want to hire Naeem, go to following URL:
* https://www.odesk.com/users/~012d73aa92fad47188
*/
@Override
public void onReceive(final Context context, Intent intent) {

// Check phone state
String strPhoneState = "", strNumber = "";
CallType ctVal = CallType.NA;
int callState = 0;  
TelephonyManager tm = null;

try{
tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
strPhoneState = intent
.getStringExtra(TelephonyManager.EXTRA_STATE);
callState = tm.getCallState();

Log.d(Keys.LOGTAG, "CS: " + callState + 
" - Last CS: " + lastCallState +" - Phone State: " + strPhoneState);

if(strPhoneState != null)
{
if(!strPhoneState.equals(TelephonyManager.EXTRA_STATE_IDLE))
// don't post here if phone state is idle, it will get posted later.
{
postPhoneStateEvent(context, strPhoneState);
}
}else{
strPhoneState = "";
}

Log.d(Keys.LOGTAG, "INF: Broadcast received; " + strPhoneState);

if(callState == TelephonyManager.CALL_STATE_IDLE){
// the call just ended, it might be incoming or outgoing
Log.d(Keys.LOGTAG, "CALL STATE: " + callState);    
if(intent.hasExtra(TelephonyManager.EXTRA_INCOMING_NUMBER))
{// this is an incoming call
ctVal = CallType.INCOMING;
strNumber = intent.getStringExtra(
 TelephonyManager.EXTRA_INCOMING_NUMBER).trim();
}
else if(intent.hasExtra(Intent.EXTRA_PHONE_NUMBER))
{// this is an outgoing call
ctVal = CallType.OUTGOING;
strNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
}
else if(lastNumber.length() > 0)
{
ctVal = CallType.INCOMING;
strNumber = lastNumber;
lastNumber = "";
}

if(strPhoneState != null){
// maybe save phone state to DB, or send it to a server 
postPhoneStateEvent(context, strPhoneState);
}

if(ctVal == CallType.OUTGOING){
// maybe save the number of called party, 
// or send the info to a server over http
postCLIEvent(context, ctVal, strNumber);
lastNumber = "";
strNumber = "";
}

if(lastCallState == CALL_STATE_CONNECTED || 
 lastCallState == TelephonyManager.CALL_STATE_OFFHOOK){
 postPhoneStateEvent(context, "DISCONNECTED");
}
if(lastCallState == TelephonyManager.CALL_STATE_RINGING){
postPhoneStateEvent(context, "MISSED");
}
}// if callState == CALL_STATE_IDLE
else if(
callState == TelephonyManager.CALL_STATE_OFFHOOK)
{// until so far we can only figure out 
// when an incoming call gets connected
if(lastCallState == TelephonyManager.CALL_STATE_RINGING){
// offhook right after ringing means we 
// attended the call
Log.d(Keys.LOGTAG, "INCOMING CALL CONNECTED");
postPhoneStateEvent(context, "CONNECTED " + lastNumber);
// tell a server that a call is
// connected over http or socket
}
}
else{
// callstate != 0 zero means call state is idle
if(intent.hasExtra
(TelephonyManager.EXTRA_INCOMING_NUMBER))
{// this is an incoming call     
lastNumber = intent.getStringExtra
 (TelephonyManager.EXTRA_INCOMING_NUMBER).trim();
Log.d(Keys.LOGTAG, "Ringing INCOMING event.");
postPhoneStateEvent(context, CallType.INCOMING + " : " + lastNumber);
}
else if(intent.hasExtra
(Intent.EXTRA_PHONE_NUMBER)){
// this is an outgoing call
lastNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
postCLIEvent(context, CallType.OUTGOING, lastNumber);
}    
Log.d(Keys.LOGTAG, "Last Number: " + lastNumber);
}
}catch(Exception excp){
excp.printStackTrace();
} 
lastCallState = callState;
// local callState is OFFHOOK our custom 
CONNECTED val gets messed
}
private void postPhoneStateEvent(final Context context, 
 String strPhoneState) {
if(strPhoneState != null){
// POST THE PHONE STATE SOMEWHERE SOMEHOW
}
}
private void postCLIEvent(Context _context, 
 CallType _callType, String _cli){
// POST THE CLI SOMEWHERE SOMEHOW
}
}

You will need following permissions in order to sue the phone state receiver
:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />

We must add every app component to our Manifest.xml file, and our phone state broadcast receiver will be added like this:

<receiver
 android:name="com.usra.ca.PhoneStateReceiver"
    android:enabled="true" >
    <intent-filter android:priority="1" >
    <action android:name="android.intent.action.PHONE_STATE"
    <action android:name="android.intent.action.NEW_OUTGOING_CALL"/>
    <action android:name="android.intent.action.ANSWER"/>
    </intent-filter>
</receiver>

Android has got only three phone states
  • IDLE
  • RINGING
  • OFFHOOK

Please feel free to comment on the post, and share ideas in general.

I'm working as a full time freelance programmer through ODesk.com, I have a strong profile over there. Feel free to ping me if you need an Android app. Elance widget is given on top right of the page, for ODesk follow the link given below:


https://www.odesk.com/users/~012d73aa92fad47188

89 comments:

  1. Thanks for this code , it works fine.. But How can i detect radio link failure during comm unication , i mean how to detect call drop event in my app?

    ReplyDelete
  2. You are welcome, I am not sure how that will happen. If the call is fully disconnected/dropped then an IDLE event will be shown in phone state receiver. If you will be keeping track of previous phone states, you can check whether previous phone state was OFFHOOK or RINGING in which cases you will know that the call was dropped after either an outgoing call or on incoming call.
    It gets complicated I know, but that's the way it is... Google does not want people to mess with its operating system :)

    ReplyDelete
  3. Hey Naeem, the statement "Log.d(Keys.LOGTAG, "Ringing INCOMING event.");" shows an error: "cannot resolve symbol Keys". Is it a local variable you created?

    ReplyDelete
  4. "LOGTAG" is a public constant defined in class "Keys". I try to use a separate class for frequently used strings and variables,

    ReplyDelete
    Replies
    1. I'm still learning and get "Multiple markers at this line
      - Log cannot be resolved
      - Keys cannot be resolved to a
      variable"
      How do I define Log, Keys and LOGTAG in this program?

      Delete
    2. I also get "Executors cannot be resolved" and "Executor cannot be resolved
      to a type" - how do I get this working?

      Delete
    3. I found "import android.util.Log;" solved the Log error

      Delete
  5. Keys is a separate class it contains a static final string named LOGTAG, you can set value to anything you like.
    You will need to import package "java.util.concurrent.Executors" in order to resolve the executors error.

    ReplyDelete
  6. คาสิโนออนไลน์ The best online casino web site with every bet to meet all the needs of the gambler completely

    ReplyDelete
  7. NAZA The best online gambling sites With every bet To meet all needs of the gambler with a complete

    ReplyDelete
  8. NAZA We are the service provider Online casinos With every bet A complete answer

    ReplyDelete
  9. แทงบอลออนไลน์ The best online football betting website and has a form of football betting

    ReplyDelete
  10. NAZA SLOT The classic gambling roulette can be played at our betting website.

    ReplyDelete
  11. คาสิโนออนไลน์ An online gambling site that offers all forms of gambling. Let the gambler experience

    ReplyDelete
  12. NAZA Online gambling service providers That answers all needs Excellent gambler 24 hours

    ReplyDelete
  13. ปั่นแปะออนไลน์An online gambling site that offers all forms of gambling. Let the gambler experience

    ReplyDelete
  14. สล็อต 55 casino website that have all the betting in it to answer all the needed for the gambler

    ReplyDelete
  15. เว็บหวยออนไลน์ The most popular Online betting sites 24 hours a day, no holidays.

    ReplyDelete
  16. ราคาบอลไหล good quality websites, 24 hours service, can be played easily on your smartphone

    ReplyDelete
  17. เว็บ 123One way to help you make money right now

    ReplyDelete
  18. เว็บ 123 A collection of popular casino games

    ReplyDelete
  19. MariaOne way to help you make money right now

    ReplyDelete
  20. เว็บ 123 online gambling service provider that meets international standards and meets all gambler needs.

    ReplyDelete
  21. earn money in your pocket at the casino.เว็บคาสิโน naza55

    ReplyDelete
  22. ไฮโล naza55 The casino site that offers all the bets, meets every need for any gambler.

    ReplyDelete
  23. ราคาบอลไหลWe have top casinos from all over the world gathered here in one place. by..,min

    ReplyDelete
  24. เว็บ88 Web betting on high returns are the most popular now.

    ReplyDelete
  25. เล่นยี่กี casino website that have all the betting in it to answer all the needed for the gambler

    ReplyDelete
  26. Link to get wealth What do I need to prepare เว็บ 123

    ReplyDelete
  27. เว็บพนันออนไลน์May 12, 2022 at 2:13 PM

    เว็บพนันออนไลน์ The most trending online gambling website on the internet. Access many services easily via smartphone. Our website is 100% safe.

    ReplyDelete
  28. วิธีเล่นหวยใต้ดิน naza can be played online betting, slot or various gambling games with the camp you like and earn money easily via any smartphone.

    ReplyDelete
  29. ราคาบอล he most interesting thing in the world is online right now

    ReplyDelete
  30. เว็บคาสิโน naza55 Online gambling websites complete in terms of casino games in particular

    ReplyDelete
  31. Comprehensive online gambling site in the matter of casino games เว็บคาสิโน

    ReplyDelete
  32. The best casino in Thailand make good money 123 คาสิโน

    ReplyDelete
  33. A complete online gambling website in terms of casino games in particular ไฮโล naza55

    ReplyDelete
  34. วิธีเล่นหวย naza55 offers a wide variety of promotions with the benefit of participating in bets.

    ReplyDelete
  35. ap123 Football price online Online betting odds

    ReplyDelete
  36. There are many games to play. The website is easy to use, good promotion, fast deposit, withdraw within 5 seconds, admin responds quickly.เว็บคาสิโนออนไลน์ 123dd

    ReplyDelete
  37. allbet Is an online betting game with a lot of service users as the top

    ReplyDelete
  38. Want to have money to spend? Come here. web Dm 123 slot

    ReplyDelete
  39. Forget the pictures of the old casinos. The present may change a lot.
    Because the casino that we know will come in a modern style and much more comfortable than before.ราคาบอลไหล

    ReplyDelete
  40. I find luck quite predictable. If you want more luck, more opportunities, more enthusiasm. เว็บคาสิโน naza55

    ReplyDelete
  41. The most popular Online betting sites 24 hours a day, no holidays 123 slot

    ReplyDelete
  42. คาสิโน123Online football training from big websites, pay for real, not pay for testing

    ReplyDelete
  43. คาสิโนออนไลน์ Enjoy and Play games that will earn your Money here Let get it

    ReplyDelete
  44. A complete online gambling website in terms of casino games in particular สล็อต55 naza

    ReplyDelete
  45. แฮนดิแคป Online gambling websites, we have a system to recommend friends that can easily make money. For you, all customers, easy to use and easy to make a casino.
    5 is famous for most people because can play when you free time. can play or home, office or drive you can play all day all night.

    ReplyDelete
  46. เว็บ 168 this site can help you find a lot of money

    ReplyDelete
  47. in our rating there are casino games you can play online with confidence on any site you like.เว็บคาสิโน naza55

    ReplyDelete
  48. many online soccer betting centers are avaliable on here. Bring it on เว็บ 123

    ReplyDelete
  49. ราคาแฮนดิแคป I find luck quite predictable. If you want more luck, more opportunities, more enthusiasm.

    ReplyDelete
  50. There are many games to play. The website is easy to use, good promotion, fast deposit, withdraw within 5 seconds, admin responds quickly. 123 slot

    ReplyDelete

  51. ยอดเทิร์นโอเวอร์
    Best friend referral system "Link to get wealth" after all customers apply for membership.

    ReplyDelete
  52. สล็อต123 casino website that have all the betting in it to answer all the needed for the gambler

    ReplyDelete
  53. Want to have money to spend? Come here. แทงบอล 123 123dd

    ReplyDelete

Feel free to talk back...