Amazon Gift Cards

Thursday, January 22, 2009

Get Phone State When Someone is calling using BroadcastReceiver Example

In this article we shall try to listen to the phone state when contacts are calling us.

First of all we need to set our Manifest file to listen to the Phone State, to do that we need to edit our it.
<application>
  .....
  <receiver android:name=".ServiceReceiver">
    <intent-filter>
      <action android:name="android.intent.action.PHONE_STATE" />
    </intent-filter>
</receiver>
</application>
<uses-permission android:name="android.permission.READ_PHONE_STATE">
</uses-permission>



Here you can see that we created a receiver xml node inside our application and have the java class ServiceReceiver to listen to it. What it would listen to is the PHONE_STATE and thus we need the permission of READ_PHONE_STATE. Then our ServiceReceiver Class would look like this.



public class ServiceReceiver extends BroadcastReceiver {
  @Override
  public void onReceive(Context context, Intent intent) {
    MyPhoneStateListener phoneListener=new MyPhoneStateListener();
    TelephonyManager telephony = (TelephonyManager) 
    context.getSystemService(Context.TELEPHONY_SERVICE);
    telephony.listen(phoneListener,PhoneStateListener.LISTEN_CALL_STATE);
  }
}


For the full class including the imports, please download the files below. In here we have another class called MyPhoneStateListener, which would be shown at the bottom. What this class would do is execute the phoneListener when the telephony.listen has received a LISTEN_CALL_STATE.


public class MyPhoneStateListener extends PhoneStateListener {
  public void onCallStateChanged(int state,String incomingNumber){
  switch(state){
    case TelephonyManager.CALL_STATE_IDLE:
      Log.d("DEBUG", "IDLE");
    break;
    case TelephonyManager.CALL_STATE_OFFHOOK:
      Log.d("DEBUG", "OFFHOOK");
    break;
    case TelephonyManager.CALL_STATE_RINGING:
      Log.d("DEBUG", "RINGING");
    break;
    }
  } 
}


What we have is a function called onCallStateChanged which would be fired when the LISTEN_CALL_STATE dispatches it. The states are either, ringing(CALL_STATE_RINGING), answers (CALL_STATE_OFFHOOK), or hang up/end call (CALL_STATE_IDLE). To see the logs in eclipse. Go to Window -> Show View -> Other -> Android -> LogCat

Hope it helps.


Sources
AndroidManifest.xml
ServiceReceiver.java
MyPhoneStateListener.java


References
BroadcastReceiver

Update History
   Jan 17, 2012 - Visual Update

26 comments:

Almond Mendoza said...

Almond,

Thank you very much for posting your code. I am sure the code is for a season developer. However, I am just learning the android environment. I wanted to get some input from you, it possible. I'm trying to run your code "Phone state listener" I have included a link
http://almondmendoza.com/2009/01/22/get-phone-state-when-someone-is-calling-using-broadcastreceiver-example/

I don't understand how to get it to run to put simply. I create the classes, but I don't understand how do I get it to run.

Any help would be appreciated

If you can't help, no worries, I just thought I'd ask.
Frank

admin said...

To explain further, from the xml there is receiver http://developer.android.com/guide/topics/manifest/receiver-element.html which would recieve an intent, which is filtered(PHONE_STATE), we then bind our receiver to the class of ServiceReceiver which would have a function called onReceive, then we listen to the the phone state. So putting them all into seperate class should work unless the current sdk had changed something, i havent tried out the code lately. Thanks

Michael said...

I use adb logcat on real device
I call android phone, the first time ringging, there one "RINGING" log messages
I hang up and call android again, this time there 2 "RINGING" log messages together
Everytime I call again, more RINGING messages appear.

It seems like a lot of instance have been created but didn't destroy.

androidev said...

How you used adb logcat on real device. Can you please explain?

admin said...

adb -d logcat

Fr said...

Hi Almond,

Thy for sharing your first steps in Android. I'm also a new developer and I have some questions after running your program.

Is it normal that the first time I run the program in the emulator, I have only one 'ringing' and the second time that i have multiples "ringing" in my logcat.
Are you sure we have to re-create the PhoneStateListener each time we receive an intent ? Or maybe it's only the emulator which is crappy ?

What I would like to know is : Is there only one ringing or multiples ? If i read the documentation, I'd say only one though but you know ... i'm not so sure : http://developer.android.com/intl/fr/reference/android/telephony/TelephonyManager.html#CALL_STATE_RINGING

Thanks for your awesome website and for the time you will spent for answering.

Unknown said...

To Fr and Michael: This example has a flaw in that it adds a listener for each broadcast intent. This is wrong.

