12、电话与通讯集成:TelecomManager API、蓝牙HFP通话、通讯录同步、来电显示与接听

车机上的电话功能,说白了就是让车变成一个大号蓝牙耳机加触控屏。用户上车,手机自动连上,然后就能在车机上打电话、看通讯录、甚至直接点屏幕接听来电。这个体验做得好不好,直接决定了用户对车机系统的第一印象。

我参与过好几个车机互联项目,电话模块永远是用户吐槽最多的地方。不是接听延迟,就是通讯录同步不全,再就是来电显示乱码。嗯,今天我们就来把这些坑一个一个填上。

12.1 TelecomManager API:车机通话的底层管家

TelecomManager 是 Android 系统里管理通话的核心 API。它负责处理电话的接听、挂断、静音、保持等操作。在车机场景下,我们主要用它来做两件事:

  • 监听通话状态:知道当前是空闲、响铃还是通话中
  • 控制通话行为:接听、挂断、切换音频通道

先看怎么获取这个服务:

TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);

获取之后,我们可以注册一个通话监听器:

telecomManager.registerPhoneAccountListener(new PhoneAccountListener() {
    @Override
    public void onCallStateChanged(int state, String phoneNumber) {
        switch (state) {
            case TelecomManager.CALL_STATE_IDLE:
                // 空闲状态
                break;
            case TelecomManager.CALL_STATE_RINGING:
                // 来电响铃
                break;
            case TelecomManager.CALL_STATE_OFFHOOK:
                // 通话中
                break;
        }
    }
});

这里有个细节要注意。我在项目中遇到过,有些车机厂商会定制 TelecomManager 的实现,导致回调不及时。我的建议是:不要完全依赖这个回调来做 UI 更新,最好同时监听蓝牙 HFP 的状态作为补充。

权限警告:使用 TelecomManager 需要声明 android.permission.READ_PHONE_STATEandroid.permission.MANAGE_OWN_CALLS。Android 10 以上还需要动态申请。

12.2 蓝牙HFP通话:音频通道的建立与切换

HFP(Hands-Free Profile)是蓝牙协议里专门用于车载免提通话的规范。车机通过 HFP 与手机建立音频通道,实现语音的上行和下行。

在 Android Automotive 中,蓝牙 HFP 的连接通常由系统服务自动管理。但作为开发者,我们需要知道如何获取 HFP 的状态,以及如何切换音频通道。

获取蓝牙适配器并检查 HFP 连接:

BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothProfile.ServiceListener profileListener = new BluetoothProfile.ServiceListener() {
    @Override
    public void onServiceConnected(int profile, BluetoothProfile proxy) {
        if (profile == BluetoothProfile.HEADSET) {
            BluetoothHeadset headset = (BluetoothHeadset) proxy;
            List<BluetoothDevice> devices = headset.getConnectedDevices();
            // 检查是否有已连接的 HFP 设备
        }
    }

    @Override
    public void onServiceDisconnected(int profile) {
        // 处理断开
    }
};
bluetoothAdapter.getProfileProxy(context, profileListener, BluetoothProfile.HEADSET);

音频通道切换是个容易出问题的地方。我记得有一次,用户接听电话后,声音还是从手机扬声器出来,车机喇叭没响。排查了半天,发现是 HFP 的 SCO(同步面向连接)链路没有正确建立。

我的经验:在接听电话前,先调用 BluetoothHeadset.startVoiceRecognition() 来强制建立 SCO 链路。虽然这个方法名字叫"语音识别",但它实际上就是用来建立 HFP 音频通道的。

12.3 通讯录同步:从手机到车机的数据流转

通讯录同步,说白了就是把手机里的联系人信息搬到车机上。这样用户就能在车机屏幕上直接搜索联系人、拨打电话。

Android Automotive 提供了两种同步方式:

