android 之 CALL

一、组件职责与定位

组件 所在进程 核心职责 关键特性
CallsManager Telecom系统进程 通话状态机核心 :管理所有Call对象的生命周期(创建、状态更新、销毁)。监听Call状态变化并通知所有观察者(如InCallController)。 通过mListeners集合维护观察者列表(如InCallControllerRinger等)。
InCallController Telecom系统进程 跨进程通信桥梁 :监听CallsManager的Call事件,绑定InCallService服务(如InCallServiceImpl)。将Call状态封装为ParcelableCall对象传递给UI进程。 通过bindServiceAsUser()绑定InCallService,触发UI进程启动。
InCallPresenter Dialer应用进程 MVP模式中的Presenter :接收InCallService的Call状态更新,控制InCallActivity的创建/销毁。管理子Presenter(如CallCardPresenter)和界面逻辑。 通过InCallAdapter将用户操作(接听/挂断)转发给CallsManager
InCallActivity Dialer应用进程 界面容器 :承载通话UI的Activity,动态加载Fragment(如CallCardFragment)。仅响应界面事件,业务逻辑委托给InCallPresenter 布局仅为FrameLayout,具体UI由Fragment实现。

二、核心交互流程(以去电MO为例)

  1. Call创建与状态同步

    • CallsManager创建Call对象,触发onCallAdded回调。
    • InCallController监听到事件,绑定InCallService服务(跨进程)。
    • 绑定成功后,InCallServiceImpl通知InCallPresenter启动InCallActivity
  2. 界面启动与用户操作

    • InCallPresenter调用startActivity()启动InCallActivity,加载通话UI。
    • 用户点击"拨号"后,InCallPresenter通过InCallAdapter调用CallsManager.placeOutgoingCall()
  3. 底层通话建立

    • CallsManager通过ConnectionService与Modem交互,Call状态变为DIALINGACTIVE
    • 状态变化经InCallController同步至UI进程,触发InCallPresenter更新界面(如显示通话计时)。

用户操作 InCallActivity InCallPresenter InCallAdapter CallsManager InCallController InCallService 点击拨号 onUserAction(拨号) placeOutgoingCall() placeOutgoingCall() 更新Call状态 onCallAdded(Call) addCall(ParcelableCall) onCallAdded() 刷新界面(计时/状态) 用户操作 InCallActivity InCallPresenter InCallAdapter CallsManager InCallController InCallService

三、与Call对象的交互关系

  1. Call的生命周期管理

    • 创建CallsManager在去电/来电时创建Call对象,分配唯一ID。
    • 状态流转 :Call状态(DIALINGRINGINGACTIVE等)由CallsManager驱动,通过setCallState()更新。
    • 销毁 :通话结束时,CallsManager移除Call并触发onCallRemoved
  2. Call数据的跨进程传递

    • InCallController将Call转换为ParcelableCall(可序列化对象),通过Binder传递至UI进程。
    • InCallPresenter解析ParcelableCall,更新界面元素(如联系人姓名、通话时长)。
  3. 用户操作与Call状态联动

    • 接听/挂断等操作通过InCallAdapter回调至CallsManager,后者调用Call.answer()Call.disconnect()
    • 状态变化反向同步至UI,形成闭环(例如挂断后界面关闭)。

四、设计特点与架构价值

  1. 分层解耦

    • 上层(UI层)InCallActivity仅负责渲染,InCallPresenter处理逻辑,符合MVP模式。
    • 下层(服务层)CallsManager专注状态机,InCallController处理跨进程通信。
  2. 跨进程高效同步

    • 通过Binder机制实现Telecom进程与Dialer进程的实时状态同步(ParcelableCall序列化)。
  3. 可扩展性

    • CallsManager的监听器模式支持动态添加组件(如Ringer振铃模块、CallAudioManager音频控制)。
    • InCallPresenter可管理多类子Presenter,适应不同通话场景(如视频通话、会议)。

五、链路

这一架构通过状态驱动CallsManager)与界面逻辑分离(MVP模式)实现高内聚低耦合:

  • 核心链路CallsManager → InCallController → InCallPresenter → InCallActivity 构成状态传递闭环;
  • 交互本质 :Call对象作为载体,在进程间传递状态,驱动UI与底层服务协同。
    其设计充分体现了Android系统服务的模块化思想,为通话功能提供了稳定可扩展的基础。

六、Call 状态

1. DIALING(拨号中)
  • 定义:用户发起呼叫后,系统开始连接对方但尚未接通的阶段。
  • 触发时机
    • 用户拨号后立即进入此状态,无论是否开始响铃。
    • 若需选择通话账户(如VoIP或SIM卡),会先进入SELECT_PHONE_ACCOUNT状态,确认后转为DIALING
  • 行为特征
    • 主叫方听回铃音或等待提示音,被叫方设备未响铃。
    • 若拨号失败(如无信号),会转为DISCONNECTED(连接断开)。
2. RINGING(响铃中)
  • 定义:被叫方收到来电请求,设备开始响铃或震动的状态。
  • 触发时机
    • 主叫方拨号后,被叫方网络收到呼叫请求时触发。
    • 若被叫方正在通话中,此状态可能伴随CALL_WAITING(呼叫等待)提示。
  • 行为特征
    • 被叫方设备响铃,显示来电界面。
    • 主叫方仍处于DIALING状态,直至被叫方接听。
3. ACTIVE(通话中)
  • 定义:双方已建立连接,可实时双向通话。
  • 触发时机
    • 被叫方接听来电后,主被叫双方均进入此状态。
    • HOLDING(通话保持)状态恢复时也会切换至此。
  • 行为特征
    • 通话计时器启动,界面显示通话时长。
    • 支持操作如静音(MUTE)、保持(HOLD)、多方通话等。
