Phone状态的监听机制

来源:互联网 发布:window.open php 编辑:程序博客网 时间:2024/05/17 03:16

一 监听手机Phone状态

在手机里面监听Phone的状态有两种方法:

1 注册接收广播

复制代码
  AndroidMenifest.xml:        <receiver android:name="CallListener" >            <intent-filter>                <action android:name="android.intent.action.PHONE_STATE" />                <action android:name="android.intent.action.NEW_OUTGOING_CALL" />            </intent-filter>        </receiver>        权限        <uses-permission android:name="android.permission.READ_PHONE_STATE" />    广播:        public class CallListener extends BroadcastReceiver{            @Override            public void onReceive(Context context, Intent intent){            }            }
复制代码

2 注册PhoneStateListener

复制代码
//获得相应的系统服务TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);//创建ListenerMyPhoneCallListener myPhoneCallListener = new MyPhoneCallListener();    //注册监听 设置监听的State    tm.listen(myPhoneCallListener, PhoneStateListener.LISTEN_CALL_STATE);//取消注册:    tm.listen(MyPhoneListener myPlistener,PhoneStateListener.LISTEN_NONE);    //实现PhoneStateListener listener并实现相应的方法public class MyPhoneCallListener extends PhoneStateListener{    @Override    public void onCallStateChanged(int state, String incomingNumber)    {        switch (state)        {            //电话通话的状态            case TelephonyManager.CALL_STATE_OFFHOOK:                              break;            //电话响铃的状态            case TelephonyManager.CALL_STATE_RINGING:                               break;            //空闲中            case TelephonyManager.CALL_STATE_IDLE:            break;        }        super.onCallStateChanged(state, incomingNumber);    }}
复制代码

  这里需要通过TelephonyManager,那么注册过程是如果实现的,以及触发的过程又是如何的呢。

Framework层telephony处理的核心是RIL这个类,网络层得各种状态变化由此传递给监听者。

Application层很多的地方都需要对Phone的state进行监听处理。下面将此过程是如何实现的。

类继承结构图:

    

二 监听Phone状态的实现机制

Phone state listen 时序图:

  

1 PhoneNotifier与Phone

在PhoneFactory中对Framework的telephony层进行了对象的初始化:

