Telephony之TelephonyManager(原)

原创 2014年10月20日 09:49:29

一、TelephonyManager概述


        TelephonyManager主要提供Telephony相关实务的处理能力,我们从他所提供的public方法来总览一下其所能提供的功能:
        //得到软件版本
        getDeviceSoftwareVersion()
        //得到设备的ID,IMEI或者MEID
        getDeviceId()
        //得到位置信息,主要是当前注册小区的位置码
        getCellLocation()
        //得到附近小区信息
        getNeighboringCellInfo()
        //得到当前Phone的类型,GSM/CDMA
        getCurrentPhoneType()
        //得到/proc/cmdline文件当前的内容
        getProcCmdLine()
        //得到运营商名字
        getNetworkOperatorName()
        //得到MCC+MNC
        getNetworkOperator()
        //得到是否漫游的状态
        isNetworkRoaming()
        //得到网络状态,NETWORK_TYPE_GPRS、NETWORK_TYPE_EDGE、NETWORK_TYPE_CDMA等等
        getNetworkType()
        //得到SIM卡状态
        getSimState()
        //得到SIM卡MCC+MNC
        getSimOperator()
        //得到SIM卡SPN
        getSimOperatorName()
        //得到SIM卡串号
        getSimSerialNumber()
        //得到MSISDN
        getMsisdn()
        //得到语音信箱号码
        getVoiceMailNumber()
        //得到语音信箱短信条数
        getVoiceMessageCount()
        //得到语音信箱名称
        getVoiceMailAlphaTag()
        //得到数据连接状态:DATA_DISCONNECTED、DATA_CONNECTING、DATA_CONNECTED、DATA_SUSPENDED等
        getDataState()
        //注册监听器监听Phone状态
        listen()
        //得到所有Phone的信息
        getAllCellInfo()
        从这些方法来看,TelephonyManager提供了与PhoneInterfaceManager类似的功能,但是又有本质的区别,其共同点是:都向其他模块提供了全面的操作Telephony相关事务的能力,其他模块可以在获取到这两个服务后,对Telephony进行各种操作。而区别在于:
        1、从本质上来讲,TelephonyManager本质不是一个Service,没有继承任何类,而PhoneInterfaceManager的本质是一个Service
        2、从注册方式上来讲,TelephonyManager是在ContextImpl中通过registerService的形式进行注册,而PhoneInterfaceManager是通过ServiceManager进行注册。
        3、从获取方式上来讲,需要TelephonyManager服务时,可以通过Context对象的getSystemService()方法来实现,而PhoneInterfaceManager服务需要通过ServiceManager的getService()方法来实现。

        下面我们通过代码来进一步论述上面的说明。


二、如何获取TelephonyManager的服务


        如果调用者是系统应用,可以直接创建TelephonyManager的对象,只需要传递Context类型的参数就行:
        @ContactsProvider2.java
        boolean isPhone() {
            if (!mIsPhoneInitialized) {
                //创建TelephonyManager对象,并调用isVoiceCapable()方法
                mIsPhone = new TelephonyManager(getContext()).isVoiceCapable();
                mIsPhoneInitialized = true;
            }
            return mIsPhone;
        }
        或者通过TelephonyManager的getDefault()方法来获取TelephonyManager对象:
        @TelephonyManager.java
        private static TelephonyManager sInstance = new TelephonyManager();
        public static TelephonyManager getDefault() {
            return sInstance;
        }
        如果调用者不是系统应用的话,如何获取他的服务呢?
        这里就要介绍TelephonyManager的注册过程了。
        ContextImpl在初始化时注册了一些常用的Service,其中就包括TelephonyManager:
        @ContextImpl.java
        registerService(TELEPHONY_SERVICE, new ServiceFetcher() {
            public Object createService(ContextImpl ctx) {
                return new TelephonyManager(ctx.getOuterContext());
            }});
        经过这样的注册,其他进程就可以通过Context对象的getSystemService()方法来获取其服务,比如:
        TelephonyManager tm = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        或者直接调用TelephonyManager的from()方法获取:
        @TelephonyManager.java
        public static TelephonyManager from(Context context) {
            return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
        }


三、TelephonyManager的内部机制


        这一节我们来介绍,TelephonyManager如何实现客户端对他的请求。
        首先我们来看TelephonyManager的继承关系:
        public class TelephonyManager {}
        看来TelephonyManager并没有继承任何的父类,那么他是如何实现各项功能的呢?
        原来,在TelephonyManager内部,获取到了三个Service的客户端,其中构造函数中获取了TelephonyRegistry的服务:
        public TelephonyManager(Context context) {
            Context appContext = context.getApplicationContext();
            if (appContext != null) {
                mContext = appContext;
            } else {
                mContext = context;
            }

            if (sRegistry == null) {
                //获取TelephonyRegistry的服务
                sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry"));
            }
        }
        然后通过getSubscriberInfo()获取了PhoneSubInfoProxy的服务:
        private IPhoneSubInfo getSubscriberInfo() {
            //获取的是PhoneSubInfoProxy的服务
            return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
        }
        以及通过getITelephony()获取了PhoneInterfaceManager的服务:
        private ITelephony getITelephony() {
            return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
        }
        TelephonyManager拿到这三个Service之后,就用三个Service提供的服务,以及SystemProperties提供的属性,搭建了自己的public方法集合
        也就是说,TelephonyManager自己并不具备处理事务的能力,而是汇集了其他三个Service的功能,向他的所有请求者提供便利的处理Telephony事务的能力。
        下面我们来看通过这三个Service分别扩展了那些功能:


