-
Star
(166)
You must be signed in to star a gist -
Fork
(83)
You must be signed in to fork a gist
-
-
Save ftvs/e61ccb039f511eb288ee to your computer and use it in GitHub Desktop.
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 void onIncomingCallStarted(Context ctx, String number, Date start){} | |
protected void onOutgoingCallStarted(Context ctx, String number, Date start){} | |
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end){} | |
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end){} | |
protected 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; | |
onIncomingCallStarted(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); | |
} | |
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; | |
} | |
} |
I read something about how android.permission.READ_PHONE_STATE
wasn't allowed on non-system apps, is this true? Will this code allow me to procedurally answer calls?
Regarding changes makes on Android Pie, (See https://developer.android.com/about/versions/pie/android-9.0-changes-all#restrict-access-phone-numbers),
You must replace lines 28 - 42 by
TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); telephony.listen(new PhoneStateListener() { @Override public void onCallStateChanged(int state, String phoneNumber) { onCustomCallStateChanged(context, state, phoneNumber); } }, PhoneStateListener.LISTEN_CALL_STATE);
And rename
onCallStateChanged()
method inPhonecallReceiver
class byonCustomCallStateChanged()
Thank you
Works all good just give these permissions and ask from user in an activity
android.permission.PROCESS_OUTGOING_CALLS
android.permission.READ_CALL_LOG
android.permission.READ_PHONE_STATE
Also, android.permission.READ_CALL_LOG is used to get phone numbers too no change in code Enjoy
for voip, if you are not using mode in_communication then use this to check if voip app in incoming : https://developer.android.com/reference/android/media/AudioManager.html#MODE_IN_COMMUNICATION
Run foreground service and put the code inside it