使用android.telecom和InCallService接听来电

22
自API 21以来,Google一般会为android.telecom添加功能,特别是通过实现TelecomManager的更多成员和添加InCallService来实现。这个最后一个应该允许非系统第三方应用程序提供并替换系统通话应用程序中的呼叫屏幕的功能-弹出窗口并允许针对 EXTRA_STATE_OFFHOOK 或 EXTRA_STATE_RINGING 广播(即传入和传出电话)进行操作。

目前,只有此屏幕通过受限的根权限MODIFY_PHONE_STATE和许多安全的AOSP代码才能对响铃、活动通话和相关的系统回调进行细粒度信息的完全控制,甚至无法通过反射来访问。与启动器、联系人和相机一起,这是不同制造商ROM版本中最常更改的代码之一。

尽管如此,...

你究竟如何开发第三方InCallService?

换言之:

  1. 你如何被通知并获取GSM通话实例
  2. 如何接听这些通话
  3. 这个类中回调的生命周期是什么
  4. 谷歌是否提供了任何实际的教程

我不会一次性询问所有这些问题,但任何一个答案可能都与其他问题相关联。这很广泛,但本质上需要:我在网上找不到除AOSP代码以外的任何示例,而该代码基于root权限的假设,因此对于第三方应用程序开发目的而言无法使用。


对于您的问题#1,android.intent.action.PHONE_STATE广播不起作用吗? - Sharp Edge
@SharpEdge,你会收到“来电”通知,但你不知道是哪个android.telecom.Call - https://developer.android.com/reference/android/telecom/Call.html 有了这样的实例,我可以直接使用Call#answer(int videoState)并解决问题。 - leRobot
似乎没有太多相关信息 - 但是这个问题中的评论可能会有所帮助:https://dev59.com/DFsW5IYBdhLWcg3winvt。需要注意的一件事,以防不清楚 - 这个API是用来替换InCallUI的,即控制通话的用户界面。 - Mick
@Mick,没错,问题不是很多,所以我才发帖问。我非常清楚API的目的是替换InCallUI。但问题是,根据我所能看出的,API并没有提供实现这一点的手段。你所提出的问题与我类似,而且很可能也会被视为过于宽泛而被关闭...另一个小伙子跟我差不多两天前就问了同样的问题,甚至我还特地检查了一下看是否是自己发的帖子,但他不是我:P! - leRobot
4个回答

13

如何获取并通知您有关GSM呼叫实例的信息

首先,用户需要将您的应用程序选择为默认电话应用程序。请参考在Android 6和7上使用InCallService替换默认的电话应用程序来完成此操作。

您还需要定义一个InCallService实现,系统将绑定并通知您有关呼叫的情况:

<service
    android:name=".CallService"
    android:permission="android.permission.BIND_INCALL_SERVICE">
    <meta-data
        android:name="android.telecom.IN_CALL_SERVICE_UI"
        android:value="true" />
    <intent-filter>
        <action android:name="android.telecom.InCallService" />
    </intent-filter>
</service>

您至少需要处理 onCallAdded(在Call上设置侦听器并为通话启动您的UI - 活动 -)和 onCallRemoved(删除侦听器)。

如何接听这些电话

如果用户想要接听电话,您需要使用Call#answer(int)方法,并提供例如VideoProfile.STATE_AUDIO_ONLY参数。

此类回调的生命周期是什么

查看Call.Callback,以获取可能发生在单个通话中的事件。

Google是否提供了任何实际教程,我没找到?

我不了解Google是否提供了相关教程,但您可以查看我简化的示例https://github.com/arekolek/simple-phone


1
花了一些时间下载了示例,在Android Nougat设备上运行它(也应该适用于Marshmallow),弹出一个窗口询问是否替换拨号器(ACTION_CHANGE_DEFAULT_DIALER),接收了一个外拨电话,按下接受键,正常工作。默认的(三星)拨号器没有显示。 - leRobot
2
@arekolek,不替换系统UI的情况下,可以使用INCALL SERVICE(您在Github上的示例)吗? - pudnivec74
1
@pudnivec74,你不需要使用InCallService - arekolek
1
@pudnivec74,那么您需要来自TelecomManager的更新API:acceptRingingCall()endCall()silenceRinger()。就像我说的那样,您应该提出一个单独的问题,因为它与这个答案完全无关。 - arekolek
1
@arekolek和团队,我想保留Android的用户界面(UI),但仍然能够得到回调。我希望完全重用Android的拨号器UI,但只控制回调。怎么做? - j2emanue
显示剩余16条评论

5

请按照第二个评论的建议来操作Replacing in call app。此外,您需要使用实现InCallService接口的服务。当一个电话到来时,将调用onCallAdded(Call call)方法,然后您可以获得对该电话对象的引用。

<service
  android:name=".InCallServiceImplementation"
  android:enabled="true"
  android:exported="true"
  android:permission="android.permission.BIND_INCALL_SERVICE">

  <meta-data
    android:name="android.telecom.IN_CALL_SERVICE_UI"
    android:value="true" />

  <intent-filter>
    <action android:name="android.telecom.InCallService" />
  </intent-filter>
</service>

一旦你有了呼叫对象,回答它就像简单的call.answer()一样。我建议在你完成上述工作时,运行几个测试呼叫以了解不同回调被调用的时间。

关于教程,当我研究这个问题时,我找不到任何教程,但那已经是一年前的事了...

希望这能帮到你!


好的,我会尝试今天进行测试实现,并带着结果回来。 - leRobot
你好IeRobot,你尝试过使用InCallService了吗?在我的情况下,服务无法被调用到来电和去电。 - rajahsekar
有什么办法可以在不让手机震动的情况下使用此服务拒绝来电吗? - Mateen Chaudhry

3
我猜谷歌一定看到了这个问题,因为在Android 8上,一个新的权限ANSWER_PHONE_CALLS终于允许第三方开发者以编程方式回答电话。

android.permission.ANSWER_PHONE_CALLS (...) 允许应用程序以编程方式回答来电

目前还没有详细信息,因为API 26的文档尚未发布。当他们发布时,我会确保更新这个答案。

编辑:用户arekolek提供了一个完美的答案,适用于原始API版本的这个问题(在问API的时候,API是23,即使问题提到了API 21),因此他得到了正确答案的标记。如果您想实现最低SDK为23的呼入屏幕,请参考他的答案。请注意,如果您希望它在更近期的API上工作,需要API相关代码或兼容库调整,这些API已经废弃(或限制)使用提供的示例代码。该github仓库的工作方式与我最初的意图相同。


这个回答与主题无关。如果您正在实现“InCallService”,则不需要该API,您可以使用API 23来接听电话。 - arekolek
请随意改进或添加答案,我已不再关注此主题,因此无法抽出时间来改进自己的问题答案。据我所知,您只能接听Oreo(26)及以上版本的电话,而不能接听Marshmallow。请参见https://developer.android.com/reference/android/telecom/TelecomManager.html#acceptRingingCall() - “在api级别26中添加”。此外,“extends InCallService”的简单谷歌搜索很好地展示了事物的状态... - leRobot
2
我的理解是acceptRingingCall()可以让你告诉Android接听电话,而不成为默认的电话应用程序。另外,据我所知,我链接到的存储库中使用的API都没有在更高级别的API上被弃用或限制。 - arekolek

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接