本文将结合前面五篇文章所讲解的知识,综合起来,实现一个接口扩展的功能。
如果还没有阅读过前面五篇文章的内容,请先阅读:
《Android Telephony分析(一) — Phone详解 》
《Android Telephony分析(二) — RegistrantList详解 》
《Android Telephony分析(三) — RILJ详解 》
《Android Telephony分析(四) — TelephonyManager详解 》
《Android Telephony分析(五) — TelephonyRegistry详解 》

至于接口扩展,也就是新增一个接口给APP调用,从APP至RIL,大体流程如下:

1. 发送请求的实现
1.1 扩展BaseCommands接口

扩展BaseCommands接口主要为了在RIL.java 中实现向modem发送请求的方法。
RILJ的继承关系如下:

所以要在RILJ中新增一个向modem发送Request的方法,需要扩展BaseCommands,再在RIL.java重写该方法。
在BaseCommands.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)添加一个方法:

    public void setValueToModem(int input,Message response) {
//这个方法为空,由让子类按需要去重写
}

在RILConstants.java (frameworks\base\telephony\java\com\android\internal\telephony)中新增一个主动请求的消息:

    //200这个数字需要根据实际项目进行修改
int RIL_REQUEST_SET_VALUE = 200;

在RIL.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)中新增发送请求的方法:

    @Override
public void setValueToModem(int input,Message response) {
//得到一个RILRequest对象
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_SET_VALUE, response);
//将APP传递过来的参数放到RILRequest对象中
rr.mParcel.writeInt(input);
//输出关键log
if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest)
+ " " + input); send(rr);
//for test
//response.sendToTarget();
}

至于RILC的扩展省略,调试为了这个接口是否可用,故意写了
response.sendToTarget();这行代码用于调试。

1.2 扩展PhoneInternalInterface接口

扩展PhoneInternalInterface接口主要为了封装RILJ的方法,只要得到Phone的实例即可间接调用RILJ的方法。
Phone的继承关系如下:

Phone.java是整个关系的中心枢纽,所以假如不用针对ImsPhone而走IMS流程的话,我们可以扩展PhoneInternalInterface接口,然后在Phone.java中具体实现即可。
先在PhoneInternalInterface.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)中新增一个接口:

    void setValueToModem(int value);

在Phone.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)统一实现该接口,Phone所有子类都使用这个方法:

    @Override
public void setValueToModem(int input){
//对于回调事件的处理,第2小节再讲
Message resp = obtainMessage(EVENT_SET_VALUE_DONE,0,0);
//直接调用RILJ中的方法
mCi.setValueToModem(input,resp);
}

1.3 扩展ITelephony接口

扩展ITelephony接口主要是为了进一步封装Phone对象中的方法,让那些不能直接得到Phone对象的类也可以间接地调用Phone对象中的方法
先在ITelephony.aidl(frameworks\base\telephony\java\com\android\internal\telephony)中新增一个接口:

    void setValueToModem(int input);

在PhoneInterfaceManager.java (packages\services\telephony\src\com\android\phone)中实现该接口:

    @Override
public void setValueToModem(int input){
try{
//得到Phone对象
Phone phone = PhoneFactory.getDefaultPhone();
if(phone != null){
phone.setValueToModem(input);
}
}catch(IllegalStateException e){ }
}

由于PhoneInterfaceManager运行在Phone进程中,所以还需进一步封装,让不运行在Phone进程中的类也可以调用
在TelephonyManager.java (frameworks\base\telephony\java\android\telephony)中封装Phone Service的方法:

    /** @hide */
public void setValueToModem(int input){
try {
//得到PhoneInterfaceManager的代理对象
ITelephony telephony = getITelephony();
if (telephony != null){
telephony.setValueToModem(input);
}
} catch (RemoteException ex) { } catch (NullPointerException ex) { }
}

从RILJ—>Phone—>PhoneInterfaceManager—>TelephonyManager,经过一层层的封装,APP终于可以通过TelephonyManager来间接调用RILJ中的方法了。
整个过程的时序图如下:

2. 返回结果的实现
2.1 RILJ中的处理

在RILJ向modem发送请求之后,modem处理完会上报Solicited Response消息并且附带着结果
所以我们需要在RIL.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)的processSolicited()方法中增加

    case RIL_REQUEST_SET_VALUE:      ret = responseInts(p); break;

在requestToString方法中增加

    case RIL_REQUEST_SET_VALUE: return "RIL_REQUEST_SET_VALUE";

2.2 Phone中的处理

