【问题标题】: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 }

【问题讨论】:

    标签: android android-studio android-intent telephony


    【解决方案1】:

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

    【讨论】:

    • 真的!在使用 BroadcastReceivers 时发现同样的问题。
    • "在 android 中,无法检测呼叫是否被实际接听(在拨出电话的情况下)。" -- 那么股票拨号器如何检测/显示持续时间?在您方便的时候试试这个:拨打另一个号码 20 秒,然后在您结束时结束通话。对于最后拨打的号码,您的拨号器应显示 0min0secs 持续时间。现在再次拨打电话,但在另一端接听电话 5-10 秒。在您结束通话时,您的拨号器会显示接听电话的持续时间
    • 是的,我已经在我的应用程序 www.callrecorder.cc/app 中彻底测试了这一点 到目前为止,无法检测是否接听了拨出电话。拨出号码后,手机立即进入 OFF_HOOK 状态。
    • 你可以设置一个定时器,从off_hook事件开始。计数 +30 秒,如果通话没有结束,你可以放心地假设它已被接听(如果你愿意,可以终止它,就像这样 stackoverflow.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。说真的,你们中有多少人甚至没有测试过就在 stackoverflow 中发布了这个?
    • @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 没有提供任何解决方案来检测呼叫是否被应答,这是我所做的最好的选择,希望它对你有用。

    【讨论】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-07
        • 1970-01-01
        相关资源
        最近更新 更多