2013-06-02 17 views
1

我試圖在每次開始通話或每次接到來電時顯示一條消息。我製作了一個適用於INCOMING呼叫但不適用於OUTGOING呼叫的代碼。 我讀了關於這個問題的不同職位。Android - INCOMING&OUTGOING來電

誰能告訴我,爲什麼這下面的代碼演示了我(當然這個代碼沒有做的一切,我以前mentionned):
- 「離開」當我接到一個電話
- 「來電」,那麼「離開」時,我開始呼叫

/*從MainActivity */

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

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

/*來自清單*/

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

只要看一眼的文字:沒有'ACTION_IN'和'ACTION_OUT'的定義逆轉嗎? – chr

+0

+1。謝啦。我猜這就是它。要檢查它。但我決定註冊兩個不同的廣播接收器。 – frontal

+0

一旦你得到它的工作,包括第二個問題(當你開始呼叫時兩個敬酒),發佈更正作爲答案並接受它。這樣做完全可以,所以如果他們在相同的問題上出行,其他人會找到答案。 – chr

回答

9

這是我使用對傳入和傳出的電話中發生反應的類。它的設置讓你只需要派生並覆蓋你關心的人。它還告訴你,電話是開始,結束,還是沒有拿起:

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

    } 



} 
+0

+1。感謝這個班級。我會研究它。只是一個問題:你爲什麼使用抽象類?我不太瞭解Java的這一部分。它意味着/提供了什麼? – frontal

+0

我試過了,但我不能使用registerReceiver以動態的方式註冊BR - 最後的IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_OUT); filter.addAction(ACTION_IN); this.br_call = new PhonecallReceiver(); this.registerReceiver(this.br_call,filter);. **我的錯誤:「無法實例化PhonecallReceiver類型」。** – frontal

+0

AN抽象類僅僅意味着它沒有被直接實例化 - 你創建了一個子類並讓它覆蓋了抽象函數。這通常是在你不知道某些功能要做什麼但是孩子做什麼的時候完成的 - 例如,在這裏你需要指定當發生呼入,發生呼出等時要做什麼。儘管它們都可以是空的什麼都不做。 –

1

這是我的更新。

其實,我嘗試了兩種方法(一個BR與兩個BR),並且都很好地工作,這要感謝您的答案。現在一切都不完美。我正在做。我會告訴你我如何處理一個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; 
    } 
    } 
-2
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; 
} 

不要忘記將許可..

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