2013-09-24 42 views
26

我看到一些SO帖子,讨论了如何以编程方式结束电话,例如,this one。是的,人们关注的结果,但没有人真正解释原因为什么它的作品?为什么ITelephony.aidl有效?

我试过了代码,它工作的很好。但我想知道更多关于下面发生了什么的细节?为什么通过创建ITelephony.aidl,android隐藏的内部ITelephony接口暴露在我们的项目中?我们如何创建ITelephony.aidl &自动生成的java(/gen/ITelephony.java)链接到 android的ITelephony接口?仅仅是因为名称匹配(包名称& aidl文件名)?

TelephonyManager tm = (TelephonyManager) context 
       .getSystemService(Context.TELEPHONY_SERVICE); 

Class c = Class.forName(tm.getClass().getName()); 
Method m = c.getDeclaredMethod("getITelephony"); 
m.setAccessible(true); 

//Why does the android internal ITelephony interface is exposed after created the ITelephony.aidl? 
com.android.internal.telephony.ITelephony telephonyService = (ITelephony) m.invoke(tm); 
telephonyService.endCall(); 

回答

72

其实,将ITelephony.aidl添加到您的项目是没有必要的,这只是一个方便。你也可以同样做这种方式:

TelephonyManager tm = (TelephonyManager) context 
      .getSystemService(Context.TELEPHONY_SERVICE); 
Class c = Class.forName(tm.getClass().getName()); 
Method m = c.getDeclaredMethod("getITelephony"); 
m.setAccessible(true); 
Object telephonyService = m.invoke(tm); // Get the internal ITelephony object 
c = Class.forName(telephonyService.getClass().getName()); // Get its class 
m = c.getDeclaredMethod("endCall"); // Get the "endCall()" method 
m.setAccessible(true); // Make it accessible 
m.invoke(telephonyService); // invoke endCall() 

在幕后此使用Java反射的所有作品,访问私(即:未公开记录)的方法。您可以通过阅读开放源代码(即:公开可用的)Android源代码来了解哪些方法以及它们的功能。一旦你知道那里有什么和它做了什么,你可以使用反射来实现它,即使它是“隐藏的”。

TelephonyManager类是使用远程服务实现的。如果您想请求TelephonyManager为您做某些事情,请拨打TelephonyManager(这是公开记录的部分)的方法,并在内部拨打远程电话服务的电话以实际完成工作。这是使用AIDL完成的,这是一种“远程过程调用”。远程服务可以通过TelephonyManager课程公开暴露的内容。你在这里做的是使用getITelephony()获得“远程过程调用”接口的客户端。这将返回ITelephony类型的对象。这个类有一个名为endCall()的方法。一旦我们得到类型为ITelephony的对象,就可以获得它的Class对象,然后从Class中获取方法endCall()。一旦我们有了这个方法,我们就可以访问它,而不是通话。方法endCall()位于远程过程调用的客户端。该方法现在向电话管理器服务(在远程服务器上运行)发送一条消息,并要求它结束呼叫。

因为用于ITelephony.aidl的源代码是公开的,你可以把源代码在你的项目,你的IDE会产生ITelephony.java(其中包含远程过程调用的客户端)从ITelephony.aidl。然后您可以只需import即可,您的IDE现在将知道ITelephony类及其方法。这允许编译器在编译项目时生成正确的字节码。当您在Android设备上运行此代码时,您会调用Android框架以获取ITelephony对象,然后将其转换为com.android.internal.telephony.ITelephony。从此,只要您对ITelephony的Java代码与返回的ITelephony对象的实际类定义匹配,就可以使用生成的ITelephony.java访问对象的方法和字段。如果类定义不匹配,虚拟机将引发适当的异常。

我希望这能回答你的问题。我不确定你已经知道了多少,所以也许我提到了你已经知道的东西。如果是这样,对此感到抱歉。如果不清楚,请指出您不明白的内容。

+1

谢谢它帮助我设计。做得好 – RobinSingh

+0

难道只是我还是这个不适合Android 4.2.2 – 130nk3r5

+1

太棒了,详细的答案。谢谢。注意:我不相信Android 4.0.3之后的块调用可以工作,因为这个API已被删除。 – raddevus