Android Telephony分析(六) ---- 接口扩展(实践篇)

来源:互联网 发布:淘宝上的组装机好吗 编辑:程序博客网 时间:2024/05/29 09:29

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

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

Created with Raphaël 2.1.0APPAPPTelephonyManagerTelephonyManagerPhonePhoneRILRIL发送Requestmodem处理返回结果返回结果

http://blog.csdn.net/linyongan


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);
7 0
原创粉丝点击