一.使用ITelephony接口和ISms接口直接进行电话和短信的操作

1. ITelephony接口和ISms接口以及AIDL
       在我们的Android 应用中,当需要实现电话拨号时,我们需要进行如下调用
        ITelephony phone =(ITelephony)ITelephony.Stub.asInterface(ServiceManager.getService("phone"))
        phone.dial("10086");
       对于短信 应用,我们需要的是调用SmsManager,代码如下
       SmsManager manager = SmsManager.getDefault();
       manager.sendTextMessage("10086",null,"hi,this is sms",null,null);
       这里,SmsManager对ISms做了一层包装,实质上是通过调用
       ISms simISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
      simISms.sendRawPdu....

       应用都是采用AIDL来实现IPC的跨进程调度。
       对于AIDL应用,调用进程方存在的是一个实现接口的Pro xy对象,通过Proxy对象与被调用进程中的Stub对象进行通讯来实现IPC的跨进程调度,所以,在被调用进程一端必定有一个ITelephony.Stub类以及ISms.Stub类的实现

2. PhoneInterfaceManager和SimSmsInterfaceManager
       ITelephony.Stub 的实现类为com.android.phone.PhoneInterfaceManager
       ISms.Stub的实现类为com.android.internal.telephony.gsm.SimSmsInterfaceManager
       从这两个类的构造器的调用代码里可以很清楚的看到进行了Service的注册工作
      ServiceManager.addService("phone",this);
      ServiceManager.addService("isms",this);

3. PhoneApp,InCallScreen,PhoneUtils及其他相关类
       从SimSmsInteferManager的相关方法实现中可以看到,具体就是调用GSMPhone的SmsDispatcher实例来进行相关操作的。
       从PhoneInterfaceManager会维持一个Phone对象的引用,当拨号应用时,PhoneInterfaceManager会将构造好的 Intent传递给PhoneApp应用,该Intent的className指定则为InCallScreen,从中我们可以看到 InCallScreen具体是通过PhoneUtils调用Phone的相关方法来实现。
       PhoneInterfaceManager怎么获取到对应的Phone对象,然后又怎么将Phone对象传递到InCallScreen中呢?
       具体这里涉及到了PhoneApp这个类,从这个类维护了一个 PhoneInterfaceManager的引用(phoneMgr)以及一个Phone引用(phone),从该类的onCreate方法中我们可以 清楚的看到,PhoneApp通过PhoneFactory获取了一个Phone实例,并通过该实例实现了PhoneInterfaceManager对 象。因此,我们现在只需要关PhoneFactory具体提供的是一个什么样的Phone实例了。另外,PhoneApp类还提供了一个静态方法 getInstance供InCallScreen调用,InCallScreen正是通过调用该方法获得PhoneApp实例从而获得对应的Phone 实例的。接下来,我们通过查看PhoneFactory的方法可以看到,Phone对象对应的就是一个GSMPhone实例。

4.GSMPhone与RIL
       从GSM的构造器可以看出,他依赖一个CommandInterface接口实例,通过PhoneFactory makeDefaultPhones方法,我们可以看到,根据系统 环境变量ro.radio.noril来判断是否需要采用RIL框架实现,如果该参数不为空,则采用Simultedcommands(主要是为了测试需要提供的模拟实现)否则,采用RIL。

5.关于C代码与硬件之间的交互
       这部分工作其实就是C代码通过串口发送AT指令来拨号,收发短信。


二.利用反射机制使用ITelephony接口和ISms接口

上文中的方法由于不是系统开发的类和方法,无法直接使用,下面通过java的反射机制进行调用

ps:

    private ITelephony getITelephony() {        return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE));    }
com.android.internal.telephony.ITelephony和android.os.ServiceManager 为系统隐藏类,代码中无法直接使用,而 getITelephony为 TelephonyManager私有方法也无法直接使用

需要用到ITelephony.aidl 和ISms.aidl文件


以ITelephony举例:

通过aidl及反射实现挂断电话
具体分三步:
(1)ITelephony.aidl ,必须新建com.android.internal.telephony包并放入ITelephony.aidl文件(构建后在gen下有ITelephony.java文件,这是aidl生成的接口)。
(2)在需要的类中添加如下方法,代码如下(通过反射获取电话接口的实例)

/**     * @param context     * @return     */    private static ITelephony getITelephony(Context context) {        TelephonyManager mTelephonyManager = (TelephonyManager) context                .getSystemService(TELEPHONY_SERVICE);        Class c = TelephonyManager.class;        Method getITelephonyMethod = null;        try {            getITelephonyMethod = c.getDeclaredMethod("getITelephony",                    (Class[]) null); // 获取声明的方法            getITelephonyMethod.setAccessible(true);        } catch (SecurityException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        }        try {            ITelephony iTelephony = (ITelephony) getITelephonyMethod.invoke(                    mTelephonyManager, (Object[]) null); // 获取实例            return iTelephony;        } catch (Exception e) {            e.printStackTrace();        }        return iTelephony;    }

(3)在来电时调用此实例,然后调用此endCall()方法。

mTelephonyManager = (TelephonyManager) this                .getSystemService(TELEPHONY_SERVICE);        mTelephonyManager.listen(phoneStateListener,                PhoneStateListener.LISTEN_CALL_STATE);//电话实例PhoneStateListener phoneStateListener = new PhoneStateListener() {        @Override        public void onCallStateChanged(int state, String incomingNumber) {            switch (state) {                case TelephonyManager.CALL_STATE_RINGING :                    iTelephony = getITelephony(getApplicationContext()); //获取电话接口                    if (iTelephony != null) {                        try {                            iTelephony.endCall(); // 挂断电话                            Toast.makeText(getApplicationContext(),                                    "endCall "+ incomingNumber +"  successful!", 3000).show();                        } catch (RemoteException e) {                            e.printStackTrace();                        }                    }                    break;                default :                    break;            }        }    };

//注意:在功能清单文件中添加电话的权限:


更多相关文章

  1. ListView为什么要使用convertView和ViewHolder
  2. 使用IDA调试android下的linux程序
  3. activity基本模式
  4. 关于Android(安卓)studio安装出现“ 'tools.jar' seems to be no
  5. Android(安卓)Activity 二
  6. startActivity调用流程及生命周期
  7. [原][Android]All WebView methods must be called on the same
  8. Android(安卓)EditText输入最大长度限制如何给用户以友好的提示
  9. ContentProvider原理分析二 MediaProvider publish .

随机推荐

  1. 在Codeigniter下,是否可能看到mysql_error
  2. 为什么我得到“MySQL没有运行但锁存在”?
  3. 关于DOS界面net start MySQL 启动失败的
  4. 如何在XMLHttpRequest中获取实际文件?
  5. PHP-停止断点会改变行为
  6. PHP:如何检测会话是否已自动过期?
  7. 关于Thinkphp访问不正常的问题
  8. PHP5中数据库抽象层: PDO
  9. 剑指offer--链表中环的入口节点(PHP)
  10. 韩顺平_php从入门到精通_视频教程_学习笔