博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Phone状态监听
阅读量:6941 次
发布时间:2019-06-27

本文共 10389 字,大约阅读时间需要 34 分钟。

hot3.png

注:本文基于Android O。

Phone状态的监听主要是通过TelephonyRegistry和PhoneStateListener来实现的。

TelephonyRegistry是一个service,负责监听事件的注册及通知,在整个流程中起一个桥梁的作用。

PhoneStateListener则是作为监听器,需要监听者实现监听到响应事件后需要进行的处理。

PhoneStateListener中定义了可以监听的事件:

public static final int LISTEN_NONE = 0;    public static final int LISTEN_SERVICE_STATE                            = 0x00000001;    public static final int LISTEN_SIGNAL_STRENGTH                          = 0x00000002;    public static final int LISTEN_MESSAGE_WAITING_INDICATOR                = 0x00000004;    public static final int LISTEN_CALL_FORWARDING_INDICATOR                = 0x00000008;    public static final int LISTEN_CELL_LOCATION                            = 0x00000010;    public static final int LISTEN_CALL_STATE                               = 0x00000020;    public static final int LISTEN_DATA_CONNECTION_STATE                    = 0x00000040;    public static final int LISTEN_DATA_ACTIVITY                            = 0x00000080;    public static final int LISTEN_SIGNAL_STRENGTHS                         = 0x00000100;    public static final int LISTEN_OTASP_CHANGED                            = 0x00000200;    public static final int LISTEN_CELL_INFO                                = 0x00000400;    public static final int LISTEN_PRECISE_CALL_STATE                       = 0x00000800;    public static final int LISTEN_PRECISE_DATA_CONNECTION_STATE            = 0x00001000;    public static final int LISTEN_DATA_CONNECTION_REAL_TIME_INFO           = 0x00002000;    public static final int LISTEN_VOLTE_STATE                              = 0x00004000;    public static final int LISTEN_OEM_HOOK_RAW_EVENT                       = 0x00008000;    public static final int LISTEN_CARRIER_NETWORK_CHANGE                   = 0x00010000;    public static final int LISTEN_VOICE_ACTIVATION_STATE                   = 0x00020000;    public static final int LISTEN_DATA_ACTIVATION_STATE                    = 0x00040000;

 

监听者在注册监听相关事件时,需要继承PhoneStateListener对象,并重写需要监听的事件对应的方法,这个方法在相应事件发生后会被回调,因此,我们重写这个方法的目的也就是添加事件发生后的处理流程,例如,如果我们要监听service state的变化,就需要重写onServiceStateChanged方法。我们来看看MobileSignalController中的例子:

mPhoneStateListener = new MobilePhoneStateListener(info.getSubscriptionId(),            receiverLooper);    class MobilePhoneStateListener extends PhoneStateListener {        public MobilePhoneStateListener(int subId, Looper looper) {            super(subId, looper);        }        @Override        public void onSignalStrengthsChanged(SignalStrength signalStrength) {            ......            mSignalStrength = signalStrength;            updateTelephony();        }        @Override        public void onServiceStateChanged(ServiceState state) {            ......        }        @Override        public void onDataConnectionStateChanged(int state, int networkType) {            ......        }        @Override        public void onDataActivity(int direction) {            ......        }        @Override        public void onCarrierNetworkChange(boolean active) {            ......        }    };    public void registerListener() {        mPhone.listen(mPhoneStateListener,                PhoneStateListener.LISTEN_SERVICE_STATE                        | PhoneStateListener.LISTEN_SIGNAL_STRENGTHS                        | PhoneStateListener.LISTEN_CALL_STATE                        | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE                        | PhoneStateListener.LISTEN_DATA_ACTIVITY                        | PhoneStateListener.LISTEN_CARRIER_NETWORK_CHANGE);        ......    }

MobilePhoneStateListener继承了PhoneStateListener,并重写了与监听事件相关的方法,然后调用mPhone.listen()进行注册监听,mPhone是一个TelephonyManager对象。

我们在传递监听事件时,可同时监听多个事件,上述例子中就监听了service state和signal strength等多个事件。

监听者通过TelephonyManager的listen()方法注册监听,listen()方法中调用了TelephonyRegistry的listenForSubscriber()方法。

其中,传入的参数listener.callback是一个IPhoneStateListenerStub对象;events参数是监听的事件;还有一个参数notifyNow,其为true时,注册后相应的callback会被立即回调一次,在这里,它的值是由获取到的PhoneInterfaceManager对象是否为null来决定的,不为null时notifyNow为true。

