Telephony之TelephonyManager(原)

一、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中处理了。
  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值