3.1、TelephonyRegistry扩展的方法


        在《Telephony之TelephonyRegistry》中介绍过,TelephonyRegistry的客户端可以有两个功能,其中一个就是注册对Radio各种状态的监听,包括通话、短信、数据连接等状态。而TelephonyManager作为TelephonyRegistry的客户端,就是讲监听的功能分派给其他进程。
        也就是说,所有获取TelephonyManager的进程,都可以通过其listen()方法实现Radio状态的监听,TelephonyManager会把监听的请求转发给TelephonyRegistry处理。
        @TelephonyManager.java
        public void listen(PhoneStateListener listener, int events) {
            String pkgForDebug = sContext != null ? sContext.getPackageName() : "<unknown>";
            try {
                Boolean notifyNow = (getITelephony() != null);
                //通过TelephonyRegistry注册监听器
                sRegistry.listen(pkgForDebug, listener.callback, events, notifyNow);
            } catch (RemoteException ex) {
            } catch (NullPointerException ex) {
            }
        }


3.2、PhoneSubInfoProxy扩展的方法


        通过这个服务可以得到软件版本、设备ID、SIM卡串号、语音信箱等信息,具体来说主要的方法有:
        //得到软件版本信息
        public String getDeviceSoftwareVersion() {
            return getSubscriberInfo().getDeviceSvn();
        }
        //得到设备ID
        public String getDeviceId() {
            return getSubscriberInfo().getDeviceId();
        }
        //得到SIM卡串号
        public String getSimSerialNumber() {
            return getSubscriberInfo().getIccSerialNumber();
        }
        //得到语音信箱
        public String getVoiceMailNumber() {
            return getSubscriberInfo().getVoiceMailNumber();
        }


3.3、PhoneInterfaceManager扩展的方法


        我们在《Telephony之PhoneInterfaceManager》一文中专门介绍过这个Service,他提供的功能比较全面,主要有:
        //得到位置信息
        public CellLocation getCellLocation() {
            Bundle bundle = getITelephony().getCellLocation();
            if (bundle.isEmpty()) return null;
            CellLocation cl = CellLocation.newFromBundle(bundle);
            return cl;
        }
        //得到附近小区信息
        public List<NeighboringCellInfo> getNeighboringCellInfo() {
            return getITelephony().getNeighboringCellInfo();
        }
        //得到当前Phone状态
        public int getCurrentPhoneType() {
            ITelephony telephony = getITelephony();
            if (telephony != null) {
                return telephony.getActivePhoneType();
            } else {
                return getPhoneTypeFromProperty();
            }
        }
        //判断是否有SIM卡插入
        public boolean hasIccCard() {
            return getITelephony().hasIccCard();
        }


四、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大大减轻了一些SystemService的负担,为什么只整合了3个SystemService呢?或者说,为什么选中了这3个SystemService来整合呢?
        我们再来梳理以下TelephonyManager的运行原理。经过TelephonyManager的整合,当我们通过Context去得到TelephonyManager对象时,得到的是同一个TelephonyManager对象,那么我们进一步得到的SystemService也是同一个,此时我们调用TelephonyManager中的方法时,得到的返回值也是完全相同的。
        这就说明了,TelephonyManager整合的SystemService,有一个共同特点:这些服务无论谁去调用,方法的返回值都是相同的。比如SIM卡的状态、当前的运营商信息、设备的ID号等。
        而对于存在差异的SystemService,由于对于不同的客户端需要返回不同的值,当然就无法放到TelephonyManager中处理了。
版权声明:本文为博主原创文章,未经博主允许不得转载。

Android dataonly、wifionly的判别方式

推荐wifionly 和 dataonly判断方法:      public static boolean isVoiceCapable(Context context) {         Te...

第86章、系统服务之TELEPHONY_SERVICE(从零开始学Android)

TelephonyManager类主要提供了一系列用于访问与手机通讯相关的状态和信息的get方法。其中包括手机SIM的状态和信息、电信网络的状态及手机用户的信息。在应用程序中可以使用这些get方法获取...

[androdi基础知识] 之十六: ((TelephonyManager)paramContext.getSystemService("phone")).getDeviceId();语句的理解

前提:paramContext是一个preferenceActivity,它的getSystemService("phone")).getDeviceId()用于干什么呢? 参考:http://b...

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

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

Android提高第十四篇之探秘TelephonyManager

通过JAVA反射机制和自定义的ITelephony.aidl,来获取TelephonyManager 在SDK中尚未提供的功能,如接听/挂断电话,开启/关闭Radio,开启/关闭数据连接等。...
  • hellogv
  • hellogv
  • 2010年12月09日 16:44
  • 33446

(M)SIM卡开机流程分析之TelephonyManager类分析

首先在PhoneFactory的makeDefaultPhone方法中,调用了TelephonyManager.getDefault方法 int numPhones = TelephonyManag...

Android之TelephonyManager

在Android平台中,通过TelephonyManager可以访问与手机通讯相关的信息,比如设备信息、网络信息及SIM卡信息,同时还可以监听电话的相关状态。下面我们通过几个方面来说明Android平...

TelecomManager与TelephonyManager区别与分析

许久没有写Blog了,其实这段时间的工作,可以写的内容有很多,但是其一是因为工作太忙了没有时间进行整理,其二则是自己懒了,说是没有时间,但是如果想的话,总能找到时间来进行的,不是吗?这次我想讨论的话题...

使用TelephonyManager监听通话事件的内存泄露

//使用TelephonyManager 对通话的监听TelephonyManager telephonyManager = (TelephonyManager) context.getSystemS...

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

前言 本文主要讲解Telephony中Phone相关的知识 ,1. Android N中Phone的改变。 Android 6.0时,Phone的继承关系:...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Telephony之TelephonyManager(原)
举报原因:
原因补充:

(最多只允许输入30个字)