• Phone状态的监听机制


    一 监听手机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);
    //创建Listener MyPhoneCallListener myPhoneCallListener = new MyPhoneCallListener(); //注册监听 设置监听的State tm.listen(myPhoneCallListener, PhoneStateListener.LISTEN_CALL_STATE); //实现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状态的实现机制

    [原创]Android Telephony 分析[PART IV] - 〇〇柒 - 朝阳光出发

    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);
    }
  • 相关阅读:
    在未排序的数组中找到第 k 个最大的元素
    区域和检索
    控制台画图程序(可更换笔刷版本)
    循环中的scanf处理了换行符怎么破
    strlen获取字符数组为什么是255
    宽字符输出中文,Devc++解决方法
    区间取最小值最大值-位值和
    模拟鼠标键盘-封装函数
    scanf("%d",a[i]+j)为什么不加取地址符号
    scanf需要多输入一行是什么问题
  • 原文地址:https://www.cnblogs.com/bastard/p/2784559.html
Copyright © 2020-2023  润新知