Android PhoneStateListener/ Phone Call Broadcast Receiver Tutorial

This tutorial explains how to implement Phone call state listener to detect Incoming or Outgoing or Missed Call State by using Broadcast Receiver for any Android device. This tutorial updated to support all Android API.

Introduction

Don't Miss

Broadcast Receiver is an Android component which allows us to register for system or application events. All registered receivers for an event are notified by the Android run time once this event happens. Broadcast receivers help us to receive messages (intent, events etc.) from system it self or other applications.

In this tutorial, we will register a Call Listener receiver by using a broadcast receiver. It will notify while changes of phone state. With the help of this tutorial, we will detecting whether our phone is ringing state, receiving state(off hook) or idle state.

Create a new project

Don't Miss

To implement Phone Call State Listner, we are going to create a new android project. Go to File ⇒ New ⇒ New Projects in Android studio.

Add Permissions

To read phone call state(Incoming or Outgoing), we need to add permissions in the AndroidManifest.xml file.

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

Register Broadcast Receiver

To register a broadcast receiver, we need to create a java class named as CallReceiver. To receive Phone call state and Outgoing call, we would have to define android.intent.action.PHONE_STATE and android.intent.action.NEW_OUTGOING_CALL as an action. Add the below code between tag in the AndroidManifest.xml file.

<receiver android:name=".CallReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>

AndroidManifest.xml file look like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="in.studytutorial.phonestatelistner">
	<uses-permission android:name="android.permission.READ_PHONE_STATE" />
	<uses-permission android:name="android.permission.READ_CALL_LOG" />

	<application
		android:allowBackup="true"
		android:icon="@mipmap/ic_launcher"
		android:label="@string/app_name"
		android:roundIcon="@mipmap/ic_launcher_round"
		android:supportsRtl="true"
		android:theme="@style/AppTheme">
		<activity android:name=".MainActivity">
		        <intent-filter>
			<action android:name="android.intent.action.MAIN" />

			<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<receiver android:name=".CallReceiver" >
		<intent-filter>
		<action android:name="android.intent.action.PHONE_STATE" />
		</intent-filter>
		</receiver>
        </application>

</manifest>

Lets Create Phone State Listener

To Listen Phone call state, create a java class file named as MyPhoneStateListener also created onCallStateChanged() method in this file. In this method, we will pass Context, State and Phone Number as a Parameter. We will cover all state changes in this method.
import android.content.Context;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;

import java.util.Date;

public class MyPhoneStateListener extends PhoneStateListener {

private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private static Date callStartTime;
private static boolean isIncoming;

public void onCallStateChanged(Context context, int state, String phoneNumber){
if(lastState == state){
//No change, debounce extras
return;
}

System.out.println("Number inside onCallStateChange : "  + phoneNumber);
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
callStartTime = new Date();

Toast.makeText(context, "Incoming Call Ringing " + phoneNumber, Toast.LENGTH_SHORT).show();
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
if(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
callStartTime = new Date();
Toast.makeText(context, "Outgoing Call Started " + phoneNumber, Toast.LENGTH_SHORT).show();
}
break;

case TelephonyManager.CALL_STATE_IDLE:
//Went to idle-  this is the end of a call.  What type depends on previous state(s)
if(lastState == TelephonyManager.CALL_STATE_RINGING){
//Ring but no pickup-  a miss
Toast.makeText(context, "Ringing but no pickup" + phoneNumber + " Call time " + callStartTime +" Date " + new Date() , Toast.LENGTH_SHORT).show();
}
else if(isIncoming){

Toast.makeText(context, "Incoming " + phoneNumber + " Call time " + callStartTime  , Toast.LENGTH_SHORT).show();
}
else{

Toast.makeText(context, "outgoing " + phoneNumber + " Call time " + callStartTime +" Date " + new Date() , Toast.LENGTH_SHORT).show();

}

break;
}
lastState = state;
}
}

