如何检测电话何时被接听或拒绝

Posted

技术标签:

【中文标题】如何检测电话何时被接听或拒绝【英文标题】:How to detect when phone is answered or rejected 【发布时间】:2012-03-29 21:40:24 【问题描述】:

当电话响起时,我设法准备了一项活动。现在我需要知道如何取消此活动,当我接听电话或拒接电话时。我是拨打EXTRA_STATE_IDLE 还是EXTRA_STATE_OFFHOOK

有什么想法吗?

清单

    <receiver android:name=".IncomingBroadcastReceiver">
        <intent-filter>
            <action android:name="android.intent.action.PHONE_STATE" />
        </intent-filter>
    </receiver>

IncomingBroadcastReceiver java 类

public class IncomingBroadcastReceiver extends BroadcastReceiver 
    @Override
    public void onReceive(Context context, Intent intent) 
        String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
        // If an incoming call arrives
        if (state.equals(TelephonyManager.EXTRA_STATE_RINGING))  //Did my work 

【问题讨论】:

【参考方案1】:

以上答案在拨出电话的情况下是完全错误的。在 Android 中,无法检测呼叫是否被实际接听(在拨出电话的情况下)。在您拨打号码的那一刻,off_hook 状态被触发。这是 Android 编程的缺点之一。

【讨论】:

真的!在使用 BroadcastReceivers 时发现同样的问题。 "在 android 中,无法检测呼叫是否被实际接听(在拨出电话的情况下)。" -- 那么股票拨号器如何检测/显示持续时间?在您方便的时候试试这个:拨打另一个号码 20 秒,然后在您结束时结束通话。对于最后拨打的号码,您的拨号器应显示 0min0secs 持续时间。现在再次拨打电话,但在另一端接听电话 5-10 秒。在您结束通话时,您的拨号器会显示接听电话的持续时间 是的,我已经在我的应用程序 www.callrecorder.cc/app 中彻底测试了这一点 到目前为止,无法检测是否接听了拨出电话。拨出号码后,手机立即进入 OFF_HOOK 状态。 你可以设置一个定时器,从off_hook事件开始。计数 +30 秒,如果通话没有结束,你可以放心地假设它已被接听(如果你愿意,可以终止它,就像这样 ***.com/a/8380418/3441905) @Firelord,股票拨号器使用隐藏的 PreciseCallState github.com/android/platform_frameworks_base/blob/master/…【参考方案2】:

在您的 onReceive 中:

PhoneStateChangeListener pscl = new PhoneStateChangeListener();
TelephonyManager tm = (TelephonyManager)this.getSystemService(Context.TELEPHONY_SERVICE);
tm.listen(pscl, PhoneStateListener.LISTEN_CALL_STATE);

单独的类:

private class PhoneStateChangeListener extends PhoneStateListener 
    public static boolean wasRinging;
    String LOG_TAG = "PhoneListener";
    @Override
    public void onCallStateChanged(int state, String incomingNumber) 
        switch(state)
            case TelephonyManager.CALL_STATE_RINGING:
                 Log.i(LOG_TAG, "RINGING");
                 wasRinging = true;
                 break;
            case TelephonyManager.CALL_STATE_OFFHOOK:
                 Log.i(LOG_TAG, "OFFHOOK");

                 if (!wasRinging) 
                     // Start your new activity
                  else 
                     // Cancel your old activity
                 

                 // this should be the last piece of code before the break
                 wasRinging = true;
                 break;
            case TelephonyManager.CALL_STATE_IDLE:
                 Log.i(LOG_TAG, "IDLE");
                 // this should be the last piece of code before the break
                 wasRinging = false;
                 break;
        
    

您需要做的就是编写一些代码来检查之前的状态是否为“响铃”。 如果当前状态是空闲并且之前的状态是响铃,他们就取消了通话。 如果当前状态是摘机而之前的状态是振铃,则他们接听了电话。

【讨论】:

