26

为了检测拨出电话何时得到应答,我尝试从这个问题PhoneStateListener创建一个并监听TelephonyManager's CALL_STATE_RINGING,CALL_STATE_OFFHOOK和, 但它似乎不起作用,如下所述。CALL_STATE_IDLE

首先,我在清单中注册了以下权限:

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

然后,每当进行拨出呼叫时都会捕获事件的被BroadcastReceiver调用OutCallLoggerNEW_OUTGOING_CALL

<receiver android:name=".listener.OutCallLogger">
    <intent-filter>
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
    </intent-filter>
</receiver>

接下来,我的OutCallLogger. 我设置了一个布尔值noCallListenerYet,以避免在调用时附加一个新PhoneStateListener的。TelephonyManageronReceive()

public class OutCallLogger extends BroadcastReceiver {

    private static boolean noCallListenerYet = true;

    @Override
    public void onReceive(final Context context, Intent intent) {
        number = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
        if (noCallListenerYet) {
            final TelephonyManager tm = (TelephonyManager) context.getSystemService(
                    Context.TELEPHONY_SERVICE);
            tm.listen(new PhoneStateListener() {
                @Override
                public void onCallStateChanged(int state, String incomingNumber) {
                    switch (state) {
                        case TelephonyManager.CALL_STATE_RINGING:
                            Log.d(This.LOG_TAG, "RINGING");
                            break;
                        case TelephonyManager.CALL_STATE_OFFHOOK:
                            Log.d(This.LOG_TAG, "OFFHOOK");
                            break;
                        case TelephonyManager.CALL_STATE_IDLE:
                            Log.d(This.LOG_TAG, "IDLE");
                            break;
                        default:
                            Log.d(This.LOG_TAG, "Default: " + state);
                            break;
                    }
                }
            }, PhoneStateListener.LISTEN_CALL_STATE);
            noCallListenerYet = false;
        }
    }

}

现在,当我在我的设备中拨打电话时,CALL_STATE_RINGING 永远不会调用。当另一条线路开始响铃时,我总是只打印“IDLE”到“OFFHOOK”,接听电话时什么也没有,当通话结束时再次打印“IDLE”。

我怎样才能可靠地检测到在 Android 中何时接听了拨出电话,或者这是否可能?

4

6 回答 6

13

从 Android 5.0 开始,这对于系统应用程序是可能的。但是您需要使用隐藏的 Android API。

我让它像这样工作:

<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
<receiver android:name=".listener.OutCallLogger">
    <intent-filter>
        <action android:name="android.intent.action.PRECISE_CALL_STATE" />
    </intent-filter>
</receiver>
public class OutCallLogger extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        switch (intent.getIntExtra(TelephonyManager.EXTRA_FOREGROUND_CALL_STATE, -2) {
            case PreciseCallState.PRECISE_CALL_STATE_IDLE:
                Log.d(This.LOG_TAG, "IDLE");
                break;
            case PreciseCallState.PRECISE_CALL_STATE_DIALING:
                Log.d(This.LOG_TAG, "DIALING");
                break;
            case PreciseCallState.PRECISE_CALL_STATE_ALERTING:
                Log.d(This.LOG_TAG, "ALERTING");
                break;
            case PreciseCallState.PRECISE_CALL_STATE_ACTIVE:
                Log.d(This.LOG_TAG, "ACTIVE");
                break;
        }
    }
}

您可以在PreciseCallState.java中找到所有可能的呼叫状态,在TelephonyRegistry.java中找到意图包含的所有额外内容。

于 2015-04-07T11:46:44.923 回答
4

看起来只有来电才能达到 RINGING 状态。拨出电话从 IDLE 变为 OFFHOOK,因此查看电话状态可能无法实现这一点。

我认为可以使用内部函数,看看这个:Android电话堆栈中不同的呼叫状态代表什么?

于 2013-08-13T16:08:27.843 回答
1

请关注:

tm.listen(new PhoneStateListener() {
            @Override
            public void onCallStateChanged(int state, String incomingNumber) {
                switch (state) {
                    case TelephonyManager.CALL_STATE_RINGING:
                        Log.d(This.LOG_TAG, "RINGING");
                        break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                        Log.d(This.LOG_TAG, "OFFHOOK");
                        break;
                    case TelephonyManager.CALL_STATE_IDLE:
                        Log.d(This.LOG_TAG, "IDLE");
                        break;
                    default:
                        Log.d(This.LOG_TAG, "Default: " + state);
                        break;
                }
            }
        }, PhoneStateListener.LISTEN_CALL_STATE);

你看到“incomingNumber”参数了吗?是的,只有当您的设备有来电时,该代码才能检测到您的电话状态。

于 2013-12-13T15:57:59.987 回答
1

也许尝试使用CallManager?查看http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.3.3_r1/com/android/internal/telephony/CallManager.java。我还在我计算机上的 SDK 文件中找到了 CallManager.java。链接页面中的以下文本似乎很有希望:

