一、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在自己内部同时申请了三个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自身的注册
在介绍使用方法之前,我们先来看看这个类的“注册”过程,了解了他的“注册”方法,我们自然就会明白如何使用他。
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存在的意义
假如现在有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的运行原理。经过TelephonyManager的整合,当我们通过Context去得到TelephonyManager对象时,得到的是同一个TelephonyManager对象,那么我们进一步得到的SystemService也是同一个,此时我们调用TelephonyManager中的方法时,得到的返回值也是完全相同的。
这就说明了,TelephonyManager整合的SystemService,有一个共同特点:这些服务无论谁去调用,方法的返回值都是相同的。比如SIM卡的状态、当前的运营商信息、设备的ID号等。
而对于存在差异的SystemService,由于对于不同的客户端需要返回不同的值,当然就无法放到TelephonyManager中处理了。