美文网首页Android开发经验谈
android 通话过程中发送数字指令DTMF

android 通话过程中发送数字指令DTMF

作者: 大胡子的机器人 | 来源:发表于2019-08-21 17:11 被阅读6次
    场景:

    接管系统的拨号盘及电话应用,需要拨打如中国移动等运营商时能发送数字按键指令。(mtk的手机方案)

    参考文档:

    发送dtmf键盘事件(模拟通话界面键盘事件)

    需要权限:

    系统权限及系统签名
    在AndroidManifest.xml里增加

    android:sharedUserId="android.uid.phone" 或 android:sharedUserId="android.uid.system"
    
    遇到的问题:

    由于我们定制了拨号界面,里面有很多交互逻辑以及第三方依赖,不可能将这个页面单独设置为android:process="com.android.phone"进程,但发送dtmf又必须在这个进程中。

    解决方案:

    单独将发送dtmf的功能独立到com.android.phone进程的service中

    package ***.service;
    
    import android.app.Service;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.IBinder;
    import android.util.Log;
    import java.lang.reflect.Method;
    
    public class DtmfSendService extends Service {
    
    private String ACTION_SEND_DTMF = "net.bonvo.client.bonvobox.send_dtmf";
    private String TAG = "DtmfSendService";
    private SendDtmfReceiver mReceiver;
    @Override
    public void onCreate() {
        super.onCreate();
        registerReceiver();
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mReceiver != null) {
            unregisterReceiver(mReceiver);
        }
    }
    
    private void registerReceiver() {
        mReceiver = new SendDtmfReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(ACTION_SEND_DTMF);
        registerReceiver(mReceiver, filter);
    }
    
    public void sendDtmf(char keycode) {
        //https://blog.csdn.net/jinliang_890905/article/details/43458877
        //https://www.cnblogs.com/IT-Goddess/p/5725705.html
        //https://stackoverflow.com/questions/4745899/how-to-access-com-android-internal-telephony-callmanager
        //源码:http://androidxref.com/9.0.0_r3/xref/frameworks/opt/telephony/src/java/com/android/internal/telephony/CallManager.java#1216
        try {
            ClassLoader classLoader = ClassLoader.getSystemClassLoader();
            final Class<?> classCallManager = classLoader.loadClass("com.android.internal.telephony.CallManager");
            Log.i(TAG, "Class loaded " + classCallManager.toString());
    
            Method methodGetInstance = classCallManager.getDeclaredMethod("getInstance");
            Log.i(TAG, "Method loaded " + methodGetInstance.getName());
    
            Object objectCallManager = methodGetInstance.invoke(null);
            Log.i(TAG, "Object loaded " + objectCallManager.getClass().getName());
    
            Method methodSendDtmf = classCallManager.getDeclaredMethod("sendDtmf", char.class);
            methodSendDtmf.setAccessible(true);
            Log.i(TAG, "Method loaded " + methodSendDtmf.getName());
    
            Log.i(TAG, "SendDtmf = " + methodSendDtmf.invoke(objectCallManager, keycode));
    
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    class SendDtmfReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent.getAction() != null && intent.getAction().contentEquals(ACTION_SEND_DTMF)) {
                char code = intent.getCharExtra("dtmfCode",'-');
                if (code != '-') {
                    Log.e(TAG,"发送dtmf=" + code);
                    sendDtmf(code);
                }
            }
        }
    }
    }
    

    清单文件中申明service

    <service android:name="***.service.DtmfSendService"
            android:process="com.android.phone" />
    
    使用方法:
    1、在通话界面先启动startService
    2、需要发送指令时发送
        Intent dtmfIntent = new Intent();
        dtmfIntent.setAction(CustomAction.SEND_DTMF);
        dtmfIntent.putExtra("dtmfCode",key);
        sendBroadcast(dtmfIntent);
    

    相关文章

      网友评论

        本文标题:android 通话过程中发送数字指令DTMF

        本文链接:https://www.haomeiwen.com/subject/kyeisctx.html