复制代码
public static void makeDefaultPhone(Context context) {    sPhoneNotifier = new DefaultPhoneNotifier();        //创建CommandsInterface实例    sCommandsInterface = new RIL(context, networkMode, cdmaSubscription);        //创建Phone实例 以及代理对象ProxyPhone    sProxyPhone = new PhoneProxy(new GSMPhone(context,                        sCommandsInterface, sPhoneNotifier));}Public GSMPhone (Context context, CommandsInterface ci, PhoneNotifier notifier, boolean unitTestMode) {        // notifier    super(notifier, context, ci, unitTestMode);} 
复制代码

在创建GSMPhone父类时传递了PhoneNotifier对象到PhoneBase类中:

复制代码
protected PhoneBase(PhoneNotifier notifier, Context context, CommandsInterface ci,            boolean unitTestMode) {      //保存notifier对象引用    this.mNotifier = notifier;    this.mContext = context;    mLooper = Looper.myLooper();    mCM = ci;    //PhoneBase是个handler 注册来电监听    mCM.setOnCallRing(this, EVENT_CALL_RING, null);} 
复制代码

  这里看到:GSMPhone将存储了一个PhoneNotifier对象的引用,PhoneBase是一个Handler,

但是并没有注册到RIL 的mCallStateRegistrants表中对Phone状态变化的事件监听,也没有在PhoneBase中

看到使用mNotifier来进行PhoneStateListener .LISTEN_CALL_STATE状态的通知触发。

         其实通过代码可以看到Phone的状态并不是直接由RIL来控制判断的,而是类GsmCallTracker对各种状态监听,综合起来进行判断通知的。

简单看下这个类继承结构:

    

这个类也挺复杂,先看看这样一个函数:

GsmCallTracker:

复制代码
private void updatePhoneState() {        Phone.State oldState = state;        //判断状态有无变化        ……        if (state != oldState) {            //GSMPhone            phone.notifyPhoneStateChanged();        }    } 
复制代码

GSMPhone:

void notifyPhoneStateChanged() {    //这就是在创建GSMPhone时传递的PhoneNotifier——DefaultPhoneNotifier        mNotifier.notifyPhoneState(this);} 

  从这里就到了PhoneNotifier派生类DefaultPhoneNotifier中,将状态变化通知其注册监听者。

DefaultPhoneNotifier:

复制代码
public void notifyPhoneState(Phone sender) {        Call ringingCall = sender.getRingingCall();        String incomingNumber = "";        if (ringingCall != null && ringingCall.getEarliestConnection() != null){            incomingNumber = ringingCall.getEarliestConnection().getAddress();        }        try {            //remote调用,通知Call State            mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);        } catch (RemoteException ex) {            // system process is dead        }    }
复制代码

  对状态的监听注册Listener ,都是在TelephonyRegistry中进行。

2 TelephonyRegistry和PhoneStateListener

看一下PhoneNotifier相关类继承结构:

            

         ServiceManager.addService("telephony.registry", new TelephonyRegistry(context));

  这里核心的类就是TelephonyRegistry,从ITelephonyRegistry.Stub继承下来,这个类是运行在SystemServer中,

作为Framework层Service,可以通过binder进程间通信,提供了状态的注册监听,状态变化的通知。

  在上面监听Phone状态的一种方式里面,通过继承PhoneStateListener来实现;继承结构中有个IPhoneStateListener这是AIDL文件所自动生成的类。

AIDL文件是按照已搭建好的框架,自动生成进程间通信所需要的接口和类,自动生成的类继承结构关系都如下:

    

再看一下实现监听需要重写的类PhoneStateListener:

    

  PhoneStateListener持有了IPhoneStateListener.Stub对象callback,因为我们想要实现监听Phone状态的所在进程和

通知phone状态变化的进程,不是同一个进程中,要实现跨进程的通信,需要使用Binder实现。

  所以在注册到TelephonyRegistry服务中的listener是一个IPhoneStateListener.Stub的binder对象。

3 Phone状态监听注册

注册过程:

复制代码
  //获得相应的系统服务    TelephonyManager tm = (TelephonyManager) getSystemService(  Context.TELEPHONY_SERVICE);    //创建Listener    MyPhoneCallListener myPhoneCallListener = new MyPhoneCallListener();      //注册监听 设置监听的State    tm.listen(myPhoneCallListener, PhoneStateListener.LISTEN_CALL_STATE);
复制代码

获取系统服务是运行在在当前进程中的:ContextImpl.java

复制代码
registerService(TELEPHONY_SERVICE, new ServiceFetcher() {            public Object createService(ContextImpl ctx) {                return new TelephonyManager(ctx.getOuterContext());            }});//TelephonyManager远程代理服务对象TelephonyRegistry:    public void listen(PhoneStateListener listener, int events) {        //注册监听对象         sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);}
复制代码

TelephonyManager远程代理服务对象TelephonyRegistry:

    

注册对象是在服务TelephonyRegistry中完成:

复制代码
public void listen(String pkgForDebug, IPhoneStateListener callback, int events,            boolean notifyNow) {    synchronized (mRecords) {  // register  Record r = null;  find_and_add:   {    IBinder b = callback.asBinder();    final int N = mRecords.size();    for (int i = 0; i < N; i++) {        r = mRecords.get(i);        if (b == r.binder) {            break find_and_add;        }}  // ArrayList< Record >    r = new Record();    r.binder = b;    r.callback = callback;    r.pkgForDebug = pkgForDebug;    mRecords.add(r);      }}
复制代码

4 触发通知状态变化

public void notifyPhoneState(Phone sender) {    //remote对象TelephonyRegistry      mRegistry.notifyCallState(convertCallState(sender.getState()), incomingNumber);} 

TelephonyRegistry服务触发状态变化通知:

复制代码
public void notifyCallState(int state, String incomingNumber) {    synchronized (mRecords) {        mCallState = state;        mCallIncomingNumber = incomingNumber;        for (Record r : mRecords) {            if ((r.events & PhoneStateListener.LISTEN_CALL_STATE) != 0) {                // remote对象回调                r.callback.onCallStateChanged(state, incomingNumber);            }        }    }    //发送广播    broadcastCallStateChanged(state, incomingNumber);} 
复制代码

  这里看到通过两种方式通知Phone状态有变化:接口回调和发送广播

接口回调:PhoneStateListener中的IPhoneStateListener实例callback

复制代码
IPhoneStateListener callback = new IPhoneStateListener.Stub() {    public void onCallStateChanged(int state, String incomingNumber) {        //Handler发送消息异步处理        Message.obtain(mHandler, LISTEN_CALL_STATE, state, 0, incomingNumber).sendToTarget();    }}Handler mHandler = new Handler() {    public void handleMessage(Message msg) {    switch (msg.what) {      case LISTEN_CALL_STATE:          //调用子类MyPhoneCallListener接口          PhoneStateListener.this.onCallStateChanged(msg.arg1, (String)msg.obj);          break;        }    }}
复制代码

发送广播:

复制代码
private void broadcastCallStateChanged(int state, String incomingNumber) {  //ACTION:android.intent.action.PHONE_STATE 正是广播所监听的ACTION  Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);  intent.putExtra(Phone.STATE_KEY, DefaultPhoneNotifier.convertCallState(state).      toString());  if (!TextUtils.isEmpty(incomingNumber)) {    intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);  }  mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE);}
复制代码

 

0 0
原创粉丝点击