Phone call states listener with TelephoneyManager in Android

    Making a call is the key feature of a phone, not exclusion with Android phones. An actual calls many states and Android also provide a class named TelephonyManager which gave us information about the telephony services. This class provides various methods to access the telephony states and services. Now let’s see how to use telephony manager to know the incoming call states. Applications need to register a listener to receive notification on call states.

Initializing a TelephonyManager object

TelephonyManager instance needs to be instantiated through call  getSystemService(Context.TELEPHONY_SERVICE). getSystemService() method returns handle to system level service, by which we get access for handling telephony features of the device (here is TELEPHONY_SERVICE):
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    In order to listen call states changed, we must use PhoneStateListener and overriding onCallStateChanged() method.
    There are 3 phone call states that declared in TelephonyManager:
  • CALL_STATE_IDLE: No phone call exists or a phone call has just finished.
  • CALL_STATE_OFFHOOK:At least one call exists that is dialing, active, or on hold, and no calls are ringing or waiting.
  • CALL_STATE_RINGING: A new call arrived and is ringing or waiting. In the latter case, another call is already active.
    Attaching TelephonyManager with PhoneStateListener through call:
telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);

Full Service code

    In this project, I put all codes above in a subclass of Service, so the application can still work in background.
PhoneCallStatesService.java
package info.devexchanges.phonecallstates;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.widget.Toast;

public class PhoneCallStatesService extends Service {

    private TelephonyManager telephonyManager;
    private PhoneStateListener listener;
    private boolean isOnCall;

    public IBinder onBind(Intent arg0) {

        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        isOnCall = false;
        telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // Create a new PhoneStateListener
        listener = new PhoneStateListener() {
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                switch (state) {
                    case TelephonyManager.CALL_STATE_IDLE:
                        if (isOnCall) {
                            showToast("Call state: idle");
                            isOnCall = false;
                        }
                        break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        showToast("Call state: offhook");
                        isOnCall = true;
                        break;
                    case TelephonyManager.CALL_STATE_RINGING:
                        showToast("call state: ringing");
                        break;
                }
            }
        };

        // Register the listener with the telephony manager
        telephonyManager.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);

        return 1;
    }

    private void showToast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onDestroy() {
    }
}

Designing a simple Activity

Declaring a simple activity layout with 2 buttons (to start and stop service):
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="info.devexchanges.phonecallstates.MainActivity">

    <Button
        android:id="@+id/btn_start"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Start Service" />

    <Button
        android:id="@+id/btn_stop"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/btn_start"
        android:text="Stop Service" />
</RelativeLayout>
Start and stop our service when clicking corresponding button in Java code:
MainActivity.java
package info.devexchanges.phonecallstates;

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

        View btnStart = findViewById(R.id.btn_start);
        View btnStop = findViewById(R.id.btn_stop);

        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent i = new Intent(MainActivity.this, PhoneCallStatesService.class);
                startService(i);
            }
        });

        btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                stopService(new Intent(MainActivity.this, PhoneCallStatesService.class));
            }
        });
    }
}

Adding permission in AndroidManifest

You must add READ_PHONE_STATE permission and declaring your Service class in AndroidManifest.xml:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="info.devexchanges.phonecallstates">

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

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        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>

        <service android:name=".PhoneCallStatesService" />
    </application>

</manifest>

Running application

    When an incoming call arrived, phone is in ringing state:
    On phoning:
    When the call finished:

Conclusions

Now you have learned about handling phone call states in Android with a simple code. For more details, please reading TelephonyManager document to deep understanding the telephony service - the main feature of Android phone. Finally, you can get full project code from @Github.

Share


Previous post
« Prev Post
Next post
Next Post »