Framework中的TelephonyManager

一、TelephonyManager的作用


        我们先来谈谈TelephonyManager的作用。
        对于这个问题,我们看TelephonyManager提供的几个重要接口就可以知道:
  1. //得到软件版本  
  2. getDeviceSoftwareVersion()  
  3. //得到设备的ID,IMEI或者MEID  
  4. getDeviceId()  
  5. //得到位置信息,主要是当前注册小区的位置码  
  6. getCellLocation()  
  7. //得到附近小区信息  
  8. getNeighboringCellInfo()  
  9. //得到当前Phone的类型,GSM/CDMA  
  10. getCurrentPhoneType()  
  11. //得到/proc/cmdline文件当前的内容  
  12. getProcCmdLine()  
  13. //得到运营商名字  
  14. getNetworkOperatorName()  
  15. //得到MCC+MNC  
  16. getNetworkOperator()  
  17. //得到是否漫游的状态  
  18. isNetworkRoaming()  
  19. //得到网络状态,NETWORK_TYPE_GPRS、NETWORK_TYPE_EDGE、NETWORK_TYPE_CDMA等等  
  20. getNetworkType()  
  21. //得到SIM卡状态  
  22. getSimState()  
  23. //得到SIM卡MCC+MNC  
  24. getSimOperator()  
  25. //得到SIM卡SPN  
  26. getSimOperatorName()  
  27. //得到SIM卡串号  
  28. getSimSerialNumber()  
  29. //得到MSISDN  
  30. getMsisdn()  
  31. //得到语音信箱号码  
  32. getVoiceMailNumber()  
  33. //得到语音信箱短信条数  
  34. getVoiceMessageCount()  
  35. //得到语音信箱名称  
  36. getVoiceMailAlphaTag()  
  37. //得到数据连接状态:DATA_DISCONNECTED、DATA_CONNECTING、DATA_CONNECTED、DATA_SUSPENDED等  
  38. getDataState()  
  39. //注册监听器监听Phone状态  
  40. listen()  
  41. //得到所有Phone的信息  
  42. getAllCellInfo()  
        从以上提供的接口可以看出,TelephonyManager作为一个“Manager”, 主要提供Phone模块各种信息的查询和监听服务。这些信息既包括设备的状态,也包括SIM卡的状态,还包括网络的状态,这都是上层应用比较关心的信息。

        那么他是如何实现这些功能的呢?我们接下来介绍。


二、TelephonyManager方法的实现


        准确的讲,TelephonyManager并不是一个标准的服务(Service),因为他既没有继承自任何其他的Service,也没有把自己注册给SystemService,他只是一个普通的类,没有继承任何父类或接口。那么他是如何实现上面提到的方法呢?
        原因说起来也简单, TelephonyManager在自己内部同时申请了三个SystemService的代理对象,当我们向TelephonyManager查询状态或注册监听时,TelephonyManager间接的将相应的请求发给系统服务,从而实现相应的功能。

        下面我们先来介绍如何得到的SystemService,再来看如何通过这些SystemService实现TelephonyManager的接口。

2.1、得到SystemService的过程

        在TelephonyManager内部注册了一下3个SystemService:
                A:telephony.registry服务;@TelephonyRegistry.java
                B:iphonesubinfo服务;@PhoneSubInfoProxy.java
                C:phone服务;@PhoneInterfaceManager.java
        我们分别来看一下如何得到的这些Service
A、telephony.registry服务
        这个服务是在TelephonyManager构造函数中得到的,他的 主要作用就是对信号、呼叫转移、位置改变、数据连接状态等信息的监听
  1. public TelephonyManager(Context context) {  
  2.     if (sContext == null) {  
  3.         Context appContext = context.getApplicationContext();  
  4.         if (appContext != null) {  
  5.             sContext = appContext;  
  6.         } else {  
  7.             sContext = context;  
  8.         }  
  9.         sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));  
  10.     }  
  11. }  
B、iphonesubinfo服务
        这个服务是在getSubscriberInfo接口中得到的,通过这个服务 可以得到软件版本、设备ID、SIM卡串号、语音信箱等信息
  1. private IPhoneSubInfo getSubscriberInfo() {  
  2.     return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));  
  3. }  
C、phone服务
        这个服务很特殊,是在Phone模块中注册给系统的(其他服务都是在framework中注册的),主要功能是 Phone模块相关状态的查询和处理,包括位置服务、小区注册信息、当前网络状态、是否有SIM卡插入、以及SIM卡状态等信息。在TelephonyManager中是通过getITelephony接口得到的这个服务:
  1. private ITelephony getITelephony() {  
  2.     return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));  
  3. }  

        通过以上3个接口,就得到了3个SystemService。下面我们分析,如何在TelephonyManager中通过这3个SystemService扩展其他的方法。

2.2、TelephonyManager方法的具体实现

        我们知道,TelephonyManager的方法是通过3个SystemService去扩展的,那么我们顺着SystemService去分析,看通过这3个SystemService可以扩展出哪些方法。
A、telephony.registry扩展的方法
        首先来看利用sRegistry对象扩展的方法,其实就是telephony.registry服务的扩展功能:
  1. public void listen(PhoneStateListener listener, int events) {  
  2.     String pkgForDebug = sContext != null ? sContext.getPackageName() : "<unknown>";  
  3.     try {  
  4.         Boolean notifyNow = (getITelephony() != null);  
  5.         //通过TelephonyRegistry注册监听器  
  6.         sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);  
  7.     } catch (RemoteException ex) {  
  8.     } catch (NullPointerException ex) {  
  9.     }  
  10. }  
        通过telephony.registry扩展的功能只有这一个,这个listen方法的作用就是去注册Phone状态的监听器。我们在TelephonyRegistry服务的介绍中讲到,客户端在得到这个服务后,可以通过listen的方法去注册某个事件的监听器,当这个事件发生时,就会调用所有曾经注册的客户端的回调函数,通知客户端。
B、iphonesubinfo扩展的方法
        上面说道,通过这个服务可以得到软件版本、设备ID、SIM卡串号、语音信箱等信息,具体来说主要的方法有:
  1. //得到软件版本信息  
  2. public String getDeviceSoftwareVersion() {  
  3.     return getSubscriberInfo().getDeviceSvn();  
  4. }  
  5. //得到设备ID  
  6. public String getDeviceId() {  
  7.     return getSubscriberInfo().getDeviceId();  
  8. }  
  9. //得到SIM卡串号  
  10. public String getSimSerialNumber() {  
  11.     return getSubscriberInfo().getIccSerialNumber();  
  12. }  
  13. //得到语音信箱  
  14. public String getVoiceMailNumber() {  
  15.     return getSubscriberInfo().getVoiceMailNumber();  
  16. }  
C、phone扩展的方法
        通过这个SystemService得到的方法主要有:
  1. //得到位置信息  
  2. public CellLocation getCellLocation() {  
  3.     Bundle bundle = getITelephony().getCellLocation();  
  4.     if (bundle.isEmpty()) return null;  
  5.     CellLocation cl = CellLocation.newFromBundle(bundle);  
  6.     return cl;  
  7. }  
  8. //得到附近小区信息  
  9. public List<NeighboringCellInfo> getNeighboringCellInfo() {  
  10.     return getITelephony().getNeighboringCellInfo();  
  11. }  
  12. //得到当前Phone状态  
  13. public int getCurrentPhoneType() {  
  14.     ITelephony telephony = getITelephony();  
  15.     if (telephony != null) {  
  16.         return telephony.getActivePhoneType();  
  17.     } else {  
  18.         return getPhoneTypeFromProperty();  
  19.     }  
  20. }  
  21. //判断是否有SIM卡插入  
  22. public boolean hasIccCard() {  
  23.     return getITelephony().hasIccCard();  
  24. }  

三、TelephonyManager自身的注册


        上面的第二节中介绍了TelephonyManager内部实现原理,那么面对如此好用又强大的信息提供者,我们如何去使用呢?

        在介绍使用方法之前,我们先来看看这个类的“注册”过程,了解了他的“注册”方法,我们自然就会明白如何使用他。

