frontal
frontal

Reputation: 99

Android - INCOMING & OUTGOING calls

I am trying to display a message everytime I start a call or everytime I receive a call. I made a code which works for INCOMING call but not for OUTGOING ones. I DID read the different posts about this subject.

Could anyone tell me why this following code shows me (of course this code does not do everything I mentionned previously) :
- "OUTGOING" when i receive a call
- "INCOMING" then "OUTGOING" when i start a call

/* From MainActivity */

protected void onCreate(Bundle savedInstanceState) 
 {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  context = getApplicationContext();
  context.startService(new Intent(context, SvcCall.class));
 }

/* From SvcCall */

public class SvcCall extends Service 
 {
  private static final String ACTION_OUT = "android.intent.action.PHONE_STATE";
  private static final String ACTION_IN = "android.intent.action.NEW_OUTGOING_CALL";
  private CallBr br_call;

  @Override
  public void onCreate()
   {
    super.onCreate();   
   }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId)
   {
    final IntentFilter filter = new IntentFilter();
    filter.addAction(ACTION_OUT);
    filter.addAction(ACTION_IN); 
    this.br_call = new CallBr();
    this.registerReceiver(this.br_call, filter);
    return (START_STICKY);
   }

  public class CallBr extends BroadcastReceiver  
   {
    @Override
    public void onReceive(Context context, Intent intent) 
 {
  if (intent.getAction().equals(ACTION_IN))
       Toast.makeText(context, "INCOMING", Toast.LENGTH_LONG).show();       
  else if (intent.getAction().equals(ACTION_OUT))
   Toast.makeText(context, "OUTGOING", Toast.LENGTH_LONG).show();
     }
   }

 @Override
 public IBinder onBind(Intent intent) 
 {
  return null;
 }
} 

/* From Manifest */

<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />

Upvotes: 2

Views: 12042

Answers (4)

Ravi Kant
Ravi Kant

Reputation: 11

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;

import java.util.Date;

public abstract class PhoneCallReceiver2 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(context);
        }

        //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);

        //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;
        }

    }

    //Derived classes should override these to respond to specific events of interest
    protected abstract void onIncomingCallStarted(Context context, String number, Date start);

    protected abstract void onOutgoingCallStarted(Context context, String number, Date start);

    protected abstract void onIncomingCallEnded(Context context, String number, Date start, Date end);

    protected abstract void onOutgoingCallEnded(Context context, String number, Date start, Date end);

    protected abstract void onMissedCall(Context context, 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
        Context savedContext;

        public PhonecallStartEndDetector(Context savedContext) {
            this.savedContext = savedContext;
        }

        //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(savedContext, 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(savedContext, 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(savedContext, savedNumber, callStartTime);
                    } else if (isIncoming) {
                        onIncomingCallEnded(savedContext, savedNumber, callStartTime, new Date());
                    } else {
                        onOutgoingCallEnded(savedContext, savedNumber, callStartTime, new Date());
                    }
                    break;
            }
            lastState = state;
        }

    }

}

Upvotes: 0

user3883019
user3883019

Reputation: 29

switch (state) {
case TelephonyManager.CALL_STATE_IDLE:                      
    //CALL_STATE_IDLE;
    Toast.makeText(getApplicationContext(), "CALL_STATE_IDLE", Toast.LENGTH_LONG).show();
    break;
case TelephonyManager.CALL_STATE_OFFHOOK:
    //CALL_STATE_OFFHOOK;
    Toast.makeText(getApplicationContext(), "CALL_STATE_OFFHOOK", Toast.LENGTH_LONG).show();
    break;
case TelephonyManager.CALL_STATE_RINGING:
    //CALL_STATE_RINGING
    Toast.makeText(getApplicationContext(), incomingNumber, Toast.LENGTH_LONG).show();   
    Toast.makeText(getApplicationContext(), "CALL_STATE_RINGING", Toast.LENGTH_LONG).show();
     break;
default:
     break;
}

Dont forget to make a permission..

<uses-permission android:name="android.permission.READ_PHONE_STATE"/>

Upvotes: -2

frontal
frontal

Reputation: 99

Here is my update.

Actually, I tried both ways (one BR vs two BR) and both worked well thanks to your answer. Everything is not perfect at this moment. I am working on it. I'll show you how I do with one BR (because it was the object of my question).

public class SvcCall extends Service 
 {
  Context _context;
  private static final String ACTION_IN = "android.intent.action.PHONE_STATE";
  private static final String ACTION_OUT = "android.intent.action.NEW_OUTGOING_CALL";
  private CallBr br_call;

  @Override
  public void onCreate()
   {
    super.onCreate();
    this._context = getApplicationContext();   
   }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId)
   {
    final IntentFilter filter = new IntentFilter();
    filter.addAction(ACTION_OUT);
    filter.addAction(ACTION_IN); 
    this.br_call = new CallBr();
    this.registerReceiver(this.br_call, filter);
    return (START_STICKY);
   }

  public class CallBr extends BroadcastReceiver  
   {
    Bundle bundle;
    String state;
    String inCall, outCall;
    public boolean wasRinging = false;

   @Override
   public void onReceive(Context context, Intent intent) 
    {
     if (intent.getAction().equals(ACTION_IN))
      {
       if ((bundle = intent.getExtras()) != null)
        {
         state = bundle.getString(TelephonyManager.EXTRA_STATE);
         if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))
          {          
           inCall = bundle.getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
           wasRinging = true;
           Toast.makeText(context, "IN : " + inCall, Toast.LENGTH_LONG).show();        
          }
         else if (state.equals(TelephonyManager.EXTRA_STATE_OFFHOOK))
          {        
           if (wasRinging == true)
            Toast.makeText(context, "ANSWERED", Toast.LENGTH_LONG).show();
          }
         else if (state.equals(TelephonyManager.EXTRA_STATE_IDLE))
          {
           wasRinging = false;
           Toast.makeText(context, "REJECT || DISCO", Toast.LENGTH_LONG).show();
          }
        }
      }
     else if (intent.getAction().equals(ACTION_OUT))
      {
       if ((bundle = intent.getExtras()) != null)
        {  
         outCall = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
         Toast.makeText(context, "OUT : " + outCall, Toast.LENGTH_LONG).show();
        }
      }
     }
    }

   @Override
   public IBinder onBind(Intent intent)
    {
     return null;
    }
  }

Upvotes: 1

Gabe Sechan
Gabe Sechan

Reputation: 93708

This is the class I use to react to incoming and outgoing phonecalls. Its set up so you just have to derive and override the ones you care about. It also tells you wheter the call is starting, ending, or was not picked up:

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;
        }

    }



}

Upvotes: 10

Related Questions