public void listen(PhoneStateListener listener, int events) {        ......        boolean notifyNow = (getITelephony() != null);        ......        sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),                listener.callback, events, notifyNow);        ......}

TelephonyRegistry实际上是一个Service,在开机时就会被添加到ServiceManager。其作用就是给其它App提供监听Phone相关状态的接口。

SystemServer.java

private void startOtherServices() {        ......        telephonyRegistry = new TelephonyRegistry(context);        ServiceManager.addService("telephony.registry", telephonyRegistry);        ......}

另外,在代码中对此类有如下介绍:

    Since phone process can be restarted, this class provides a centralized place

    that applications can register and be called back from.

也就是说,之所以要单独使用一个service来做这个监听的任务,是因为即使phone进程重启,

我们之前注册监听的事件也都还在,如果直接向phone进程进行注册,那么phone进程重启后,

就需要之前注册了的App重新再去注册,这种做法显然是不合理的。

TelephonyRegistry的listenForSubscriber方法直接调用其listen方法。

public void listenForSubscriber(int subId, String pkgForDebug, IPhoneStateListener callback,        int events, boolean notifyNow) {    listen(pkgForDebug, callback, events, notifyNow, subId);}

listen方法中首先会判断要监听的事件是什么,如果监听的事件为空的话,就认为调用者是想取消之前注册的listener,然后就会将之前的注册信息删除掉。

对于正常的注册监听流程,首先会进行一系列的权限判断,以确保Caller具有相应事件的监听权限,然后就是在已注册的记录中查找当前的callback是否已经注册,若已注册,则更新之前的记录,若未注册,则会创建一个新的记录。
最后,还会根据传入的notifyNow参数以及PhoneId是否有效来决定是否立即回调一次callback,而正常情况下是会立即回调的。

private void listen(String callingPackage, IPhoneStateListener callback, int events,        boolean notifyNow, int subId) {    ......    if (events != PhoneStateListener.LISTEN_NONE) {        // 权限判断,略...        ......        synchronized (mRecords) {            // register            Record r;            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; // 当前callback之前已经注册了                    }                }                r = new Record(); // 当前callback未注册,则新建一条记录                r.binder = b;                mRecords.add(r);                if (DBG) log("listen: add new record");            }            // 保存相关数据到原有/新建的记录中            r.callback = callback;            r.callingPackage = callingPackage;            r.callerUserId = callerUserId;            boolean isPhoneStateEvent = (events & (CHECK_PHONE_STATE_PERMISSION_MASK                    | ENFORCE_PHONE_STATE_PERMISSION_MASK)) != 0;            r.canReadPhoneState = isPhoneStateEvent && canReadPhoneState(callingPackage);            // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,            // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID            if (!SubscriptionManager.isValidSubscriptionId(subId)) {                r.subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;             } else {//APP specify subID                r.subId = subId;            }            r.phoneId = SubscriptionManager.getPhoneId(r.subId);            int phoneId = r.phoneId;            r.events = events;            ......            // 判断是否立即回调callback            if (notifyNow && validatePhoneId(phoneId)) {                if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {                    ......                        r.callback.onServiceStateChanged(                                new ServiceState(mServiceState[phoneId]));                    ......                }                ......            }        }    } else {        // 没有监听的事件,则注销之前已注册的callback        remove(callback.asBinder());    }}

至此,注册监听的流程就结束了,接下来我们再来看看各事件发生后是怎么通知到相应监听者的。

以LISTEN_SERVICE_STATE为例,其在PhoneStateListener之前的大致流程为:

-> GsmServiceStateTracker调用pollState()方法查询Service State-> GsmCdmaPhone.notifyServiceStateChanged()-> Phone.notifyServiceStateChangedP()-> DefaultPhoneNotifier.notifyServiceState()-> TelephonyRegistry.notifyServiceStateForPhoneId()-> PhoneStateListener.callback.onServiceStateChanged()

下面再来看PhoneStateListener内部的调用流程,而这部分流程对于所有监听的事件都是类似的。

我们看看PhoneStateListener中的callback,一个IPhoneStateListenerStub对象,它的onServiceStateChanged方法被调用后,会发送一个LISTEN_SERVICE_STATE事件。

private static class IPhoneStateListenerStub extends IPhoneStateListener.Stub {    ......    public void onServiceStateChanged(ServiceState serviceState) {        send(LISTEN_SERVICE_STATE, 0, 0, serviceState);    }    private void send(int what, int arg1, int arg2, Object obj) {        PhoneStateListener listener = mPhoneStateListenerWeakRef.get();        if (listener != null) {            Message.obtain(listener.mHandler, what, arg1, arg2, obj).sendToTarget();        }    }    ......}IPhoneStateListener callback = new IPhoneStateListenerStub(this);

然后PhoneStateListener又会收到这个LISTEN_SERVICE_STATE事件,并调用自己的onServiceStateChanged()方法,而这个onServiceStateChanged()方法在最初注册监听时是被caller重写了的,因此实际被调用的是被重写了的onServiceStateChanged方法,就这样,caller就监听到相应事件并进行处理了。

public void handleMessage(Message msg) {        ......        case LISTEN_SERVICE_STATE:            PhoneStateListener.this.onServiceStateChanged((ServiceState)msg.obj);            break;        ......}

 

附:PhoneStateListener相关事件的处理流程

1) LISTEN_SERVICE_STATE

-> GsmServiceStateTracker调用pollState()方法查询Service State-> GsmCdmaPhone.notifyServiceStateChanged()-> Phone.notifyServiceStateChangedP()-> DefaultPhoneNotifier.notifyServiceState()-> TelephonyRegistry.notifyServiceStateForPhoneId()-> PhoneStateListener.callback.onServiceStateChanged()

2) LISTEN_SIGNAL_STRENGTH

    deprecated by LISTEN_SIGNAL_STRENGTHS