You should register the listener in some context that fits (such as an activity or service) and keep the reference. If you want to use the above mentioned method (which you shouldn't), you must keep a reference to a listener and only add a reference if one isn't available.

Some intents, such as this listener, must be executed in code for the reason that you don't want 20 applications starting for no reason each time a call is received.

Unknown said...

Hi i m new n i want to know can i change state of phone....means i want to create a stoplist and if any call comes from stop list i want stop dat call
plz explain me or give some code i m new

cellurl said...

How do you make a user-type broadcast instead of a PHONE one.

I have a status-bar-app trying to talk to a widget.

Thanks Almond!

Unknown said...

Why are u using broadcast reciever , y not a service ... ??

monmonja said...

@anoop you listen to a broadcast (event) like someone is calling you or something, and then you could bind that receiver code into either an activity or a service. Its event base, therefore someone has to broadcast something (you can have your own event) before you could do something :)

Anonymous said...

I am sorry but you are confusing everyone here. You are mixing up two different ways of handling the PhoneStateChanges. If you use the BroadcastReceiver way, in the Intent is the new state information you need.
If you use the Listener you bind it to a running context. (Activity or Service).
The decision to use one or the other depends on what your app does. And how it does it.
If you are coding a game and want to capture a ringing state you use a listener bound to your Activity.
If you are trying to capture every call you use a BroadcastReceiver. Please do some research before posting misleading code.

monmonja said...

HI anonymous, thank you for your comment, when i was doing this i was implementing BroadcastReceiver via all calls and not by activity based, and i was still new to Android at that time and was willing to share what i have learned, like most tutorial online, if you want to get deep into what you want to know its not really ideal to base yourself on one post (this like) but do your own research. Thanks anyway

Lars Vogel said...

Thanks for this post. Even with this little mixture between Broadcast Receiver and Service it is useful. I also think it is ok to post something and get some feedback.

Perhaps you should adjust your example to use the intent data?

sudeep said...

Hello,this tutorial was good.I am doing an android app for my mini-project.I want to give some statistics about call.This activity should come up when a phone call is made or phone call is ended.Is this possible..?If so,can u briefly explain??I would be thankful to you if you help me out.

Android Phone Tips said...

The most difficult thing in my opinion the most important and also for use in smartphones android is to create a shortcut, and this tutorial is fitted with my expectations.

JeffG said...

Your example is not right - you are mixing up the BroadcastReceiver and the PhoneStateListener.

You can declare a PhoneStateListener in a normal activity (or a service) and then override the onCallStateChanged method. You then process changes in that method - no need for a BroadcastReceiver.

Or you can use a BroadcastReceiver to listen for changes and process them yourself in the receiver.

You shouldn't use both of these methods together.

You are adding a new listener to the telephony service every time the phone state changes. That's why Michael is getting multiple logs of "Ringing" - you must only add that listener once (in an onCreate method)

Sudeep said...

Thanks man...Its really nice especially for a beginner like me !!!

aftab said...

hi I have a question related to Phone call state,How i can detect pro-grammatically if a phone accept(answer) or reject a call ?

VVS said...

Could you help me, please!

How to show toast from listener in this example?

Forexample:
protected Context context;

public void onCallStateChanged(int state,String incomingNumber){



switch(state){
case TelephonyManager.CALL_STATE_IDLE:
Log.d("DEBUG", "IDLE");
Toast.makeText(context, "IDLE", Toast.LENGTH_LONG).show();

break;

Does'not work.

Imran Khan said...

Thank you for posting this valuable code.I am thinking about an android application which play some audio when a user put his/her call on hold.Any idea how to get "HOLD" state so that we can put our code during that state and play audio.Thanks in advance.

Anonymous said...

Simple and very useful to understand.... Thanks.
Kumar

Deepak said...

Thnx for your tutorial, I am new in the Android and i want to change the default call incoming screen.So i launch an activity from the your broadcast receiver in the ringing mode but it is giving some problem.

rohit said...

Hi Almond,
Thank you very much for posting code.I am new to the android . I didn't find the source code Because when i click the below links, That links showing different path can any one help me .

Anonymous said...

How to detect phone has been connected or not?

adynis said...

I had the same problem as Michael, and finally I think I understood what Anonymous said.

It seems that the solution for the problem (for multiple instantiations and multiple "answers" being seen in LogCat) is this:

public class ServiceReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {


String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
if (TelephonyManager.EXTRA_STATE_OFFHOOK.equals(state))
{
Log.d("DEBUG", "Phone state: OFFHOOK");
}
else if (TelephonyManager.EXTRA_STATE_IDLE.equals(state))
{
Log.d("DEBUG", "Phone state: IDLE");
}
else if (TelephonyManager.EXTRA_STATE_RINGING.equals(state))
{
Log.d("DEBUG", "Phone state: RINGING");
}
else
{
//I hope this will never happen :)
Log.d("DEBUG", "Unknown&unwanted phone state"+state.toString());
}
}
}