androidbroadcastreceiverphone-call

Detect the end of an answered incoming call by user in android? (not declined)


In my android application, I have created a BroadcastReceiver that detects incoming call; my code is running very well. If there is an incoming call (EXTRA_STATE_RINGING), I can see my incommingNumber in the logcat, also when the user answered the call (EXTRA_STATE_OFFHOOK)

This is my code, it works perfectly:

 public class IncomingCallReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        
           String incomingNumber = null ;
          if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) 
          {
            // Ringing state
            // Phone number 
              incomingNumber = intent.getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);
             
              Log.i("test2", incomingNumber);
              
              SharedPreferences myPrefs = context.getSharedPreferences("myPrefs",Context.MODE_WORLD_WRITEABLE);
              SharedPreferences.Editor prefsEditor = myPrefs.edit();
              prefsEditor.putString("Incomingnumber", incomingNumber);
              //Not forgot to commit.
              prefsEditor.commit();

              
          } 
          
          else if  (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) 
          {
              //get the incoming number 
              SharedPreferences myPrefs = context.getSharedPreferences("myPrefs",Context.MODE_WORLD_READABLE);
              String incomNumber = myPrefs.getString("Incomingnumber", incomingNumber);
              
              // This code will execute when the call is answered
              
              Log.i("test2", incomNumber);
              Toast.makeText(context,incomNumber, Toast.LENGTH_LONG).show();
               
          }

BUT: My problem that my code can display a toast when the user just Accept the incoming call.

So, I need to know how I can detect the end of an answered the incoming call to do something else (display an alert dialog or launch an activity)


Solution

  • I've posted this here before- here's my class for detecting incoming calls start and end, outgoing calls start and end, and missed calls.

    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.PhoneStateListener;
    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
        static PhonecallStartEndDetector listener;
        String outgoingSavedNumber;
        protected Context savedContext;
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
            savedContext = context;
            if(listener == null){
                listener = new PhonecallStartEndDetector();
            }
    
            //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")) {
                listener.setOutgoingNumber(intent.getExtras().getString("android.intent.extra.PHONE_NUMBER"));
                return;
            }
    
            //The other intent tells us the phone state changed.  Here we set a listener to deal with it
            TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); 
            telephony.listen(listener, PhoneStateListener.LISTEN_CALL_STATE);
        }
    
        //Derived classes should override these to respond to specific events of interest
        protected abstract void onIncomingCallStarted(String number, Date start);
        protected abstract void onOutgoingCallStarted(String number, Date start);
        protected abstract void onIncomingCallEnded(String number, Date start, Date end); 
        protected abstract void onOutgoingCallEnded(String number, Date start, Date end);
        protected abstract void onMissedCall(String number, Date start);
    
        //Deals with actual events
        public class PhonecallStartEndDetector extends PhoneStateListener {
            int lastState = TelephonyManager.CALL_STATE_IDLE;
            Date callStartTime;
            boolean isIncoming;
            String savedNumber;  //because the passed incoming is only valid in ringing
    
            public PhonecallStartEndDetector() {}
    
            //The outgoing number is only sent via a separate intent, so we need to store it out of band
            public void setOutgoingNumber(String number){
                savedNumber = number;
            }
    
            //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
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                super.onCallStateChanged(state, incomingNumber);
                if(lastState == state){
                    //No change, debounce extras
                    return;
                }
                switch (state) {
                    case TelephonyManager.CALL_STATE_RINGING:
                        isIncoming = true;
                        callStartTime = new Date();
                        savedNumber = incomingNumber;
                        onIncomingCallStarted(incomingNumber, callStartTime);
                        break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        //Transition of ringing->offhook are pickups of incoming calls.  Nothing donw on them
                        if(lastState != TelephonyManager.CALL_STATE_RINGING){
                            isIncoming = false;
                            callStartTime = new Date();
                            onOutgoingCallStarted(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(savedNumber, callStartTime);
                        }
                        else if(isIncoming){
                            onIncomingCallEnded(savedNumber, callStartTime, new Date());                        
                        }
                        else{
                            onOutgoingCallEnded(savedNumber, callStartTime, new Date());                                                
                        }
                        break;
                }
                lastState = state;
            }
    
        }
    
    
    
    }