简体   繁体   English

Android - 来电和去电

[英]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 - 当我开始通话时“INCOMING”然后“OUTGOING”

/* From MainActivity */ /* 来自 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 */ /* 来自 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" />

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

    }



}

Here is my update. 这是我的更新。

Actually, I tried both ways (one BR vs two BR) and both worked well thanks to your answer. 实际上,我尝试了两种方式(一个BR对两个BR),并且由于你的答案,两者都运作良好。 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). 我将告诉你我如何处理一个BR(因为它是我的问题的对象)。

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

    }

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM