Android(安卓)Telephony分析(四) ---- TelephonyManager详解
前言
TelephonyManager主要提供Telephony相关信息的查询/修改功能,以及Phone状态监听功能,封装的方法主要是提供给APP上层使用。
TelephonyManager.java 在frameworks\base\telephony\java\android\telephony目录下。
1. TelephonyManager整体结构
从TelephonyManager导入的文件中可以发现有四个接口
import com.android.internal.telecom.ITelecomService;import com.android.internal.telephony.IPhoneSubInfo;import com.android.internal.telephony.ITelephony;import com.android.internal.telephony.ITelephonyRegistry;
分别对应下面这几个AIDL接口:
\frameworks\base\telecomm\java\com\android\internal\telecom\ITelecomService.aidl\frameworks\base\telephony\java\com\android\internal\telephony\IPhoneSubInfo.aidl\frameworks\base\telephony\java\com\android\internal\telephony\ITelephony.aidl\frameworks\base\telephony\java\com\android\internal\telephony\ITelephonyRegistry.aidl
所以可以猜测到,在TelephonyManager中可以得到这四种Service。
通过所有文件中搜索”extends 接口名.Stub”,如”extends ITelephony.Stub”,可以找到是哪些类实现了上面四个AIDL接口中的方法,整理可得:
在TelephonyManager中搜索”接口名.Stub.asInterface”,如”ITelephony.Stub.asInterface”,可以找到这四个Service的名字,整理可得:
接口 | 服务端 | Service Name |
---|---|---|
ITelecomService.aidl | TelecomServiceImpl.java | telecom (TELECOM_SERVICE) |
IPhoneSubInfo.aidl | PhoneSubInfoController.java | iphonesubinfo |
ITelephony.aidl | PhoneInterfaceManager.java | phone (TELEPHONY_SERVICE) |
ITelephonyRegistry.aidl | TelephonyRegistry.java | telephony.registry |
好了,下面分别对这四种Service进行分析:
本文来自 http://blog.csdn.net/linyongan ,转载请务必注明出处。
1.1 TelecomServiceImpl—Telecom Service
服务端TelecomServiceImpl中有mBinderImpl实现了ITelecomService接口中的方法
public class TelecomServiceImpl { private final ITelecomService.Stub mBinderImpl = new ITelecomService.Stub() { ... }}
在TelecomLoaderService.java中,TelecomServiceImpl把自己注册到ServiceManager中,
ServiceManager.addService(Context.TELECOM_SERVICE, service);
所以在TelephonyManager中可以通过ServiceManager得到Telecom Service
private ITelecomService getTelecomService() { //得到TelecomServiceImpl的代理对象 return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE)); }
其实Telecom Service的最常用客户端是TelecomManager.java。而在TelephonyManager中由于无法得到CallManager对象,所以只能依赖Telecom Service获取Call State。
/** * Returns one of the following constants that represents the current state of all * phone calls. * * {@link TelephonyManager#CALL_STATE_RINGING} * {@link TelephonyManager#CALL_STATE_OFFHOOK} * {@link TelephonyManager#CALL_STATE_IDLE} */ public int getCallState() { try { ITelecomService telecom = getTelecomService(); if (telecom != null) { return telecom.getCallState(); } } catch (RemoteException e) { Log.e(TAG, "Error calling ITelecomService#getCallState", e); } return CALL_STATE_IDLE; }
所以,总体上来说,虽然TelecomManager得到了Telecom Service,但其实作用不大。相反,Telecom Service中会反过来得到TelephonyManager对象,进一步实现自己的方法,如在TelecomServiceImpl.java中:
public String getVoiceMailNumber(PhoneAccountHandle accountHandle, String callingPackage) { ... return getTelephonyManager().getVoiceMailNumber(subId); ... } private TelephonyManager getTelephonyManager() { return (TelephonyManager)mContext.getSystemService(Context.TELEPHONY_SERVICE); }
1.2 PhoneSubInfoController— “iphonesubinfo” Service
服务端PhoneSubInfoController继承自IPhoneSubInfo.Stub
public class PhoneSubInfoController extends IPhoneSubInfo.Stub {
在创建Default Phone对象之后,ProxyController对象在PhoneFactory.java的makeDefaultPhone()中被初始化
public static void makeDefaultPhone(Context context) { ... //先初始化ProxyController mProxyController = ProxyController.getInstance(context, sProxyPhones, mUiccController, sCommandsInterfaces); ... } private ProxyController(Context context, PhoneProxy[] phoneProxy, UiccController uiccController, CommandsInterface[] ci) { ... //在ProxyController的构造方法中初始化了PhoneSubInfoController对象 mPhoneSubInfoController = new PhoneSubInfoController(mContext, mPhones); ... } public PhoneSubInfoController(Context context, Phone[] phone) { mPhone = phone; if (ServiceManager.getService("iphonesubinfo") == null) { //将PhoneSubInfoController实例注册到ServiceManager中 ServiceManager.addService("iphonesubinfo", this); } mContext = context; mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); }
所以在TelephonyManager中可以通过ServiceManager得到”iphonesubinfo” Service
private IPhoneSubInfo getSubscriberInfo() { // get it each time because that process crashes a lot return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo")); }
通过”iphonesubinfo” Service可以得到software version、deviceID、VoiceMail Number等信息,TelephonyManager在这里只是对这些方法进一步封装,这些方法具体的实现,最后还是通过Phone实例和IsimRecords实例来完成的。
以getMsisdn()方法为例,最常见的调用方式如下:
备注:在Android N中已删除PhoneSubInfo.java和PhoneSubInfoProxy.java,所以流程变得简单了。
1.3 PhoneInterfaceManager—Telephony Service
TelephonyManager依赖Telephony Service实现了大部分的方法。
PhoneInterfaceManager继承自ITelephony.Stub
public class PhoneInterfaceManager extends ITelephony.Stub {
PhoneInterfaceManager.java在 packages\services\telephony\src\com\android\phone目录下,显然它是运行在Phone进程中的。
在Phone进程启动时,Default Phone对象创建完之后,PhoneInterfaceManager对象在PhoneGlobals的onCreate()中被初始化:
public void onCreate() { ... phoneMgr = PhoneInterfaceManager.init(this, PhoneFactory.getDefaultPhone()); ... } /* package */ static PhoneInterfaceManager init(PhoneGlobals app, Phone phone) { synchronized (PhoneInterfaceManager.class) { if (sInstance == null) { //初始化PhoneInterfaceManager sInstance = new PhoneInterfaceManager(app, phone); } else { Log.wtf(LOG_TAG, "init() called multiple times! sInstance = " + sInstance); } return sInstance; } }
在PhoneInterfaceManager的构造方法中:
private PhoneInterfaceManager(PhoneGlobals app, Phone phone) { //得到一些关键类 mApp = app; mPhone = phone; mCM = PhoneGlobals.getInstance().mCM; mUserManager = (UserManager) app.getSystemService(Context.USER_SERVICE); mAppOps = (AppOpsManager)app.getSystemService(Context.APP_OPS_SERVICE); mMainThreadHandler = new MainThreadHandler(); mTelephonySharedPreferences = PreferenceManager.getDefaultSharedPreferences(mPhone.getContext()); mSubscriptionController = SubscriptionController.getInstance(); publish(); } private void publish() { //将PhoneInterfaceManager实例注册到ServiceManager中 ServiceManager.addService("phone", this); }
在PhoneInterfaceManager初始化的时候,把自己注册成SystemServer,这样客户端(如TelephonyManager)则可以通过ServiceManager把它取出来。
private ITelephony getITelephony() { //得到PhoneInterfaceManager的代理对象 return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); }
PhoneInterfaceManager中的方法,最后还是通过Phone实例来实现。
以isImsRegistered()方法为例,最常见的调用方式如下:
1.4 TelephonyRegistry—“telephony.registry” Service
TelephonyRegistry继承自ITelephonyRegistry.Stub
class TelephonyRegistry extends ITelephonyRegistry.Stub {
在SystemServer.java中,
telephonyRegistry = new TelephonyRegistry(context); //将TelephonyRegistry实例注册到ServiceManager中 ServiceManager.addService("telephony.registry", telephonyRegistry);
所以在TelephonyManager中可以通过ServiceManager得到”telephony.registry” Service
if (sRegistry == null) { sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService( "telephony.registry")); }
TelephonyManager主要利用”telephony.registry” Service实现listen()方法,实现对Phone状态的监听的功能
public void listen(PhoneStateListener listener, int events) { if (mContext == null) return; try { Boolean notifyNow = (getITelephony() != null); sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(), listener.callback, events, notifyNow); } catch (RemoteException ex) { // system process dead } catch (NullPointerException ex) { // system process dead } }
关于TelephonyRegistry,后续的文章会详细讲,目前先不用太关注。
2. 如何得到TelephonyManager对象
1、 假如没有Context,可以通过:
private static TelephonyManager sInstance = new TelephonyManager(); public static TelephonyManager getDefault() { return sInstance; }
2、如果能得到Context对象,可以通过:
//注意,这是从SystemService中取TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); //或者TelephonyManager mTelephonyManager = TelephonyManager.from(context);
3. 其他重要方法
TelephonyManager还提供了两个其他比较重要的方法:
/** * Gets the telephony property. * * @hide */ public static String getTelephonyProperty(int phoneId, String property, String defaultVal) { String propVal = null; //根据key获取到value String prop = SystemProperties.get(property); if ((prop != null) && (prop.length() > 0)) { //将value分割成字符串数组 String values[] = prop.split(","); if ((phoneId >= 0) && (phoneId < values.length) && (values[phoneId] != null)) { //取出phoneId对应的value propVal = values[phoneId]; } } return propVal == null ? defaultVal : propVal; } /** * Sets the telephony property with the value specified. * * @hide */ public static void setTelephonyProperty(int phoneId, String property, String value) { ... }
这样子就可以实现对于同一个key,不同phoneId可以存储不同的值。
更多相关文章
- Android兼容性优化-8.0之后禁止在后台启动服务的兼容性优化
- Android版的模拟交通灯
- android学习方法
- Android(安卓)studio for mac 的一些常用快捷键
- View编程(2): invalidate()再探
- LibGDX学习-LibGDX基本框架
- Android和H5交互一篇就够了
- oauth 授权显示无权访问页面问题的解决方法
- 我的android 第24天 - ContentUris和ContentProvider