本文主要讲解IP Multimedia Subsystem (IMS)在Android 7.0上由谷歌Android实现的部分内容。
从APP侧一直到Telephony Framework,是不区分CS流程还是PS流程的。到了Telephony Framework模块,会依据IMS相关的状态信息(Registration Status,Service Status等)和用户设置信息(Volte Enable?Wifi Calling Enable?UT Enable?等 )进而判断出,Call、SMS等是否需要优先走IMS的流程。
整体来看,IMS框架如下图:

通常都是由Phone对象或者ImsPhoneCallTracker对象直接得到ImsManager对象

mImsManager = ImsManager.getInstance(mPhone.getContext(), mPhone.getPhoneId());

接着再通过ImsManager对象间接地得到ImsConfig、ImsUt、ImsCall等重要对象,然后根据请求不同而走不同的通道与Vendor RIL通信,与Call相关的走ImsCall,与补充业务相关的走ImsUt,与IMS功能的能力、参数相关的走ImsConfig,所以分工是十分明确的。谷歌为了规范高通/MTK等芯片厂商的行为,所以定义了IImsService、IImsConfig、IImsCallSession和IImsUt等接口,再由各芯片厂商来实现这些接口,谷歌只需要处理好上层调用接口的逻辑即可。

接下来分别讲一下各个类

ImsPhone

ImsPhone是为了与CS Call区分开,用来处理IMS相关事务的Phone实例,以setCallWaiting为例:

    public void setCallWaiting(boolean enable, Message onComplete) {
if (isPhoneTypeGsm()) {
Phone imsPhone = mImsPhone;
//判断是否符合IMS的条件
if ((imsPhone != null)
&& ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
|| imsPhone.isUtEnabled())) {
//走IMS流程
imsPhone.setCallWaiting(enable, onComplete);
return;
}
//走CS流程
mCi.setCallWaiting(enable, CommandsInterface.SERVICE_CLASS_VOICE, onComplete);
} else {
loge("method setCallWaiting is NOT supported in CDMA!");
}
}

然而仅仅有Phone实例是不够的,还需要有对应地CallTracker、Call以及Connection对象,所以就有了下面这张图:

ImsPhone实例是在IMS Service启动之后被创建的,接着会初始化ImsPhoneCallTracker对象。

ImsPhoneCallTracker

ImsPhoneCallTracker在初始化的时候会注册监听IMS InComing call

intentfilter.addAction(ImsManager.ACTION_IMS_INCOMING_CALL);

同时将Action为“ACTION_IMS_INCOMING_CALL”的PendingIntent传递给IMS Service,这样子就可以监听到IMS MT Call了。

ImsPhoneCallTracker内部会初始化四个ImsPhoneCall对象,

    public ImsPhoneCall mRingingCall = new ImsPhoneCall(this, ImsPhoneCall.CONTEXT_RINGING);
public ImsPhoneCall mForegroundCall = new ImsPhoneCall(this,ImsPhoneCall.CONTEXT_FOREGROUND);
public ImsPhoneCall mBackgroundCall = new ImsPhoneCall(this,ImsPhoneCall.CONTEXT_BACKGROUND);
public ImsPhoneCall mHandoverCall = new ImsPhoneCall(this, ImsPhoneCall.CONTEXT_HANDOVER);

比GsmCdmaCallTracker多了一个Handover Call,比如VoWiFi与VoLTE相互切换就是通过Handover来实现的。

还有一点ImsPhoneCallTracker与GsmCdmaCallTracker不一样的就是

    protected void handlePollCalls(AsyncResult ar) { }

ImsPhoneCallTracker的handlePollCalls()方法是空的,是因为IMS Call状态消息的上报和获取modem当前Call List信息等这些逻辑需要高通/MTK来实现,ImsPhoneCallTracker则通过ImsCall.Listener来监听Ims Call的状态变化信息,然后再根据ImsCall的状态,更新当前ImsPhoneConnection与四种ImsPhoneCall的绑定关系。
比如:
1. A<—>B正在通话,这通电话对应的Connection会与mForegroundCall绑定;
2. 此时A再呼叫C,那么A<—>B这通电话的Connection就会先与mBackgroundCall绑定,这种切换是由mBackgroundCall与mForegroundCall互换Connection集合和状态实现的;

mForegroundCall.switchWith(mBackgroundCall);

3.然后A<—>C接通之后,A<—>C这通电话对应的Connection会与mForegroundCall绑定。
就是这样子。每个ImsPhoneCall最多绑定5个ImsPhoneConnection,这个值规定在ImsPhoneCallTracker中:

static final int MAX_CONNECTIONS_PER_CALL = 5;

ImsPhoneCallTracker还负责监听IMS service的状态变化

