本文将结合前面五篇文章所讲解的知识,综合起来,实现一个接口扩展的功能。
如果还没有阅读过前面五篇文章的内容,请先阅读:
《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. 用 Flask 来写个轻博客 (8) — (M)VC_Alembic 管理数据库结构的升级和降级

    Blog 项目源码:https://github.com/JmilkFan/JmilkFan-s-Blog 目录 目录 前文列表 扩展阅读 Alembic 查看指令 manager db 的可用选项 ...

  2. idea Maven 一键 mvn clean package

    文章目录 方法一 方法二 方法一 方法二

  3. Django框架(十五)—— forms组件、局部钩子、全局钩子

    目录 forms组件.局部钩子.全局钩子 一.什么是forms组件 二.forms组件的使用 1.使用语法 2.组件的参数 3.注意点 三.渲染模板 四.渲染错误信息 五.局部钩子 1.什么是局部钩子 ...

  4. compareTo冒泡比较时间字符串

    public static void main(String[] args) { List<String> dates = new ArrayList<String>(); d ...

  5. 如何在webpack开发中利用vue框架使用ES6中提供的新语法

    在webpack中开发,会遇到一大推问题,特别是babel6升级到babel7,要跟新一大推插件,而对于安装babel的功能就是在webpack开发中,vue中能够是用ES6的新特性: 例如ES6中的 ...

  6. 在egg中配置cors

    在egg中配置 cors(跨域) 第一步,安装 egg-cors npm i egg-cors --save 第二步,配置 cors 在config/plugin.js文件下添加: exports.c ...

  7. 利用ARIMA算法建立短期预测模型

    周五福利日活动是电信为回馈老用户而做的活动,其主要回馈老用户的方式是让用户免费领取对应的优惠券,意在提升老用户的忠诚度和活跃度.今日,为保证仓库备货优惠券资源充足,特别是5元话费券等,需要对该类优惠券 ...

  8. 【CSS】水平居中与垂直居中

    有宽度的div水平居中 1.左右margin设为auto即可 .center { width: 960px; margin-left: auto; margin-right: auto; } 2.绝对 ...

  9. vue组件 is ref

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  10. mysql字段类型不是整型的排序问题

    今天想按从小到大的顺序重数据库提取数据,发现取出的数据不是按顺序排的,经检查之后发现是mysql保存的字符类型是varchar,但是值是整数,解决办法:把排序字段+0; SELECT * FROM u ...