Android Snippet

When you need a real-time response to a Missed-call OTP, you can set the listener on your Android code. The code format is available on Kotlin and Java.

Kotlin

The files consist of AndroidManifest.xml, Helper.kt, MainActivity.kt and PhoneStateReceiver.kt

AndroidManifest.xml

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

Helper.kt

private fun isAirplaneModeOn(): Boolean {
    return Settings.System.getInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0) != 0
}

MainActivity.kt

import android.Manifest
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat


class MainActivity : AppCompatActivity() {
    var key: String? = null //OTP
    val digits: Int = 4 // 4 or 6 digits to pass verification

    private val phoneStateReceiver = PhoneStateReceiver()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        //check READ_PHONE_STATE and READ_CALL_LOG permission
        val permissions: MutableList = mutableListOf()
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_PHONE_STATE
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            permissions.add(Manifest.permission.READ_PHONE_STATE)
        }
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_CALL_LOG
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            permissions.add((Manifest.permission.READ_CALL_LOG))
        }

        if (permissions.isEmpty()) {
            //register receivers if all permissions have been granted
            registerReceiver(phoneStateReceiver, IntentFilter("android.intent.action.PHONE_STATE"))
            registerReceiver(keyReceiver, IntentFilter(PhoneStateReceiver.KEY_RECEIVER))
        } else {
            //request permission(s) that has not been granted
            ActivityCompat.requestPermissions(this, permissions.toTypedArray(), 100)
        }
    }

    //receiver to get the key
    private var keyReceiver: BroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent) {
            val phoneNumber = intent.extras?.getString(PhoneStateReceiver.PHONE_NUMBER)
            key = phoneNumber?.takeLast(digits)
        }
    }


    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array,
        grantResults: IntArray
    ) {
        var allGranted = true
        if (requestCode == 100) {
            grantResults.forEach {
                if (it != PackageManager.PERMISSION_GRANTED) allGranted = false
            }
            if (allGranted) {
                registerReceiver(
                    phoneStateReceiver,
                    IntentFilter("android.intent.action.PHONE_STATE")
                )
            }
        }
    }

    override fun onDestroy() {
        super.onDestroy()
        //unregister receivers
        unregisterReceiver(keyReceiver)
        unregisterReceiver(phoneStateReceiver)
    }
}

PhoneStateReceiver.kt

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.telephony.PhoneStateListener
import android.telephony.TelephonyManager


class PhoneStateReceiver : BroadcastReceiver() {
    companion object {
        var phoneStateListener: CustomPhoneStateListener? = null
        const val PHONE_NUMBER = "PHONE_NUMBER"
        const val KEY_RECEIVER = "KeyReceiver"
    }

    override fun onReceive(context: Context, intent: Intent) {
        val telephonyManager =
            context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager

        //onReceive will called multiple time, so we have to make sure the listener is only made once
        if (phoneStateListener == null) {
            phoneStateListener = CustomPhoneStateListener(context)
            telephonyManager.listen(
                phoneStateListener,
                PhoneStateListener.LISTEN_CALL_STATE
            )
        }
    }


    inner class CustomPhoneStateListener(private val context: Context) : PhoneStateListener() {
        private var incomingNumber: String = ""

        override fun onCallStateChanged(state: Int, phoneNumber: String) {
            if (phoneNumber.isNotEmpty()) incomingNumber = phoneNumber
            when (state) {
                //ringing
                TelephonyManager.CALL_STATE_RINGING -> {
                    val intent = Intent(KEY_RECEIVER)
                    intent.putExtra(PHONE_NUMBER, incomingNumber)
                    context.sendBroadcast(intent)
                }
            }
        }
    }
}

Java

The files consist of Helper.java, MainActivity.java and PhoneStateReceiver.java

Helper.java

private boolean isAirplaneModeOn() {
    return Settings.System.getInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
}

MainActivity.java

import android.Manifest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.provider.Settings;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {
    String key; //OTP
    int digits = 6; // 4 or 6 digits to pass verification

    private PhoneStateReceiver phoneStateReceiver = new PhoneStateReceiver();

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

        //check READ_PHONE_STATE and READ_CALL_LOG permission
        List permissions = new ArrayList<>();
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_PHONE_STATE
        ) != PackageManager.PERMISSION_GRANTED
        ) {
            permissions.add(Manifest.permission.READ_PHONE_STATE);
        }
        if (ContextCompat.checkSelfPermission(
                this,
                Manifest.permission.READ_CALL_LOG
        ) != PackageManager.PERMISSION_GRANTED
        ) {
            permissions.add((Manifest.permission.READ_CALL_LOG));
        }

        if (permissions.isEmpty()) {
            //register receivers if all permissions have been granted
            registerReceiver(phoneStateReceiver, new IntentFilter("android.intent.action.PHONE_STATE"));
            registerReceiver(keyReceiver, new IntentFilter(PhoneStateReceiver.KEY_RECEIVER));
        } else {
            //request permission(s) that has not been granted
            ActivityCompat.requestPermissions(this, permissions.toArray(new String[0]), 100);
        }
    }

    //receiver to get the key
    private BroadcastReceiver keyReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String phoneNumber = intent.getExtras().getString(PhoneStateReceiver.PHONE_NUMBER);
            key = phoneNumber.substring(phoneNumber.length()-digits);
        }
    };

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        boolean allGranted = true;
        if (requestCode == 100) {
            for (int result : grantResults) {
                if (result != PackageManager.PERMISSION_GRANTED) {
                    allGranted = false;
                    break;
                }
            }
            if (allGranted) {
                registerReceiver(
                        phoneStateReceiver,
                        new IntentFilter("android.intent.action.PHONE_STATE")
                );
            }
        }
    }

    private boolean isAirplaneModeOn() {
        return Settings.System.getInt(getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0) != 0;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        //unregister receivers
        unregisterReceiver(keyReceiver);
        unregisterReceiver(phoneStateReceiver);
    }
}

PhoneStateReceiver.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;

public class PhoneStateReceiver extends BroadcastReceiver {
    static CustomPhoneStateListener phoneStateListener;
    static String PHONE_NUMBER = "PHONE_NUMBER";
    static String KEY_RECEIVER = "KeyReceiver";

    @Override
    public void onReceive(Context context, Intent intent) {
        TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

        //onReceive will called multiple time, so we have to make sure the listener is only made once
        if (phoneStateListener == null) {
            phoneStateListener = new CustomPhoneStateListener(context);
            telephonyManager.listen(
                    phoneStateListener,
                    PhoneStateListener.LISTEN_CALL_STATE
            );
        }
    }

    class CustomPhoneStateListener extends PhoneStateListener {
        Context context;
        private String incomingNumber;

        public CustomPhoneStateListener(Context context) {
            this.context = context;
        }

        @Override
        public void onCallStateChanged(int state, String phoneNumber) {
            if (!phoneNumber.isEmpty()) incomingNumber = phoneNumber;
            //ringing
            if (state == TelephonyManager.CALL_STATE_RINGING) {
                Intent intent = new Intent(KEY_RECEIVER);
                intent.putExtra(PHONE_NUMBER, incomingNumber);
                context.sendBroadcast(intent);
            }
        }
    }
}