在Android中无法检测到何时应答拨出呼叫

Mat*_*ros 25 android broadcastreceiver

为了检测时传出呼叫接通后,我尝试创建一个PhoneStateListener和监听TelephonyManagerCALL_STATE_RINGING,CALL_STATE_OFFHOOKCALL_STATE_IDLE,从这个问题,但它似乎没有工作,如下所述.

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

<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
Run Code Online (Sandbox Code Playgroud)

然后,一个BroadcastReceiverOutCallLogger映入NEW_OUTGOING_CALL每当呼出由事件:

<receiver android:name=".listener.OutCallLogger">
    <intent-filter>
        <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
    </intent-filter>
</receiver>
Run Code Online (Sandbox Code Playgroud)

接下来,我执行OutCallLogger.我设置了一个布尔值,调用noCallListenerYet以避免在调用PhoneStateListenerTelephonyManager时候附加一个新的onReceive().

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

}
Run Code Online (Sandbox Code Playgroud)

现在,当我在我的设备中拨打电话时,CALL_STATE_RINGING 永远不会被调用.当另一条线路开始响铃时,我总是只能将"IDLE"的打印输出打印到"OFFHOOK",当应答呼叫时,只打印输出"IDLE",并且当呼叫结束时再打印输出"IDLE".

如何可靠地检测何时在Android中应答拨出电话,或者甚至是可能的?

Tim*_* S. 11

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

我让它像这样工作:

<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
Run Code Online (Sandbox Code Playgroud)
<receiver android:name=".listener.OutCallLogger">
    <intent-filter>
        <action android:name="android.intent.action.PRECISE_CALL_STATE" />
    </intent-filter>
</receiver>
Run Code Online (Sandbox Code Playgroud)
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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以在PreciseCallState.java中找到所有可能的调用状态以及intent在TelephonyRegistry.java中包含的所有额外内容.

  • @stack此解决方案仅适用于Android> = 5.0.Android 5.0中的Telephony API已[更改](https://github.com/android/platform_frameworks_base/commit/c5ac15a3e11c03951e269b243674858411204b67)以实现此目的.(所需权限的保护级别后来[从危险更改为签名系统](https://android.googlesource.com/platform/frameworks/base/+/5742335%5E!/). (3认同)
  • @MuhammadBabar 我使用它的方式是我使用反射在运行时加载符号,并且我只在有 root 权限的手机上安装我的应用程序作为系统应用程序。我自己没有尝试过替换任何 .jars,但我认为你需要在编译时链接到 `android-with-hidden-api.jar`。 (2认同)

Man*_*esh -3

这里你的答案是你在 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();
    }
}
Run Code Online (Sandbox Code Playgroud)
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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
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);  
    }
}
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

  • 我从你的代码中了解到,当拨打电话时,它会触发“NEW_OUTGOING_CALL”,因此它会转到“OutGoingCallReceiver”,它除了显示“Toast”之外什么也不做。然后,当来电到达时(这不是所述问题),“PHONE_STATE”意图被触发,并且应用程序在“AutoCallReceiver”执行之前崩溃,因为您没有包含“READ_PHONE_STATE”权限。但无论如何,您只需将“PhoneStateListener”放在外部类中,而我将其编写为匿名类。因此,预期的效果是相同的。 (4认同)