由于系统API并没有给我们提供Itelephony这个电话管理服务类的接口使用,所以我们就得通过非正常手段来得到这个服务接口.(通过源码中的Itelephony.aidl来帮助我们生成电话管理服务接口,从而使我们能够使用到系统操作电话的功能).
例如>>结束通话:
1> 拷贝连同包结构将用到的Itelephony.aidl文件到你的项目中
(由于其中引入了android.telephony.NeighboringCellInfo.aidl, 所以将其也引入到你的项目中去)
要想挂断电话必须具有<uses-permission android:name="android.permission.CALL_PHONE"/>权限
try{ //反射获得系统服务的getService方法对象 Method method = Class.forName("android.os.ServiceManager") .getMethod("getService", String.class); //执行这个方法得到一个IBinder对象 IBinder binder = (IBinder) method.invoke(null, new Object[]{TELEPHONY_SERVICE}); //转换为具体的服务类(ITelephony)接口对象 ITelephony telephony = ITelephony.Stub.asInterface(binder); //结束通话 telephony.endCall(); //从上是通过 反射来做的, 下面正常的做法>> 按下面来做 // IBinder bindr = ServiceManager.getService(TELEPHONY_SERVICE); // ITelephony telephony2 = ITelephony.Stub.asInterface(binder); // telephony2.endCall(); }catch(Exception e){ e.printStackTrace(); } |
下面来看看它是怎样的一个机制来操作电话管理功能的.
首先我们要知道所有的服务类都是在与服务管理器交互.服务管理器把所有的服务都纳入到它的管理范畴.而那些系统框架中的各个服务工具类底层都是与这个服务管理器大管家交互.
我是通过 ServiceManager这个系统框架提供服务管理器来得到Itelephony这个服务的Binder对象的
ServiceManager è系统框架上的所有服务都在后来运行着.要想得这些服务 就得通过 这个方法getService来获得
public static IBinder getService(String name) {//取得服务的Ibinder对象
try {
IBinder service = sCache.get(name);//先从缓存上找到这个服务的IBinder
if (service != null) {
return service;
} else { //如果为空就通过服务管理器接口实现类的getService方法来得到你想要的服务
return getIServiceManager().getService(name);
}
} catch(RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
public static void addService(Stringname, IBinder service){//往服务管理器中追加一个服务
public static IBinder checkService(String name)…..//检索已经存在的Service
public static String[] listServices() throwsRemoteException//列出当前以有的服务
下面来看看class ContextImplextends Context类
@Override
public Object getSystemService(String name) {
if (WINDOW_SERVICE.equals(name)) {
returnWindowManagerImpl.getDefault();
} else if (ACTIVITY_SERVICE.equals(name)) {
returngetActivityManager();
}else if (TELEPHONY_SERVICE.equals(name)) {
return getTelephonyManager();
…..以下略
private TelephonyManager getTelephonyManager() {
synchronized (mSync) {
if (mTelephonyManager == null) {
mTelephonyManager = new TelephonyManager(getOuterContext());
}
}
return mTelephonyManager;
}
以下是TelephonyManager类的构造方法
/** @hide */
public TelephonyManager(Context context) {
mContext = context;
mRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
"telephony.registry"));
}
privateIPhoneSubInfo getSubscriberInfo() {
// get it each time because that process crashes a lot
returnIPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo"));
}
private ITelephony getITelephony() {
return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));
}
public void listen(PhoneStateListener listener, int events) {
String pkgForDebug = mContext != null ? mContext.getPackageName() : "<unknown>";
try {
Boolean notifyNow =(getITelephony() != null);
mRegistry.listen(pkgForDebug, listener.callback, events,notifyNow);
} catch(RemoteException ex) {
// system process dead
} catch(NullPointerException ex) {
// system process dead
}
}
在TelephonyManager类中只是通过服务管理器来得到不同的具体服务者进而提供电话的一些基本信息和注册对电话状态监听的回调, 并没有提供给可以挂断电话的功能
那系统是怎样挂断电话呢…?
最后没有找到有挂断电话的功能方法,但是在ITelephony.aidl文件中找到了
/**
* End call or go to the Home screen
*
* @return whether it hung up
*/
booleanendCall();
我们知道AIDL文件是Android接口描述语言。Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信. 为使其他的应用程序也可以访问本应用程序提供的服务,Android系统采用了远程过程调用(Remote Procedure Call,RPC)方式来实现.这种以跨进程访问的服务称为AIDL(Android Interface Definition Language)服务.
这也就是说明我们可以通过此AIDL来访问到Itelephony这个接口提供的endCall功能.
加载完成后通过ITelephony telephony2 = ITelephony.Stub.asInterface(binder);把Binder对象转换成对应的服务端的代理对象,然后就通过这个Itelephony服务类在调用端的代理来完成挂断电话的功能.