4. HOLDING(保持中)
  • 通话被主动暂停(如接听新来电),双方暂时中断语音连接。
  • 界面显示"已保持",恢复后回到ACTIVE
5. DISCONNECTING(断开中)
  • 用户挂断电话后,系统释放资源的中间状态,随后转为DISCONNECTED
6. DISCONNECTED(已断开)
  • 通话完全结束,资源已释放。界面显示挂断提示(如通话时长总结)。
7. CALL_WAITING(呼叫等待)
  • 用户通话中时第三方来电,当前通话保持,新来电进入RINGING状态。
状态转换关系

通话状态的典型生命周期流程如下:
被叫方响应 被叫方接听 用户点击保持 恢复通话 挂断 DIALING RINGING ACTIVE HOLDING DISCONNECTING DISCONNECTED

  • 特殊场景
    • 通话保持时新来电:ACTIVE → HOLDING(原通话) + RINGING(新来电)。
    • 拨号失败:DIALING → DISCONNECTED
各个层的差异
DriverCall.State Call.State(opt/telephony) Connection.State(base/telecomm) CallState(services/Telecomm) Call.State(base/telecomm) Call.State(Dialler)
ACTIVE ACTIVE STATE_ACTIVE ACTIVE STATE_ACTIVE ACTIVE
HOLDING HOLDING STATE_HOLDING ON_HOLD STATE_HOLDING ONHOLD
DIALING DIALING STATE_DIALING DIALING STATE_DIALING DIALING
ALERTING ALERTING RINGALERTING
INCOMING INCOMING STATE_RINGING RINGING STATE_RINGING INCOMING
WAITING WAITING CALL_WAITING
IDLE IDLE
DISCONNECTED STATE_DISCONNECTED DISCONNECTED STATE_DISCONNECTED DISCONNECTED
DISCONNECTING DISCONNECTING STATE_DISCONNECTING DISCONNECTING
STATE_INITIALIZING CONNECTING STATE_CONNECTING CONNECTING
STATE_NEW NEW STATE_NEW
STATE_PULLING_CALL STATE_PULLING_CALL
SELECT_PHONE_ACCOUNT STATE_SELECT_PHONE_ACCOUNT SELECT_PHONE_ACCOUNT
ABORTED STATE_DISCONNECTED DISCONNECTED
STATE_PRE_DIAL_WAIT
INVALID
CONFERENCED
BLOCKED
WAIT_ACCOUNT_RESPONSE

七、MT 与 MO

在Android通话系统中,MO(Mobile Originated,移动始发)和MT(Mobile Terminated,移动终止) 分别指代用户主动拨打电话(主叫)和接听来电(被叫)的流程。

1. MO(去电流程)

定义 :用户主动发起呼叫的过程,即"拨打电话"。
核心步骤

  1. 拨号触发 :用户在Dialer应用的拨号界面(DialpadFragment)点击拨号按钮,通过Intent.ACTION_CALL发起请求。
  2. 权限检查
    • 系统检查CALL_PHONE权限及默认拨号器身份(TelecomUtil.hasCallPhonePermission())。
    • 紧急呼叫(如ACTION_CALL_EMERGENCY)绕过权限限制。
  3. Telecom服务处理
    • TelecomServiceImpl.placeCall()验证号码合法性,并通过CallsManager创建通话对象(Call)。
  4. UI启动与状态更新
    • 系统启动InCallActivity,根据通话状态(如DIALING)显示拨号界面。
    • 底层Modem返回DIALING状态后,界面更新为拨号中。
  5. 呼叫建立
    • 被叫方接听后,状态转为ACTIVE,通话计时开始。

流程图简化

2. MT(来电流程)

定义 :用户接收来电并接听的过程,即"接听电话"。
核心步骤

  1. 来电通知
    • Modem检测到来电,通过RIL层上报RINGING状态至CallsManager
  2. 铃声与震动
    • CallNotifier调用Ringer播放铃声(非DIALING状态独有)。
  3. UI启动
    • 系统启动InCallActivity,显示来电界面(如联系人信息、接听/挂断按钮)。
  4. 用户响应
    • 接听:状态转为ACTIVE,建立双向通话。
    • 拒接:状态转为DISCONNECTED

流程图简化
接听 拒接 Modem上报来电 Ringer播放铃声 启动InCallActivity 显示RINGING界面 用户操作 ACTIVE状态 DISCONNECTED

3. MO与MT的核心区别
维度 MO(主叫) MT(被叫)
触发起点 用户主动拨号 网络侧下发来电请求
关键状态 DIALING(拨号中) RINGING(响铃中)
系统组件 DialpadFragment触发Intent RIL/CallsManager检测来电状态
特殊处理 紧急呼叫权限绕过 铃声播放(Ringer
VoLTE角色 主叫UE构造SIP INVITE 被叫S-CSCF触发业务逻辑(如彩铃)
注意点
  • MO :用户拨号 → 权限检查 → Telecom处理 → 界面显示DIALING → 通话建立(ACTIVE)。
  • MT :网络下发来电 → 播放铃声 → 界面显示RINGING → 用户接听(ACTIVE)或拒接(DISCONNECTED)。
    本质差异 在于触发源 (用户主动 vs. 网络被动)和核心状态DIALING vs. RINGING)。理解两者区别对开发通话功能、优化用户体验及设计测试用例至关重要。
相关推荐
阿巴斯甜16 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker17 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq952718 小时前
Andorid Google 登录接入文档
android
黄林晴19 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab1 天前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿1 天前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_2 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android