Register for getting notifications for change in the Call State Call.State This is 
called PreciseCallState because the call state is more precise than the Phone.State 
which can be obtained using the android.telephony.PhoneStateListener Resulting events 
will have an AsyncResult in Message.obj. AsyncResult.userData will be set to the obj 
argument here. The h parameter is held only by a weak reference.

1051
1052    public void registerForPreciseCallStateChanged(Handler h, int what, Object obj){
1053        mPreciseCallStateRegistrants.addUnique(h, what, obj);
1054    }

我没有尝试编写任何代码,所以真的不知道它是否可以做你想做的事,但我很想知道。

于 2012-11-09T22:32:12.127 回答
-1

您可以执行以下操作...不是很精确,但可以解决问题:

  1. 您将接收器用于android.intent.action.NEW_OUTGOING_CALL操作
  2. 当接收器被调用时,您将 NEW_OUTGOIN_CALL 状态和发生这种情况的时间(即 new Date().getTime())存储在某处(例如静态变量)
  3. 您将另一个接收器用于android.intent.action.PHONE_STATE并在 onReceive 中执行以下操作:

    if (intent.getAction().equals("android.intent.action.PHONE_STATE")) {
        TelephonyManager telephony = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        telephony.listen(new PhoneStateListener() {
            public void onCallStateChanged(int state, String incomingNumber) {
                  switch(state) {
                    case TelephonyManager.CALL_STATE_IDLE:
                    break;
                    case TelephonyManager.CALL_STATE_OFFHOOK:
                    break;
                    case TelephonyManager.CALL_STATE_RINGING:
                    break;
                   }
            } 
        }, PhoneStateListener.LISTEN_CALL_STATE);
    
    }
    

在 CALL_STATE_OFFHOOK 情况下,您检查最后存储的状态是 NEW_OUTGOING_CALL 并且不超过 aprox。自上次状态更改以来已过去 10 秒。这意味着电话最多在 10 秒前发起呼叫,现在他处于摘机状态(即通话中),没有经过空闲或振铃。这可能意味着呼叫已被应答。

于 2013-01-02T17:04:14.790 回答
-2

在这里,您的答案是您在 OutGoingCallReceiver 中实现了 CallStateListener ,这是错误的。您必须在 PhoneStateListener 中实现 CallStateListener

我在早期的项目中也尝试过这个东西,我遇到了同样的问题,然后我解决了它,如下所示。我参加了以下3节课。

  1. AutoCallReceiver:注册 TelephonyManagerPhoneStateListener.LISTEN_CALL_STATE

  2. CallStateListener 侦听三个状态为TelephonyManager.CALL_STATE_IDLE, TelephonyManager.CALL_STATE_OFFHOOK,TelephonyManager.CALL_STATE_RINGING

3.OutGoingCallReceiver 处理去电

public class OutGoingCallReceiver extends BroadcastReceiver {  
    /* onReceive will execute on out going call */
    @Override  
    public void onReceive(Context context, Intent intent) {  
        Toast.makeText(context, "OutGoingCallReceiver", Toast.LENGTH_SHORT).show();
    }
}

public class CallStateListener extends PhoneStateListener {  
    String number=""; // variable for storing incoming/outgoing number
    Context mContext; // Application Context

    //Constructor that will accept Application context as argument
    public CallStateListener(Context context) {
        mContext=context;
    }

    // This function will automatically invoke when call state changed
    public void onCallStateChanged(int state,String incomingNumber)
    {
        boolean end_call_state=false; // this variable when true indicate that call is disconnected
        switch(state) {
            case TelephonyManager.CALL_STATE_IDLE:  
                // Handling Call disconnect state after incoming/outgoing call 
                Toast.makeText(mContext, "idle", Toast.LENGTH_SHORT).show();
                break;  

            case TelephonyManager.CALL_STATE_OFFHOOK:     
                // Handling outgoing call  
                Toast.makeText(mContext, "OFFHOOK", Toast.LENGTH_SHORT).show();
                // saving outgoing call state so that after disconnect idle state can act accordingly
                break;  

            case TelephonyManager.CALL_STATE_RINGING: 
                Toast.makeText(mContext, "RINGING", Toast.LENGTH_SHORT).show();     
                break;
        }
    }
}

public class AutoCallReceiver extends BroadcastReceiver {       
    /* onReceive will execute on call state change */
    @Override  
    public void onReceive(Context context, Intent intent) { 

    // Instantiating PhoneStateListener
    CallStateListener phoneListener=new CallStateListener(context);  

    // Instantiating TelephonyManager
        TelephonyManager telephony = (TelephonyManager)   
                         context.getSystemService(Context.TELEPHONY_SERVICE);  

            // Registering the telephony to listen CALL STATE change
        telephony.listen(phoneListener,PhoneStateListener.LISTEN_CALL_STATE);  
    }
}

<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
<application ...>
    <receiver android:name=".OutGoingCallReceiver">
        <intent-filter>
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
    </receiver>
    <receiver android:name=".AutoCallReceiver">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
    </receiver>
</application>
于 2012-10-30T07:27:51.567 回答