Lets extend Broadcast Receiver

Now, we need to extend BroadcastReceiver class. In this class, we must override onReceive(Context context, Intent intent) method because it’s an abstract method of BroadcastReceiver class. The onReceive() method receives each message as an Intent object parameter. We have already declared Broadcast Receiver & registered it in AndroidManifest.xml.

Listen Phone Call State

We will get two intents in the onReceive() method. To get Outgoing intent, we need to use android.intent.action.NEW_OUTGOING_CALL and to detect our phone call states using TelephonyManager.EXTRA_STATE. It indicates the current call state and it will return phone state as a String Object. To get different phone call states, we have to implement code like below-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class CallReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
//Log.w("intent " , intent.getAction().toString());
TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
MyPhoneStateListener customPhoneListener = new MyPhoneStateListener();

telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);

Bundle bundle = intent.getExtras();
String phone_number = bundle.getString("incoming_number");

String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
// String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
state = TelephonyManager.CALL_STATE_IDLE;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
state = TelephonyManager.CALL_STATE_OFFHOOK;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
state = TelephonyManager.CALL_STATE_RINGING;
}
if (phone_number == null || "".equals(phone_number)) {
return;
}
customPhoneListener.onCallStateChanged(context, state, phone_number);
Toast.makeText(context, "Phone Number " + phone_number , Toast.LENGTH_SHORT).show();
}
}
   

Main Activity

We need to ask READ_PHONE_STATE & READ_CALL_LOG permission on runtime in the MainActivity file
public class MainActivity extends AppCompatActivity {

public static final int REQUEST_ID_MULTIPLE_PERMISSIONS = 1;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkAndRequestPermissions();
}

private  boolean checkAndRequestPermissions() {
int readPhoneState = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE);
int read_call_log = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CALL_LOG);
List listPermissionsNeeded = new ArrayList<>();
if (readPhoneState != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_PHONE_STATE);
}

if (read_call_log != PackageManager.PERMISSION_GRANTED) {
listPermissionsNeeded.add(Manifest.permission.READ_CALL_LOG);
}

if (!listPermissionsNeeded.isEmpty()) {
ActivityCompat.requestPermissions(this,
listPermissionsNeeded.toArray(new String[listPermissionsNeeded.size()]),
REQUEST_ID_MULTIPLE_PERMISSIONS);
return false;
}
return true;
}
}
 
outgoing_call_listenerOutgoing_call_endincoming_call_listener

21 COMMENTS

  1. will this code work when the application is completly closed . will i be able to get phone state and number even after application is closed/killed?

  2. how can I show an alert with a close button showing data related to the number from my sqlite database please, i’m trying to avoid adding contacts to the phone to avoid user input or changes.
    thanks for any help

  3. Helo sir, it is working fine but it is not showing incoming number.Please tell how to get incoming number.
    Thanks.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

564FansLike

Recent Posts

How to create ListView using Adapter in Android Tutorial

In this tutorial, we're explaining the way to create ListView in Android Application. What is Android ListView? Android ListView is a view which teams a number...

Basic Geometry Math Formula List

Geometry is a department of mathematics that offers with shape, dimension, relative position of figures, and the properties of space. It emerges independently in variety of early cultures as a practical approach of dealing with lengths, area and volumes.

How to Sign in with Google in Android Tutorial

In this tutorial, we are going to explain how to sign in with Google in Android Application. Many apps want to...

Related Articles

How to create ListView using Adapter in Android Tutorial

In this tutorial, we're explaining the way to create ListView in Android Application. What is Android ListView? Android ListView is a view which teams a number...

Basic Geometry Math Formula List

Geometry is a department of mathematics that offers with shape, dimension, relative position of figures, and the properties of space. It emerges independently in variety of early cultures as a practical approach of dealing with lengths, area and volumes.

How to Sign in with Google in Android Tutorial

In this tutorial, we are going to explain how to sign in with Google in Android Application. Many apps want to...