Created
April 20, 2020 16:10
-
-
Save gavelez/92e31020edd0c2f1bf5cf9cb18ba839a to your computer and use it in GitHub Desktop.
How to detect call state Android
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
//https://developer.android.com/reference/android/telephony/TelephonyManager.html | |
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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment