I\'m trying to make an app like, when a call comes to the phone I want to detect the number. Below is what I tried, but it\'s not detecting incoming calls.
I want t
Here's what I use to do this:
Manifest:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<!--This part is inside the application-->
<receiver android:name=".CallReceiver" >
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
My base reusable call detector
package com.gabesechan.android.reusable.receivers;
import java.util.Date;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
public abstract class PhonecallReceiver extends BroadcastReceiver {
//The receiver will be recreated whenever android feels like it. We need a static variable to remember data between instantiations
private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private static Date callStartTime;
private static boolean isIncoming;
private static String savedNumber; //because the passed incoming is only valid in ringing
@Override
public void onReceive(Context context, Intent intent) {
//We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number.
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
}
else{
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;
}
onCallStateChanged(context, state, number);
}
}
//Derived classes should override these to respond to specific events of interest
protected abstract void onIncomingCallReceived(Context ctx, String number, Date start);
protected abstract void onIncomingCallAnswered(Context ctx, String number, Date start);
protected abstract void onIncomingCallEnded(Context ctx, String number, Date start, Date end);
protected abstract void onOutgoingCallStarted(Context ctx, String number, Date start);
protected abstract void onOutgoingCallEnded(Context ctx, String number, Date start, Date end);
protected abstract void onMissedCall(Context ctx, String number, Date start);
//Deals with actual events
//Incoming call- goes from IDLE to RINGING when it rings, to OFFHOOK when it's answered, to IDLE when its hung up
//Outgoing call- goes from IDLE to OFFHOOK when it dials out, to IDLE when hung up
public void onCallStateChanged(Context context, int state, String number) {
if(lastState == state){
//No change, debounce extras
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
callStartTime = new Date();
savedNumber = number;
onIncomingCallReceived(context, number, callStartTime);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
if(lastState != TelephonyManager.CALL_STATE_RINGING){
isIncoming = false;
callStartTime = new Date();
onOutgoingCallStarted(context, savedNumber, callStartTime);
}
else
{
isIncoming = true;
callStartTime = new Date();
onIncomingCallAnswered(context, savedNumber, callStartTime);
}
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
onMissedCall(context, savedNumber, callStartTime);
}
else if(isIncoming){
onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
}
else{
onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
}
break;
}
lastState = state;
}
}
Then to use it, simply derive a class from it and implement a few easy functions, whichever call types you care about:
public class CallReceiver extends PhonecallReceiver {
@Override
protected void onIncomingCallReceived(Context ctx, String number, Date start)
{
//
}
@Override
protected void onIncomingCallAnswered(Context ctx, String number, Date start)
{
//
}
@Override
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end)
{
//
}
@Override
protected void onOutgoingCallStarted(Context ctx, String number, Date start)
{
//
}
@Override
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end)
{
//
}
@Override
protected void onMissedCall(Context ctx, String number, Date start)
{
//
}
}
In addition you can see a writeup I did on why the code is like it is on my blog. Gist link: https://gist.github.com/ftvs/e61ccb039f511eb288ee
EDIT: Updated to simpler code, as I've reworked the class for my own use
this may helps you and also add require permision
public class PhoneListener extends PhoneStateListener
{
private Context context;
public static String getincomno;
public PhoneListener(Context c) {
Log.i("CallRecorder", "PhoneListener constructor");
context = c;
}
public void onCallStateChanged (int state, String incomingNumber)
{
if(!TextUtils.isEmpty(incomingNumber)){
// here for Outgoing number make null to get incoming number
CallBroadcastReceiver.numberToCall = null;
getincomno = incomingNumber;
}
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
break;
case TelephonyManager.CALL_STATE_RINGING:
Log.d("CallRecorder", "CALL_STATE_RINGING");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
break;
}
}
}
private MyPhoneStateListener phoneStateListener = new MyPhoneStateListener();
to register
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE);
and to unregister
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_NONE);
@Gabe Sechan, thanks for your code. It works fine except the onOutgoingCallEnded()
. It is never executed. Testing phones are Samsung S5 & Trendy. There are 2 bugs I think.
1: a pair of brackets is missing.
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
onMissedCall(context, savedNumber, callStartTime);
} else {
// this one is missing
if(isIncoming){
onIncomingCallEnded(context, savedNumber, callStartTime, new Date());
} else {
onOutgoingCallEnded(context, savedNumber, callStartTime, new Date());
}
}
// this one is missing
break;
2: lastState
is not updated by the state
if it is at the end of the function. It should be replaced to the first line of this function by
public void onCallStateChanged(Context context, int state, String number) {
int lastStateTemp = lastState;
lastState = state;
// todo replace all the "lastState" by lastStateTemp from here.
if (lastStateTemp == state) {
//No change, debounce extras
return;
}
//....
}
Additional I've put lastState
and savedNumber
into shared preference as you suggested.
Just tested it with above changes. Bug fixed at least on my phones.