本文将结合前面五篇文章所讲解的知识, 综合起来, 实现一个接口扩展的功能.
如果还没有阅读过前面五篇文章的内容, 请先阅读:
《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);
- ----------------
来源: http://www.bubuko.com/infodetail-3326886.html