private ImsConnectionStateListener mImsConnectionStateListener =
new ImsConnectionStateListener() {
//IMS已注册上
public void onImsConnected() {}
//IMS已断开,有时候会上报断开的原因
public void onImsDisconnected(ImsReasonInfo imsReasonInfo) {}
//IMS处于正在注册状态
public void onImsProgressing() {}
//"VoLTE", "ViLTE", "VoWiFi", "ViWiFi",
//"UTLTE", "UTWiFi"等功能的能力变化
public void onFeatureCapabilityChanged() {}
......
}

如果遇到IMS注册不上的问题,应该去看IMS注册时的SIP信令流程。

ImsManager

ImsManager作为IMS框架的核心,是任意IMS action的出发点。ImsManager的职责主要有以下3点:
1. 向上提供ImsConfig、ImsUt、ImsCall等重要对象,得到这些对象就可以跟Vendor RIL通信了。

 public ImsUtInterface getSupplementaryServiceConfiguration(){}
public ImsConfig getConfigInterface(){}
public ImsCall makeCall(){}

2 .向APP提供设置IMS相关功能的接口

//设置VoLTE打开或者关闭
public static void setVtSetting(Context context, boolean enabled) {}
//设置WiFi Calling打开或者关闭
public static void setWfcSetting(Context context, boolean enabled) {}
//设置WiFi Calling的模式,如WiFi Only、WiFi优先...
public static void setWfcMode(Context context, int wfcMode) {}
//设置4G LTE增强模式打开或者关闭
public static void setEnhanced4gLteModeSetting(Context context, boolean enabled) {}

3.向上传递IMS注册状态变化的消息,是由ImsManager来通知ImsPhoneCallTracker的。

ImsService

谷歌定义好了ImsServiceBase抽象类和IImsService接口,接着由芯片厂商实现ImsService。
ImsConfig、ImsUt、ImsCall等对象最终是依靠ImsService来创建的,
由此可见,其他三种通信方式都是依赖着ImsService的。

ImsManager—>ImsService—>Vendor RIL
这种通信方式主要用来通知modem turn on/off Ims。
使用场景就是在VoLTE、WFC和Advanced4GMode等功能被用户手动enable/disable时,就要响应地通知modem turn on/off Ims了。

ImsConfig

ImsManager—>ImsConfig—>Vendor RIL
ImsConfig主要就是提供接口给上层动态地去控制IMS功能的能力、参数等。
ImsConfig类中虽然只有7个方法,但是功能强大,特别是下面几个方法

public int getProvisionedValue();
public int setProvisionedValue();
public String getProvisionedStringValue();
public int setProvisionedStringValue();

这些方法为开发者打开了一扇大门!通向底层NV的大门!(不同芯片厂商可能有差异)比如,在UI界面上点击了打开WFC的按钮,就可以间接地修改到NV的某一项。
目前Android 7.0中支持的NV只有几十个,但是这并不能满足OEM所有的需求,所以有时候还需扩展这个接口。

还有就是,如果要开发IMS接口的话,建议也是加在这里,其他通道都不太合适。

ImsCall

ImsManager—>ImsCall—>ImsCallSession—>Vendor RIL
这个就很明显了,这条通道是专门处理IMS Call相关事务的,创建ImsCall的方式有两种:
1. IMS MO Call时,通过ImsManager.makeCall()来创建;
2. IMS MT Call时,通过ImsManager.takeCall()来创建。
在ImsCall中,每个对Call操作的方法(accept/reject/hold/resume/merge等等)都会有对应的回调方法:

    /**
* @see Listener#onCallResumed, Listener#onCallResumeFailed
*/
public void resume(){
......
}

如果resume成功则通过onCallResumed()方法通知上层,如果resume失败则通过onCallResumeFailed()方法通知上层,一般的流程如下:

ImsUt

ImsManager—>ImsUt—>Vendor RIL
这条通道是专门提供向上提供设置补充业务接口的,如呼叫转移、呼叫限制、呼叫等待、outgoing Caller Id display等等。

最后,更多关于IMS的内容,请查阅如下协议文档:
- GSMA IR.92 : features for voice and sms profile
- GSMA IR.94 : video calling feature
- 3GPP TS 24.229 : IMS call control (SIP and SDP)
- 3GPP TS 26.114 : IMS media handling and interaction
- 3GPP TS 26.111 : Codec for CS multimedia telephony service (H.324)
- 3GPP TS 24.623 : XCAP over the Ut interface for manipulating supplementary services

————————————————
版权声明:本文为CSDN博主「linyongan」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/linyongan/article/details/53350493

