如何检测电话何时被接听或拒绝
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 的蓝牙设备(如智能手表)上的呼叫?