本文紧接着上一篇文章《Android Telephony分析(四) —- TelephonyManager详解 》的1.4小节。
从TelephonyRegistry的大部分方法中:

可以看出TelephonyRegistry主要的功能是上报消息,有两种方式:
1. 通过notifyXXX方法。
2. 通过发送broadcast。
至于发广播没什么好说的了,我们看看notifyXXX方法吧,以notifyCallStateForPhoneId()方法为例

    public void notifyCallStateForPhoneId(int phoneId, int subId, int state,
String incomingNumber) {
//先检测权限
if (!checkNotifyPermission("notifyCallState()")) {
return;
}
//1.mRecords是什么?
synchronized (mRecords) {
int phoneId = SubscriptionManager.getPhoneId(subId);
if (validatePhoneId(phoneId)) {
mCallState[phoneId] = state;
mCallIncomingNumber[phoneId] = incomingNumber;
//遍历mRecords列表
for (Record r : mRecords) {
//取出注册监听"LISTEN_CALL_STATE"这种事件的Record对象
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
(r.subId == subId) &&
(r.subId != SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
try {
String incomingNumberOrEmpty = getCallIncomingNumber(r, phoneId);
//2.Record.callback又是什么?
r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
}
}
}
handleRemoveListLocked();
}
//同时调用发广播的方法
broadcastCallStateChanged(state, incomingNumber, phoneId, subId);
}

通过初步分析notifyCallState()方法,你会发现有两个疑问:
1. mRecords是什么?
2. Record.callback又是什么?
好了,带着上面两种疑问,我们继续分析代码吧。
接着你会发现mRecords是由Record对象组成的List集合

    private final ArrayList<Record> mRecords = new ArrayList<Record>();

而Record是TelephonyRegistry中的内部类,TelephonyRegistry会把监听者的信息封装成一个Record对象,并且放进mRecords列表中管理。

class TelephonyRegistry extends ITelephonyRegistry.Stub {

    private static class Record {
String callingPackage;
IBinder binder;
//Record.callback是实现了IPhoneStateListener接口的类,
//也就是继承了或者重写了PhoneStateListener的类
IPhoneStateListener callback;
IOnSubscriptionsChangedListener onSubscriptionsChangedListenerCallback;
int callerUserId;
//存储用来记录监听的事件
int events;
int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
int phoneId = SubscriptionManager.INVALID_PHONE_INDEX;
boolean canReadPhoneState;
boolean matchPhoneStateListenerEvent(int events) {
return (callback != null) && ((events & this.events) != 0);
}
boolean matchOnSubscriptionsChangedListener() {
return (onSubscriptionsChangedListenerCallback != null);
}
}

在TelephonyRegistry.java的listen方法中,管理并维护着mRecords列表:

    public void listenForSubscriber(int subId, String pkgForDebug, IPhoneStateListener callback,
int events, boolean notifyNow) {
listen(pkgForDebug, callback, events, notifyNow, subId);
} private void listen(String callingPackage, IPhoneStateListener callback, int events,
boolean notifyNow, int subId) {
...
synchronized (mRecords) {
// register
Record r;
find_and_add: {
//得到监听者的信息
IBinder b = callback.asBinder();
//遍历mRecords列表
for (int i = 0; i < N; i++) {
r = mRecords.get(i);
if (b == r.binder) {
//退出循环
break find_and_add;
}
}
//如果监听者还没有被加到mRecords列表中
r = new Record();
r.binder = b;
//新建一个Record对象并且加入mRecords列表中
mRecords.add(r);
if (DBG) log("listen: add new record");
}
//存储监听者
r.callback = callback;
...
//存储监听者所监听的事件
r.events = events;
//如果需要现在发通知的话
if (notifyNow && validatePhoneId(phoneId)) {
if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) {
try {
//注册之后,马上通知一次监听者
r.callback.onServiceStateChanged(
new ServiceState(mServiceState[phoneId]));
} catch (RemoteException ex) {
remove(r.binder);
}
}
...
}

常见的注册监听和发通知的流程,以监听Call状态变化为例:

总体看分成3步:
1. 根据需要监听的事件,重写PhoneStateListener中对应的方法,如果需要监听LISTEN_CALL_STATE,那么需要重写 onCallStateChanged()方法;如果需要监听LISTEN_SERVICE_STATE,则需要重写onServiceStateChanged()方法。(步骤1)
2. 调用TelephonyManager的listen()方法,传递PhoneStateListener对象和events。到这里监听的操作一直执行到步骤4就结束了。
3. 当有Call状态变化消息上来时,通知上报的路径:
RILJ—>CallTracker—>Phone—>DefaultPhoneNotifier—>TelephonyRegistry—>监听者
最后也是来到监听者重写的PhoneStateListener的那个方法中,整个过程也是一个回调。

其他需要说明的是:
1. DefaultPhoneNotifier是TelephonyRegistry最常用的客户端,它继承自

public class DefaultPhoneNotifier implements PhoneNotifier {

在它构造方法中:

    protected DefaultPhoneNotifier() {
//通过ServiceManager得到了TelephonyRegistry的代理对象 mRegistry = ITelephonyRegistry.Stub.asInterface(
      ServiceManager.getService("telephony.registry"));
}

所以DefaultPhoneNotifier中大部分方法都依靠TelephonyRegistry对象来实现。

2 . 如何知道我需要监听的事件以及对应要重写的方法?
所有的可以监听的事件都定义在PhoneStateListener.java (frameworks\base\telephony\java\android\telephony)中,

需要重写的方法,初始都定义在IPhoneStateListener.aidl(frameworks/base/telephony/java/com/android/internal/telephony)中

接着由PhoneStateListener初步重写了IPhoneStateListener.aidl接口中的方法:

    /**
* The callback methods need to be called on the handler thread where
* this object was created. If the binder did that for us it'd be nice.
*/
IPhoneStateListener callback = new IPhoneStateListener.Stub() {
public void onServiceStateChanged(ServiceState serviceState) {
    Message.obtain(mHandler, LISTEN_SERVICE_STATE, 0, 0, serviceState)
                    .sendToTarget();
}
...
}

在这里就可以找到某个事件对应的方法是什么。
当然可以自己新增事件以及在IPhoneStateListener.aidl中新增对应的接口,再实现该接口就可以了.

————————————————
版权声明:本文为CSDN博主「linyongan」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/linyongan/article/details/52126969

Android Telephony分析(五) ---- TelephonyRegistry详解的更多相关文章

  1. Android Telephony分析(三) ---- RILJ详解

    前言 本文主要讲解RILJ工作原理,以便更好地分析代码,分析业务的流程.这里说的RILJ指的是RIL.java (frameworks\opt\telephony\src\java\com\andro ...

  2. Android Telephony分析(二) ---- RegistrantList详解

    前言 本文主要讲解RegistrantList的原理,以及如何快速分析RegistrantList相关的代码流程.在Telephony模块中,在RIL.Tracker(ServiceStateTrac ...

  3. Android Telephony分析(四) ---- TelephonyManager详解

    前言 TelephonyManager主要提供Telephony相关信息的查询/修改功能,以及Phone状态监听功能,封装的方法主要是提供给APP上层使用.TelephonyManager.java ...

  4. Android Telephony分析(一) ---- Phone详解

    目录: Phone的继承关系与PhoneFactory(GsmCdmaPhone.ImsPhone.SipPhone) Phone进程的启动 Phone对象的初始化(DefaultPhoneNotif ...

  5. vuex 源码分析(五) action 详解

    action类似于mutation,不同的是Action提交的是mutation,而不是直接变更状态,而且action里可以包含任意异步操作,每个mutation的参数1是一个对象,可以包含如下六个属 ...

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

    本文将结合前面五篇文章所讲解的知识,综合起来,实现一个接口扩展的功能.如果还没有阅读过前面五篇文章的内容,请先阅读:<Android Telephony分析(一) — Phone详解 >& ...

  7. [Android新手区] SQLite 操作详解--SQL语法

    该文章完全摘自转自:北大青鸟[Android新手区] SQLite 操作详解--SQL语法  :http://home.bdqn.cn/thread-49363-1-1.html SQLite库可以解 ...

  8. Android高效率编码-第三方SDK详解系列(一)——百度地图,绘制,覆盖物,导航,定位,细腻分解!

    Android高效率编码-第三方SDK详解系列(一)--百度地图,绘制,覆盖物,导航,定位,细腻分解! 这是一个系列,但是我也不确定具体会更新多少期,最近很忙,主要还是效率的问题,所以一些有效的东西还 ...

  9. Android Telephony分析(七) ---- 接口扩展(异步转同步)

    本文是基于上一篇<Android Telephony分析(六) —- 接口扩展(实践篇)>来写的.上一篇介绍的接口扩展的方法需要实现两部分代码:1. 从APP至RIL,发送请求:2. 从R ...

随机推荐

  1. move_base 分层代价地图的作用(翻译)

    A. 标准层 ​ Static Map Layer:为了做全局规划,机器人需要一个超越其传感器的地图,以了解墙壁和其他静态障碍物的位置. 静态地图可以先用SLAM算法生成,也可以从架构图中创建. 当层 ...

  2. 17、通过maven生成测试报告

    目录如下: 通过Maven 生成报告 进入testngTest根目录,运行mvn test 命令 进入 testngTest\target\surefire-reports 路径查看测试报告

  3. 2019杭电多校第三场hdu6608 Fansblog(威尔逊定理)

    Fansblog 题目传送门 解题思路 Q! % P = (P-1)!/(P-1)...(Q-1) % P. 因为P是质数,根据威尔逊定理,(P-1)!%P=P-1.所以答案就是(P-1)((P-1) ...

  4. HDU 5443 The Water Problem (ST算法)

    题目链接:HDU 5443 Problem Description In Land waterless, water is a very limited resource. People always ...

  5. VC++ 2010 创建高级Ribbon界面详解(2)

    Ribbon 控件的使用 1.命令按钮 命令按钮可以说是我们最常用的Ribbon控件了,我们通常都是通过命令按钮来发送某个命令,执行某个动作.它代替了过去的菜单命令,成为使用最频繁的Ribbon控件. ...

  6. Java架构师必看的10本书

    1.大型网站系统与JAVA中间件实践 本书围绕大型网站和支撑大型网站架构的Java中间件的实践展开介绍. 从分布式系统的知识切入,让读者对分布式系统有基本的了解:然后介绍大型网站随着数据量.访问量增长 ...

  7. leetcode.字符串.696计数二进制子串-java

    1. 具体题目 给定一个字符串 s,计算具有相同数量0和1的非空(连续)子字符串的数量,并且这些子字符串中的所有0和所有1都是组合在一起的.重复出现的子串要计算它们出现的次数. 示例 1 : 输入: ...

  8. C-Ubuntu中MySQL出现ERROR1698(28000):Access denied for user root@localhost错误解决方法

    卸载原先的MySQL,重新安装过程中没有提示设置密码, 当键入命令:mysql -uroot -p; 不知密码是什么,输入主机的密码以及不输入密码,回车后都出现标题错误. 寻找多篇相关博文,验证如下博 ...

  9. python之常用的数据处理方法

    1.生成6位数验证码 "".join([random.choice(chars) for i in range(6)]) 2.密码加密 import hashlib def enc ...

  10. 通过反射来创建对象?getConstructor()和getDeclaredConstructor()区别?

    1. 通过类对象调用newInstance()方法,适用于无参构造方法: 例如:String.class.newInstance() public class Solution { public st ...