3) LISTEN_MESSAGE_WAITING_INDICATOR
    VoiceMail相关的,不作介绍。
4) LISTEN_CALL_FORWARDING_INDICATOR
    参考
5) LISTEN_CELL_LOCATION
6) LISTEN_CALL_STATE
7) LISTEN_DATA_CONNECTION_STATE
8) LISTEN_DATA_ACTIVITY
9) LISTEN_SIGNAL_STRENGTHS

-> ServiceStateTracker查询Signal Strength-> Phone.notifySignalStrength()-> DefaultPhoneNotifier.notifySignalStrength()-> TelephonyRegistry.notifySignalStrengthForPhoneId()-> PhoneStateListener.callback.onSignalStrengthsChanged()-> PhoneStateListener.onSignalStrengthsChanged()

10) LISTEN_OTASP_CHANGED

11) LISTEN_CELL_INFO
12) LISTEN_PRECISE_CALL_STATE
13) LISTEN_PRECISE_DATA_CONNECTION_STATE
14) LISTEN_DATA_CONNECTION_REAL_TIME_INFO
15) LISTEN_VOLTE_STATE
16) LISTEN_OEM_HOOK_RAW_EVENT
17) LISTEN_CARRIER_NETWORK_CHANGE
18) LISTEN_VOICE_ACTIVATION_STATE
19) LISTEN_DATA_ACTIVATION_STATE

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/igiantpanda/blog/1608094

你可能感兴趣的文章
获取当前域名
查看>>
Spark小课堂Week4 从控制台看Spark逻辑结构
查看>>
linux上启动tomcat远程不能访问
查看>>
网络传输中的三张表,MAC地址表、ARP缓存表以及路由表
查看>>
Windows+Apache2.4.10+PHP7.0+MySQL5.6.21安装
查看>>
AT NEW F、AT END OF F注意事项
查看>>
FOR ALL ENTRIES IN 与 INNER JOIN 写在一个SQL上影响效率
查看>>
2010年04月01日
查看>>
IDEA下maven工程的classpath
查看>>
sql的where条件转换成mongdb筛选条件
查看>>
支持新版chrome,用webstorm编译形成css和sourcemap,调试sass和less源文件(转)
查看>>
【转载】aspx,ascx和ashx使用小结
查看>>
蓝牙智能灯带(天猫精灵生态)方案
查看>>
Java缓存类的实际应用场景
查看>>
JQuery:怎么动态切换一个元素的显示、隐藏呢?原来隐藏就显示,原来显示就隐藏...
查看>>
SQL Server之存储过程基础知识
查看>>
Oracle 11g完全卸载(Windows)(转)
查看>>
(图 BFS)走迷宫
查看>>
转:Linux tcpdump命令详解
查看>>
计算机网络笔记整理
查看>>