Framework中的TelephonyManager(原)

一、TelephonyManager的作用


        我们先来谈谈TelephonyManager的作用。
        对于这个问题,我们看TelephonyManager提供的几个重要接口就可以知道:
    //得到软件版本
    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作为一个“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构造函数中得到的,他的 主要作用就是对信号、呼叫转移、位置改变、数据连接状态等信息的监听
    public TelephonyManager(Context context) {
        if (sContext == null) {
            Context appContext = context.getApplicationContext();
            if (appContext != null) {
                sContext = appContext;
            } else {
                sContext = context;
            }
            sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
        }
    }
B、iphonesubinfo服务
        这个服务是在getSubscriberInfo接口中得到的,通过这个服务 可以得到软件版本、设备ID、SIM卡串号、语音信箱等信息
    private IPhoneSubInfo getSubscriberInfo() {
        return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
    }
C、phone服务
        这个服务很特殊,是在Phone模块中注册给系统的(其他服务都是在framework中注册的),主要功能是 Phone模块相关状态的查询和处理,包括位置服务、小区注册信息、当前网络状态、是否有SIM卡插入、以及SIM卡状态等信息。在TelephonyManager中是通过getITelephony接口得到的这个服务:
    private ITelephony getITelephony() {
        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
    }

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

2.2、TelephonyManager方法的具体实现

        我们知道,TelephonyManager的方法是通过3个SystemService去扩展的,那么我们顺着SystemService去分析,看通过这3个SystemService可以扩展出哪些方法。
A、telephony.registry扩展的方法
        首先来看利用sRegistry对象扩展的方法,其实就是telephony.registry服务的扩展功能:
    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) {
        }
    }
        通过telephony.registry扩展的功能只有这一个,这个listen方法的作用就是去注册Phone状态的监听器。我们在TelephonyRegistry服务的介绍中讲到,客户端在得到这个服务后,可以通过listen的方法去注册某个事件的监听器,当这个事件发生时,就会调用所有曾经注册的客户端的回调函数,通知客户端。
B、iphonesubinfo扩展的方法
        上面说道,通过这个服务可以得到软件版本、设备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();
    }
C、phone扩展的方法
        通过这个SystemService得到的方法主要有:
    //得到位置信息
    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自身的注册


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

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

3.1、TelephonyManager的“注册”过程

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

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

        这个过程也很容易理解,就是通过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中处理了。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值