Android 7.0 IMS框架详解的更多相关文章

  1. android 6.0 权限设置详解

    从Android 6.0版本开始,在安装应用时,该应用无法取得任何权限. 相反,在使用应用的过程中,若某个功能需要获取某个权限,系统会弹出一个对话框,显式地由用户决定是否将该权限赋予应用. 只有得到了 ...

  2. [转]Android 5.0——Material Design详解(动画篇)

    Material Design:Google推出的一个全新的设计语言,它的特点就是拟物扁平化. Material Design包含了很多内容,今天跟大家分享一下Material新增的动画: 在Andr ...

  3. OAuth 2.0授权框架详解

    目录 简介 OAuth的构成 refresh Token Authorization Code模式 隐式授权 Resource Owner 授权密码认证 Client 认证授权 github的OAut ...

  4. Android 常用的ORM框架详解

    1. OrmLite OrmLite 不是 Android 平台专用的ORM框架,它是Java ORM.支持JDBC连接,Spring以及Android平台.语法中广泛使用了注解(Annotation ...

  5. Android EventBus 3.0 实例使用详解

    EventBus的使用和原理在网上有很多的博客了,其中泓洋大哥和启舰写的非常非常棒,我也是跟着他们的博客学会的EventBus,因为是第一次接触并使用EventBus,所以我写的更多是如何使用,源码解 ...

  6. Spark2.1.0——内置Web框架详解

    Spark2.1.0——内置Web框架详解 任何系统都需要提供监控功能,否则在运行期间发生一些异常时,我们将会束手无策.也许有人说,可以增加日志来解决这个问题.日志只能解决你的程序逻辑在运行期的监控, ...

  7. Spark2.1.0——内置RPC框架详解

    Spark2.1.0——内置RPC框架详解 在Spark中很多地方都涉及网络通信,比如Spark各个组件间的消息互通.用户文件与Jar包的上传.节点间的Shuffle过程.Block数据的复制与备份等 ...

  8. Android图片缓存之Bitmap详解

    前言: 最近准备研究一下图片缓存框架,基于这个想法觉得还是先了解有关图片缓存的基础知识,今天重点学习一下Bitmap.BitmapFactory这两个类. 图片缓存相关博客地址: Android图片缓 ...

  9. Android 之窗口小部件详解--App Widget

    Android 之窗口小部件详解--App Widget  版本号 说明 作者 日期  1.0  添加App Widge介绍和示例  Sky Wang 2013/06/27        1 App ...

随机推荐

  1. DELPHI常用类型及定义单元

    Controls Application (the variable not a type) Forms Beep SysUtils or Windows (different functions) ...

  2. AcWing 201. 可见的点 (欧拉函数打表)打卡

    在一个平面直角坐标系的第一象限内,如果一个点(x,y)与原点(0,0)的连线中没有通过其他任何点,则称该点在原点处是可见的. 例如,点(4,2)就是不可见的,因为它与原点的连线会通过点(2,1). 部 ...

  3. 使用 windsor 实现IOC 和 AOP

    代码很简单,不多说. 对于拦截,windsor 使用动态代理的方式,即生成继承类的方式来实现的,因此无法拦截private 方法,因为无法在继承类中看见private方法. using System; ...

  4. git clone慢的解决办法

    转自:http://www.kindemh.cn/ 转自Kindem的博客 问题 大家可能都遇到过从github使用git clone指令奇慢无比的问题,网上很多人说使用代理来加速git,但是这也不是 ...

  5. 1、Monkey环境搭建

    步骤: 1.下载adb压缩包: 32位计算机,用这个包:64位计算机,用这个包: 2.把对应的adb压缩包在本地解压,然后把解压后的文件里面的文件夹拷贝到D盘(当然随便你放在哪个目录)根目录,注意路径 ...

  6. webpack中引用Element-ui

    1.下载element-ui npm i element-ui --production 2.在main.js中引用 import Element from 'element-ui' import ' ...

  7. 拾遗:Git 常用操作回顾

    温故而知新,可以为师矣. Git 布局 工作区---->暂存区---->本地仓库---->远程仓库 Create Repository git init PATH git add P ...

  8. 前端(十三)—— JavaScript高级:回调函数、闭包、循环绑定、面向对象、定时器

    回调函数.闭包.循环绑定.面向对象.定时器 一.函数高级 1.函数回调 // 回调函数 function callback(data) {} // 逻辑函数 function func(callbac ...

  9. 如何在react中实现一个倒计时组件

    倒计时组件 import React, { Component } from 'react' import $ from 'jquery' import "../../css/spellTE ...

  10. 将一个压缩文件分成多个压缩文件;RAR文件分卷

    有时候需要上传压缩文件,但是限制了单个文件的大小,那我们怎么才能将一个比较大的压缩文件分割成多个压缩文件,从而符合要求的进行文件的上传呢?这里小编告诉你一个技巧. 工具/原料 电脑 winrar(一般 ...