Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
Twitter logo OReilly Book Cover Art
HomeF.A.Q.
Community
Writing Recipes
Login
Do something when the phone rings
Contributed by Johan Pelgrim 2011-03-27 03:34:47 (updated 2011-09-11 08:26:29)
In Published Edition? Yes
Minimum Version 1.5
2
Votes
Problem

You want to act on an incoming phone call and do something with the incoming number.

Solution

This can be achieved by implementing a Broadcast receiver and listening for a TelephonyManager.ACTION_PHONE_STATE_CHANGED action.

Discussion

If you want to do something when the phone rings you have to implement a broadcast receiver which listens for the TelephonyManager.ACTION_PHONE_STATE_CHANGED intent action. This is a broadcast intent action indicating that the call state (cellular) on the device has changed.

1. Create a class IncomingCallInterceptor which extends BroadcastReceiver.

2. Override the onReceive method to handle incoming broadcast messages.

3. The EXTRA_STATE intent extra in this case indicates the new call state.

4. If (and only if) the new state is RINGING, a second intent extra EXTRA_INCOMING_NUMBER provides the incoming phone number as a String.

5. We extract the number information from the EXTRA_INCOMING_NUMBER intent extra.

Note: Additionally you can act on a state change to OFFHOOK or IDLE when the user picks up the phone or ends/rejects the phone call respectively.

package nl.codestone.cookbook.incomingcallinterceptor;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class IncomingCallInterceptor extends BroadcastReceiver {                                    // 1

    @Override
    public void onReceive(Context context, Intent intent) {                                         // 2
        String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);                         // 3
        String msg = "Phone state changed to " + state;
        
        if (TelephonyManager.EXTRA_STATE_RINGING.equals(state)) {                                   // 4
            String incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);  // 5
            msg += ". Incoming number is " + incomingNumber;
            
            // TODO This would be a good place to "Do something when the phone rings" ;-)
            
        }
        
        Toast.makeText(context, msg, Toast.LENGTH_LONG).show();

    }

}

6. We have to register our IncomingCallInterceptor as a <receiver> within the <application> element in the AndroidManifest.xml file.

7. We register an <intent-filter> ...

8. and an <action value which registers our receiver to listen for TelephonyManager.ACTION_PHONE_STATE_CHANGED broadcast messages.

9. Finally we have to register a <uses-permission> so we are allowed to listen to phone state changes.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="nl.codestone.cookbook.incomingcallinterceptor"
    android:versionCode="1"
    android:versionName="1.0">
    <uses-sdk android:minSdkVersion="3" />

    <application android:icon="@drawable/icon" android:label="Incoming Call Interceptor">

        <receiver android:name="IncomingCallInterceptor">                     // 6
            <intent-filter>                                                   // 7
                 <action android:name="android.intent.action.PHONE_STATE"/>   // 8
            </intent-filter>
        </receiver>

    </application>

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

If all is well you should see something like this when the phone rings:

What happens if two receivers listen for phone state changes?

In general, a broadcast message is just that, a message which is sent out to many receivers at the same time. This is the case for normal broadcast messages which is used to send out the ACTION_PHONE_STATE_CHANGED intent as well. All receivers of the broadcast are run in an undefined order, often at the same time and for that reason order is not applicable.

In other cases the system sends out ordered broadcast which is described in more detail in the Recipe Process outgoing calls.

Final notes

When your BroadcastReceiver does not finish within 10 seconds the Android framework will show the infamous Application Not Responding (ANR) dialog, giving your users the possibility to kill your program. If you need to do some processing which takes longer than 10 seconds implement a Service and call the service method.

It is also not advised to start an activity from a BroadcastReceiver, as it will spawn a new screen that will steal focus from whatever application the user is currently has running. If your application has something to show the user in response to an Intent broadcast, it should do so using the Notification Manager.

Code Repository Subdirectory The code example is in the "TelephonyManager" subdirectory of our GitHub repo, and can be viewed at https://github.com/androidcook/Android-Cookbook-Examples/tree/master/TelephonyManager You can also download the complete collection of examples at https://github.com/androidcook/Android-Cookbook-Examples/.
Comments (3)
Leave a comment
Edit History (25)
jpelgrim said 2011-05-05 01:15:57 Hi Todd, Sorry for the late reply. I received your comments via e-mail, but didn't see them on the website (they had to be moderator approved by Ian), so I couldn't respond earlier. Thanks for the compliments and kudos for yourself for finding a solution for your technical problem ;-) Sometimes a good old restart or "Project... clean" will magically fix things for you. Which sounds a bit scary in my opinion, but still... problem solved (by you!) Cheers, Johan
todd.deland said 2011-04-28 11:40:10 Got it working, not sure what I did, but works great now. My logcat had errors about "bad process" so I ended up restarting Eclipse and it went away. Thanks for the great tutorial!
todd.deland said 2011-04-28 10:52:50 Great tutorial! I copy/pasted and I can't get it to work :( It installs fine, and even trying to debug no break points hit (but will they in a BroadcastReceiver?) Any tips?