在《Android Telephony分析(三) — RILJ详解 》的2.2.1小节中我们说过,接着会通过rr.mResult.sendToTarget();返回到创建Message对象的地方,也就是上面1.2小节说到的
在Phone.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)中:

    @Override
public void setValueToModem(int input){
//对于回调事件的处理,第2小节再讲
Message resp = obtainMessage(EVENT_SET_VALUE_DONE,0,0);
//直接调用RILJ中的方法
mCi.setValueToModem(input,resp);
}

还需要对于回调事件进行处理,也就是先在Phone.java中定义EVENT_SET_VALUE_DONE消息:

    //100这个数字需要根据实际项目进行修改
protected static final int EVENT_SET_VALUE_DONE = 100;
protected static final int EVENT_LAST =EVENT_SET_VALUE_DONE;

接着在handleMessage()方法中增加对EVENT_SET_VALUE_DONE的处理:

            case EVENT_SET_VALUE_DONE:
//取出返回结果
ar = (AsyncResult)msg.obj;
String result = null;
//如果返回结果不为空且没有异常
if (ar != null && ar.exception == null) {
result = "success";
}else{
result = "fail";
}
//其实最偷懒的方式是直接在这里发广播通知APP,
//但是为了结合我们学过的知识,我还是通过PhoneNotifier来实现
mNotifier.notifySetValueDone(result);
break;

2.3 扩展PhoneNotifier接口

扩展PhoneNotifier接口主要为了进一步上报消息并且附带这结果。PhoneNotifier的常用子类是DefaultPhoneNotifier。
先在PhoneNotifier.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)中新增一个接口:

    public void notifySetValueDone(String result);

接着在DefaultPhoneNotifier.java (frameworks\opt\telephony\src\java\com\android\internal\telephony)中实现该接口:

    @Override
public void notifySetValueDone(String result){
try {
if (mRegistry != null) {
//需要依赖TelephonyRegistry进一步上报通知
mRegistry.notifySetValueDone(result);
}
} catch (RemoteException ex) {
ex.printStackTrace();
}
}

2.4 扩展ITelephonyRegistry接口

先在ITelephonyRegistry.aidl(frameworks\base\telephony\java\com\android\internal\telephony)中新增接口:

    void notifySetValueDone(String result);

在TelephonyRegistry.java (frameworks\base\services\core\java\com\android\server)中实现该接口:

    @Override
