How to listen for Phone Events in Android

If we want our application to deal with telephony services on the device then we can do so with the help android.telephony package. In this article, I will show you how to listen for different phone events and take action based upon them. In other words we can make our application react to any phone event such as when the phone rings, signal strength changes, etc. Also, the access to this telephony information of device is permission protected and our application should have appropriate permissions in order to receive device call change updates. So, let's get started!

In order to demonstrate how to listen to phone events, we will add a textview to our application. Whenever we receive any update related to device call state we will add the information to this textview and display it to the user. Create a new Android project in Eclipse with the following properties:

  • Project Name – Phone Events
  • Name of the Application – Phone Events
  • Package name – com.botskool.PhoneEvents
  • Activity Name – PhoneEventsActivity 

Open the file named AndroidManifest.xml and add the following tag, as a child node of mainfest tag:

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

This tag specifies that our application needs permission to read phone state. This permission is requested from user during installation of the application. So the complete code of AndroidManifest.xml file will be:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.botskool.PhoneEvents"
      android:versionCode="1"
      android:versionName="1.0">
    <uses-sdk android:minSdkVersion="10" />
	<uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".PhoneEventsActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
</manifest>

Next, open the file named res/layout/main.xml and add the following code to it:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/call_state_view"
    />
</LinearLayout>

We are using linear layout for our application and we have defined a textview inside it. We will display phone state information inside this textview.

Now, add the following code to PhoneEventsActivity.java:

package com.botskool.PhoneEvents;

import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.TextView;

public class PhoneEventsActivity extends Activity {
    /** Called when the activity is first created. */
	@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        final TextView textView = (TextView) findViewById(R.id.call_state_view);
        final TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        PhoneStateListener phoneStateListener = new PhoneStateListener() {
        	@Override
        	public void onCallStateChanged(int state, String number) {
        		String currentPhoneState = null;
        		switch (state) {
        			case TelephonyManager.CALL_STATE_RINGING:
        				currentPhoneState = "Device is ringing. Call from " + number + ".\n\n";
        				break;
        			case TelephonyManager.CALL_STATE_OFFHOOK:
        				currentPhoneState = "Device call state is currently Off Hook.\n\n";
        				break;
        			case TelephonyManager.CALL_STATE_IDLE:
        				currentPhoneState = "Device call state is currently Idle.\n\n";
        				break;
        		}
        		textView.append(currentPhoneState);
        	}
        };
        telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
    }
}

Finally, compile the program and launch the Android application. Initially, you will see the device call state as idle as shown below:

Initial Phone State

Now, lets try calling the emaluator by going to Emaluator Control tab in DDMS perspective of the Eclipse and see how our Android application behaves:

Making a phone call to emaluator

As soon as you will call you will see the ringing screen on the emaluator as shown below:

Incoming call to the emaluator

After you hangup, the Android application will show the information pertaining to all device call state changes. A sample screenshot is show below:

Phone Events list after call

You can extend this idea further and take more definitive actions based upon state change. Here, we have used TelephonyManager and PhoneStateListener classes.

The getSystemService() method returns a reference to the telephony service which is a system level service. 

Next, we instantiate an object of the PhoneStateListener class. Here, we define our actions corresponding to various phone events in the onCallStateChanged() method.

The telephonyManager.listen() method has been used to register the phone listener with the system. We pass the device we want to listen to as the parameter of this method.  The device has been specified in the form of PhoneStateListener constant LISTEN_CALL_STATE. Whenever there is any change in the phone call state the onCallStateChange() method gets fired and a corresponding message is appended to the textview as a result.