谢谢,这看起来是正确的答案!我是这方面的菜鸟...如何查看手机以前的状态?感谢您的宝贵时间!!! 只需将您需要的代码添加到 OFFHOOK 和 IDLE。如果您拿起电话(OFFHOOK)或拒绝呼叫(IDLE),代码将被执行。无需检查以前的状态:电话的默认状态是空闲的,所以在有人打电话之前,它不会改变(我假设活动在有人打电话时开始)。只需确保检查 CALL_STATE_IDLE 的活动是否仍处于活动状态,因为如果您拿起电话,它可能已经关闭,然后关闭呼叫。 谢谢!我有一个问题...我需要在发出新的拨出电话时提出新的活动。我可以在 onCallStateChanged 中的哪里执行此操作? 还有一个问题 拨出电话被接听了怎么办? case TelephonyManager.CALL_STATE_OFFHOOK 中的最后一段代码,应该改成wasRinging = false; 吗?【参考方案3】:

以下是它在不同场景中经历的状态:

1) 接听来电

CALL_STATE_RINGING => CALL_STATE_OFFHOOK (After Answering call) => CALL_STATE_IDLE (After End call) 

2) 拒绝/未接听(未接)已接电话

CALL_STATE_RINGING => CALL_STATE_IDLE (After End call)  

3) 拨打电话

CALL_STATE_OFFHOOK (After dialing) => CALL_STATE_IDLE (After End call) 

代码

  int prev_state=0;


  public class CustomPhoneStateListener extends PhoneStateListener   

        private static final String TAG = "CustomPhoneStateListener";  

        @Override  
        public void onCallStateChanged(int state, String incomingNumber)  

            if(incomingNumber!=null&&incomingNumber.length()>0) incoming_nr=incomingNumber;   

            switch(state)  
                case TelephonyManager.CALL_STATE_RINGING:  
                        Log.d(TAG, "CALL_STATE_RINGING");  
                        prev_state=state;  
                        break;  
                case TelephonyManager.CALL_STATE_OFFHOOK:  
                Log.d(TAG, "CALL_STATE_OFFHOOK");  
                prev_state=state;  
                break;  
                case TelephonyManager.CALL_STATE_IDLE:  
                    Log.d(TAG, "CALL_STATE_IDLE==>"+incoming_nr);  
                    NumberDatabase database=new NumberDatabase(mContext);  
                    if((prev_state==TelephonyManager.CALL_STATE_OFFHOOK))  
                        prev_state=state;  
                        //Answered Call which is ended  
                      
                    if((prev_state==TelephonyManager.CALL_STATE_RINGING))  
                        prev_state=state;  
                        //Rejected or Missed call  
                      
                    break;  

              
          
      

在你的接收器中

onReceive(Context context, Intent intent)   
        TelephonyManager telephony = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); //TelephonyManager object  
        CustomPhoneStateListener customPhoneListener = new CustomPhoneStateListener();  
        telephony.listen(customPhoneListener, PhoneStateListener.LISTEN_CALL_STATE);          //Register our listener with TelephonyManager  

        Bundle bundle = intent.getExtras();  
        String phoneNr= bundle.getString("incoming_number");  

        mContext=context;  
   

【讨论】:

Tnaks!有什么方法可以知道如何知道拨出电话是否已接听? 这是错误的。拨打电话时立即调用 CALL_STATE_OFFHOOK。说真的,你们中有多少人甚至没有测试过就在 *** 中发布了这个? Please read this carefully @AndroidDev 你找到解决方案了吗【参考方案4】:

以下是通过辅助功能事件检测拨出呼叫的代码 -

在您的项目中添加一个扩展 AccessibilityService 的类 -

public class CallDetection extends AccessibilityService 
@Override
public void onAccessibilityEvent(AccessibilityEvent event) 
     acquireLock(this);
    Log.d("myaccess","after lock");
    if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED) 
        Log.d("myaccess","in window changed");
        AccessibilityNodeInfo info = event.getSource();
        if (info != null && info.getText() != null) 
            String duration = info.getText().toString();
            String zeroSeconds = String.format("%02d:%02d", new Object[]Integer.valueOf(0), Integer.valueOf(0));
            String firstSecond = String.format("%02d:%02d", new Object[]Integer.valueOf(0), Integer.valueOf(1));
            Log.d("myaccess","after calculation - "+ zeroSeconds + " --- "+ firstSecond + " --- " + duration);
            if (zeroSeconds.equals(duration) || firstSecond.equals(duration)) 
                Toast.makeText(getApplicationContext(),"Call answered",Toast.LENGTH_SHORT).show();
               // Your Code goes here
            
            info.recycle();
        
    