public void notifySetValueDone(String result){
synchronized (mRecords) {
for (Record r : mRecords) {
//通知所有监听了LISTEN_SET_VALUE_DONE的类
if((r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SET_VALUE_DONE))){
try {
r.callback.onSetValueDone(result);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
handleRemoveListLocked();
}
}

2.5 扩展IPhoneStateListener接口

扩展IPhoneStateListener接口主要为了新增一个可以监听的事件LISTEN_SET_VALUE_DONE。通过APP事先监听,当有该事件上报的时候,就会通知到APP。
先IPhoneStateListener.aidl(frameworks/base/telephony/java/com/android/internal/telephony)中新增接口:

    void onSetValueDone(String result);

在PhoneStateListener.java (frameworks\base\telephony\java\android\telephony)中新增可监听的事件,并且初步实现接口中的方法

    /** @hide */
//这个数字按项目实际需要修改
public static final int LISTEN_SET_VALUE_DONE = 0x00800000; /** @hide*/
public void onSetValueDone(String result){
//由子类来重写
}

在IPhoneStateListener callback = new IPhoneStateListener.Stub()中新增:

        public void onSetValueDone(String result){
Message.obtain(mHandler, LISTEN_SET_VALUE_DONE, 0, 0, result).sendToTarget();
}

在handleMessage中新增:

    case LISTEN_SET_VALUE_DONE:
//调用子类重写的方法,也就是APP中的方法
PhoneStateListener.this.onSetValueDone((String)msg.obj);
break;

到这里,从RILJ—>Phone—>DefaultPhoneNotifier—>TelephonyRegistry—>APP,消息和结果就上报到APP了。
整个过程的时序图如下(步骤10~15):

3. APP如何使用接口

在APP中可以这样调用并调试接口:

    //监听事件
TelephonyManager.getDefault().listen(new PhoneStateListener(){
@Override
public void onSetValueDone(String result){
//对结果进行处理
}
}, PhoneStateListener.LISTEN_SET_VALUE_DONE);
//发送请求
TelephonyManager.getDefault().setValueToModem(1);

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

Android Telephony分析(六) ---- 接口扩展(实践篇)的更多相关文章

  1. Android Telephony分析(七) ---- 接口扩展(异步转同步)

    本文是基于上一篇<Android Telephony分析(六) —- 接口扩展(实践篇)>来写的.上一篇介绍的接口扩展的方法需要实现两部分代码:1. 从APP至RIL,发送请求:2. 从R ...

  2. Android Telephony分析(五) ---- TelephonyRegistry详解

    本文紧接着上一篇文章<Android Telephony分析(四) —- TelephonyManager详解 >的1.4小节.从TelephonyRegistry的大部分方法中: 可以看 ...

  3. Android Telephony分析(三) ---- RILJ详解

    前言 本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程.这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\andro ...

  4. Android Telephony分析(二) ---- RegistrantList详解

    前言 本文主要讲解RegistrantList的原理,以及如何快速分析RegistrantList相关的代码流程.在Telephony模块中,在RIL.Tracker(ServiceStateTrac ...

  5. Android Telephony分析(四) ---- TelephonyManager详解

    前言 TelephonyManager主要提供Telephony相关信息的查询/修改功能,以及Phone状态监听功能,封装的方法主要是提供给APP上层使用.TelephonyManager.java ...

  6. Android Telephony分析(一) ---- Phone详解

    目录: Phone的继承关系与PhoneFactory(GsmCdmaPhone.ImsPhone.SipPhone) Phone进程的启动 Phone对象的初始化(DefaultPhoneNotif ...

  7. Android架构分析之使用自定义硬件抽象层(HAL)模块

    作者:刘昊昱 博客:http://blog.csdn.net/liuhaoyutz Android版本:2.3.7_r1 Linux内核版本:android-goldfish-2.6.29 在上一篇博 ...

  8. Android Launcher分析和修改8——AllAPP界面拖拽元素(PagedViewWithDraggableItems)

    接着上一篇文章,继续分析AllAPP列表界面.上一篇文章分析了所有应用列表的界面构成以及如何通过配置文件修改属性.今天主要是分析PagedViewWithDraggableItems类,因为在我们分析 ...

  9. 使用Typescript重构axios(十一)——接口扩展

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

随机推荐

  1. PHP面试 MySQL查询优化

    MySQL查询优化 面试题一 请简述项目中优化SQL语句执行效率的方法,从那些方面,SQL语句性能如何分析? 优化查询过程中的数据访问.优化长难的查询语句.优化特定类型的查询语句 分析SQL语句方法 ...

  2. java 重新学习 (二)

    一.栈内存里的引用变量并未真正存储对象的成员变量,对象的成员变量数据实际存放在堆内存中,而引用变量只是指向该堆内存里的对象. 二.堆内存里的对象可以有多个引用,若果堆内存中没有变量指向该对象,程序无法 ...

  3. mySQL学习入门教程——2.创建表

    二.创建表 一.创建数据表的SQL语句模型(弱类型)CREATE TABLE [IF NOT EXISTS] 表名称(字段名1 列的类型[属性][索引],字段名2 列的类型[属性][索引],-字段名n ...

  4. Inversion of Control 控制反转 有什么好处

    作者:Mingqi链接:https://www.zhihu.com/question/23277575/answer/169698662来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转 ...

  5. 使用vue.js开发小程序

    写在前面 刚刚开源的mpvue引起了不少前端er们的注意,下图是一个简单的对比. 话不多说,我们现在感受一下如何使用mpvue开发小程序.(以下内容参照mpvue文档完成). 开发环境 node np ...

  6. java爬取猫咪上的图片

    首先是对知识点归纳 1.用到获取网页源代码,分析图片地址,发现图片的地址都是按编号排列的,所以想到用循环获取 2.保存图片要用到流操作和文件操作,对两部分知识进行了复习巩固 3.保存后的图片有一部分是 ...

  7. MySQL中orderby和limit分页数据重复的问题

    背景 读取规则是按照某表中sequence字段排序的,而这个字段是让人手工填写的.那么,可想而知,数据一多,难免会出现填写的值相同的情况. 综上所述,可能就会导致以下两条sql出现数据重叠的情况: s ...

  8. Asp.net Controller中View 和Action方法认证Authorize 及对AuthorizeAttribute扩展

    Asp.net Controller中View和Action方法认证Authorize 在建立Web 站点安全性时 1.登录后才可访问系统文件 ——限制 Forms认证 <authenticat ...

  9. ElasticSearch中分词器组件配置详解

    首先要明确一点,ElasticSearch是基于Lucene的,它的很多基础性组件,都是由Apache Lucene提供的,而es则提供了更高层次的封装以及分布式方面的增强与扩展. 所以要想熟练的掌握 ...

  10. C# Copy一个文件到另一个文件夹下

    public static void CopyToFile() { //源文件路径 string sourceName = @"D:\Source\Test.txt"; //目标路 ...