3.1、TelephonyManager的“注册”过程

        在第二节开始的地方我们讲过,TelephonyManager既不是服务,也没有注册给SystemService,他甚至没有继承自任何父类或接口。因此他的“注册”过程并不是严格意义上的“注册”。
  1. @ContextImpl.java  
  2. registerService(TELEPHONY_SERVICE, new ServiceFetcher() {  
  3.         public Object createService(ContextImpl ctx) {  
  4.             return new TelephonyManager(ctx.getOuterContext());  
  5.         }});  
        我们继续看registerService:
  1. private static void registerService(String serviceName, ServiceFetcher fetcher) {  
  2.     if (!(fetcher instanceof StaticServiceFetcher)) {  
  3.         fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;  
  4.     }  
  5.     SYSTEM_SERVICE_MAP.put(serviceName, fetcher);  
  6. }  
        以及TELEPHONY_SERVICE:        
  1. private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP = new HashMap<String, ServiceFetcher>();  

        上面三段代码说明这样一个事实:在ContextImpl中,我们new了一个TelephonyManager对象,并把这个对象通过registerService的方法放到了一个SYSTEM_SERVICE_MAP的HashMap中。这个过程,就是TelephonyManager所谓的“注册”过程

        那么我们如何得到TelephonyManager对象呢?

3.2、如何得到TelephonyManager对象   

  1. public Object getSystemService(String name) {  
  2.         ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);  
  3.         return fetcher == null ? null : fetcher.getService(this);  
  4. }  

        这个过程也很容易理解,就是通过getSystemService接口从SYSTEM_SERVICE_MAP中找到TelephonyManager的对象,并返回出来

3.3、TelephonyManager的注册本质

        从TelephonyManager的注册和得到的过程我们看出, 其实所谓的“注册”,就是在ContextImpl中new一个TelephonyManager的对象,并保存在HashMap中。
        我们可以通过Context的getSystemService方法去得到这个对象,也就是TelephonyManager这个“服务”。

四、TelephonyManager存在的意义


        此时我们再来谈谈TelephonyManager存在的意义,也就是说, 为什么需要构建这么一个东西来同时注册3个SystemService
        假如现在有3个模块A、B、C,都需要做一些Phone有关的操作,他么的需求如下:
        A模块:需要用到TelephonyRegistry和PhoneSubInfoProxy的服务,那么他就要去分别申请这两个服务的代理对象;
        B模块:需要用到TelephonyRegistry和PhoneInterfaceManager服务,他也需要分别申请代理对象。
        C模块:需要用到上面的3个服务,那么就需要申请3个代理对象。
        对于这样的情况,我们当然可以在每个需要的模块内部分别调用系统接口(ServiceManager.getService)去得到相应的代理对象。这种情况下我们需要调用7次getService方法得到7个SystemService的远程对象。
        如果通过TelephonyRegistry的方式去实现呢?
        此时我们只需要在3个模块中,分别调用Context的getSystemService方法就能同时得到3个SystemService远程代理对象。而且我们得到的3个TelephonyManager对象是同一个对象,3个模块公用了同一个SystemService。因此,我们实际上只调用了3此getService方法,得到了3个SystemService远程对象。
        这个例子说明, TelephonyManager整合3个SystemService的意义就在于减轻系统负担,特别是一些SystemService的负担,同时提高了访问效率

五、为什么TelephonyManager只整合了3个SystemService?


        既然TelephonyManager大大减轻了一些SystemService的负担,为什么只整合了3个SystemService呢?或者说, 为什么选中了这3个SystemService来整合呢
        我们再来梳理以下TelephonyManager的运行原理。经过TelephonyManager的整合,当我们通过Context去得到TelephonyManager对象时,得到的是同一个TelephonyManager对象,那么我们进一步得到的SystemService也是同一个,此时我们调用TelephonyManager中的方法时,得到的返回值也是完全相同的。
        这就说明了,TelephonyManager整合的SystemService,有一个共同特点:这些服务无论谁去调用,方法的返回值都是相同的。比如SIM卡的状态、当前的运营商信息、设备的ID号等。
        而对于存在差异的SystemService,由于对于不同的客户端需要返回不同的值,当然就无法放到TelephonyManager中处理了。
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值