Skip to content

Instantly share code, notes, and snippets.

@yvantcheuffa
Forked from ftvs/PhonecallReceiver.java
Created October 12, 2020 09:15
Show Gist options
  • Save yvantcheuffa/881f48e2ef1f9396259cabfc3ba0a3bc to your computer and use it in GitHub Desktop.
Save yvantcheuffa/881f48e2ef1f9396259cabfc3ba0a3bc to your computer and use it in GitHub Desktop.

Revisions

  1. @ftvs ftvs revised this gist Aug 21, 2020. No changes.
  2. @ftvs ftvs revised this gist Aug 5, 2015. No changes.
  3. @ftvs ftvs revised this gist Aug 5, 2015. No changes.
  4. @ftvs ftvs revised this gist Aug 5, 2015. No changes.
  5. @ftvs ftvs revised this gist Aug 5, 2015. No changes.
  6. @ftvs ftvs revised this gist Aug 5, 2015. No changes.
  7. @ftvs ftvs revised this gist Aug 5, 2015. No changes.
  8. @ftvs ftvs revised this gist Aug 5, 2015. No changes.
  9. @ftvs ftvs revised this gist Aug 5, 2015. No changes.
  10. @ftvs ftvs created this gist Aug 5, 2015.
    93 changes: 93 additions & 0 deletions PhonecallReceiver.java
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,93 @@
    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;
    }
    }