方式 协议 特点
PBAP(Phone Book Access Profile) 蓝牙 自动同步,无需用户操作,但数据量有限
ContentProvider 同步 网络/数据线 数据完整,支持头像、分组,但需要应用配合

PBAP 是车机最常用的方式。车机作为 PBAP Client,手机作为 PBAP Server。连接建立后,车机可以拉取手机上的联系人列表。

在代码层面,我们可以通过 BluetoothMapClient 来获取联系人:

BluetoothMapClient mapClient = new BluetoothMapClient(context, profileListener);
mapClient.getContacts(); // 异步获取联系人列表

但这里有个坑。PBAP 同步回来的联系人数据,通常只包含姓名和电话号码。头像、公司、备注这些信息,很多手机厂商不会同步。我建议在车机端做一个本地缓存,每次同步时做增量更新,而不是全量替换。否则用户可能在开车途中看到通讯录"闪一下"。

核心原则:通讯录同步要快、要稳、要不打扰用户。同步过程应该在后台静默完成,不要在驾驶过程中弹出任何进度条或对话框。

12.4 来电显示与接听:用户体验的最后一步

来电显示和接听,是用户直接感知的功能。做得好,用户觉得"这车机真智能";做得不好,用户觉得"这车机真垃圾"。

来电显示的核心逻辑:

  1. 监听到来电事件(TelecomManager 或 HFP 回调)
  2. 获取来电号码
  3. 在本地通讯录中匹配联系人
  4. 显示联系人姓名、头像(如果有)
  5. 提供接听/挂断按钮

接听操作的代码很简单:

// 接听来电
telecomManager.acceptRingingCall();

// 挂断来电
telecomManager.endCall();

但实际开发中,问题往往出在来电显示的延迟上。我曾经遇到一个情况:电话已经响了 3 秒,车机屏幕才显示出联系人姓名。用户早就拿起手机接了,车机上的接听按钮成了摆设。

为什么会这样?因为通讯录匹配是在车机本地做的,如果通讯录数据量大(比如几千个联系人),匹配过程就会卡顿。

我的优化方案是:

  • 预索引:在通讯录同步完成后,立即建立电话号码的哈希索引
  • 异步匹配:来电时先显示号码,后台匹配到姓名后再更新 UI
  • 缓存热门联系人:最近通话过的联系人,优先匹配
一个小技巧:来电显示时,如果匹配不到联系人,不要显示"未知"两个字。可以显示号码归属地,或者直接显示号码本身。用户看到熟悉的号码,自然知道是谁打来的。

12.5 知识体系总览

下面这张图,是我梳理的电话与通讯集成的整体架构。你可以把它当作一个 roadmap,开发时对照着看,不容易漏掉关键环节。

电话与通讯集成 · 知识体系 手机端(Phone Side) 蓝牙协议层 HFP(通话) | PBAP(通讯录) | MAP(消息) TelecomManager 通话状态监听 接听/挂断控制 蓝牙 HFP SCO音频通道 免提控制 通讯录同步 PBAP/ContentProvider 本地缓存与索引 来电显示与接听 号码匹配 UI交互 车机用户界面(UI) 来电卡片 · 通讯录列表 · 通话控制按钮 · 音频切换

从这张图你可以看到,整个电话与通讯集成分为三层:手机端、蓝牙协议层、车机端。车机端的四个模块各司其职,又相互协作。TelecomManager 负责通话控制,HFP 负责音频通道,通讯录同步提供数据支撑,来电显示与接听则是最终的用户交互出口。

开发时,我建议你从下往上做:先搞定蓝牙连接和 HFP 音频通道,再接入 TelecomManager 监听通话状态,然后做通讯录同步,最后才是来电显示的 UI 交互。每一步都验证通过后,再进入下一步。这样排查问题会轻松很多。

一句话总结:电话与通讯集成,核心就是打通手机到车机的数据流和音频流,让用户在驾驶场景下安全、便捷地使用电话功能。
公众号:蓝海资料掘金营,微信deep3321