-
-
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; | |
} | |
} |
Thank you @ftvs for your nice share! The code works like a charm except for Android 6.0 and above we need to manually popup a dialog to ask the user for the READ_PHONE_STATE
permission. For those folks who have trouble implementing this, I've created a repo and the implemented apk: https://github.com/1isten/WhoIsThat/releases/latest, hope that helps.
Thank you!
methods from class CallReceiver never calls (onIncoming and so on) if you don't implement in Manifest class CallReceiver.
why u guys need it in MainActivity when u already implement in manifest..
Maybe for callbacks implementation? Don't think so?
yup may be..
This lib and call_log not interested now, because Google removing apps, if they cannot be used as default phone app.
how u sure about that becose presently m working on such kind of project?
Because we can't publish our app without default installing and with call_log permission. Old apps with this permissions will be removed soon. It's an answer from Google play support team via email. So, we already remove permissions and make call detecting another way. Google play team accepts our app
what do you think about this app https://play.google.com/store/apps/details?id=com.personlization.magiccall ? it also uses same permissions.
If user can replace default incoming call application (with photo, number and accept/decline call buttons), this app will be leave and active. Google not remove your app. If your app cannot replace default incoming call app (for answering call), Google will remove this app from store :(
Put changes to your app for default using in operation system and all be okay
thank u so much :)
Okay, good luck!:)
I want to read only incoming call number in marshmallow and above. What should I do? My app got rejected by google so I removed the READ_CALL_LOG and everything is OK. But I want to implement the incoming call read in android. Any idea how to build that? Or any suggestion on how to make default calling app in android.
Thanks in advanced.
I want to read only incoming call number in marshmallow and above. What should I do? My app got rejected by google so I removed the READ_CALL_LOG and everything is OK. But I want to implement the incoming call read in android. Any idea how to build that? Or any suggestion on how to make default calling app in android.
Thanks in advanced.
Handle incoming calls via accessibility
Is there a similar method to detect VoIP incoming call start and end in Android programtically ? Thank you
Is there a similar method to detect VoIP incoming call start and end in Android programtically ? Thank you
No. VoIP working over Internet and have private protocol. Look info about SIP.
In case of Multi SIM (Dual SIM) devices, is there any way to find out which SIM is receiving the incoming call ?
This sample not working for multiple calls (second incoming, for example)
not working on oreo devices
not working on oreo devices
Working
not working on oreo devices
Working
have you test this on app kill state?
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()
That worked for me Thanks
not working on oreo devices
Working
have you test this on app kill state?
it is not working when app removed from recent or its process killed
not working on oreo devices
Working
have you test this on app kill state?
it is not working when app removed from recent or its process killed
Run foreground service and put the code inside it
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
There is no state of answer call. I mean If I call someone and they attend the call then this can be also considered as a state like others (CALL_STATE_OFFHOOK, CALL_STATE_IDLE, CALL_STATE_RINGING ). I don't see such state in all example that exists on the internet. If anyone has info or any reference I would be grateful for that.