@Override
protected void onServiceConnected() 
    super.onServiceConnected();
    Toast.makeText(this,"Service connected",Toast.LENGTH_SHORT).show();
    AccessibilityServiceInfo info = new AccessibilityServiceInfo();
    info.eventTypes = AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
    info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
    info.notificationTimeout = 0;
    info.packageNames = null;
    setServiceInfo(info);


@Override
public void onInterrupt() 



但要让event.getSource() 函数工作,你必须通过xml 指定一些服务配置,所以在你的项目中创建一个xml 文件夹并添加一个名为serviceconfig 的xml 文件。 xml(你可以给任何你想要的名字。

serviceconfig的内容如下——

<accessibility-service xmlns:android="http://schemas.android.com/apk/res/android"
android:description="@string/callDetection"
android:accessibilityEventTypes="typeWindowContentChanged"
android:notificationTimeout="100"
android:canRetrieveWindowContent="true"
/>

您可以在Here中找到更多关于serviceconfig的信息

现在像这样在 Manifest 文件中添加您的服务 -

<service android:name=".CallDetection"
        android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
        android:label="@string/callDetection">
        <intent-filter>
            <action android:name="android.accessibilityservice.AccessibilityService" />
        </intent-filter>
        <meta-data
            android:name="android.accessibilityservice"
            android:resource="@xml/serviceconfig" />
</service>

大功告成,只需运行该应用程序并转到手机中的辅助功能设置,您将找到一个名为检测或任何您喜欢的名称)的选项已作为您的服务描述提供),将其打开以授予您应用的访问权限。

现在您会在接听电话时看到祝酒词。

您可以在其中编写任何您想要的代码,也可以在您的活动中调用回调函数

最重要的 - 在接听电话之前不要拨打您的通话窗口(Android 拨号器窗口),否则这将不起作用。

注意 - 由于 android 没有提供任何解决方案来检测呼叫是否被应答,这是我所做的最好的选择,希望它对你有用。

【讨论】:

您能否添加一个示例,展示如何在问题的特定情况下应用您的解决方案?就目前而言,您的答案只不过是带有指向另一个问题答案的链接的评论。 以前我将整个代码和示例添加到多个答案中,但是来自 *** 的一位版主删除了我的答案,说不要添加重复的答案,这就是为什么我在此处添加链接和对一个问题的实际答案仅限。 我相信重复答案只有在完全重复时才被认为是一个问题。由于问题之间存在差异,因此答案应该存在差异,我个人(作为一个低级平民)更愿意看到完整且与上下文相关的答案,而不是(可能会破坏)其他地方相关答案的链接。跨度> 添加了完整答案 这看起来很有希望。【参考方案5】:
//
public class myService extends InCallService 

    // Here... :)
    @Override public void onCanAddCallChanged(boolean canAddCall) 
    
        super.onCanAddCallChanged(canAddCall);  
    

【讨论】:

【参考方案6】:

要检测是否接到电话,您可以检测“你好”的声音。 “你好”语音是呼叫进度频率之外的频率(语音活动)。作为参考,您可以查看此数据表部分:https://www.cmlmicro.com/products/call-progress-and-voice-detector/

【讨论】:

以上是关于如何检测电话何时被接听或拒绝的主要内容,如果未能解决你的问题,请参考以下文章

接听用户电话问题的系统权限

如何检测非侵入式电话

接受或拒绝来自 iPhone 的蓝牙设备(如智能手表)上的呼叫?

UCMA 如何在遇忙信号和终止信号之前检测呼叫响铃持续时间并转移呼叫?

C# 在 LYNC 中自动接听电话

是否可以在 iOS 模拟器中使用 CallKit 接听电话?