Android电话录音文件



本人最近开发电话软件,大概是通过pc分发指令,实现电话拨打,挂机,录音文件上传功能,说起来是和简单,实际还是遇到很多问题,现在贴出来,与猿友一起共勉。


问题一:实现自动拨打电话,有人认为只能最多实现跳转到拨号界面,这是不可能的,现在跳转到拨号界面,并自动拨号的方式,前提要动态申请权限哦

/**
     * 拨打电话(直接拨打电话
     *
     * @param context
     * @param phoneNum 电话号码
     */
    public void callPhone(Context context, String phoneNum) {
        Intent intent = new Intent(Intent.ACTION_CALL);
        Uri data = Uri.parse("tel:" + phoneNum);
        intent.setData(data);
        context.startActivity(intent);
    }

问题二:自动挂断电话,这个东西由于Android系统设有安全权限,只能通过aidl拿到权限,新建aidl文件,此时要注意路径,

android实现多录音 android录音组件_拨打电话

package com.android.internal.telephony;
 /**
 * Interface used to interact with the phone. Mostly this is used by the
 * TelephonyManager class. A few places are still using this directly.
 * Please clean them up if possible and use TelephonyManager instead.
 * {@hide}
 */

interface ITelephony {
 /**
 * End call or go to the Home screen
 * @return whether it hung up
 */
 boolean endCall();
 
 }
public void endCallnew() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, RemoteException {
        TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
        Class clazz = Class.forName(telephonyManager.getClass().getName());
        Method method = clazz.getDeclaredMethod("getITelephony");
        method.setAccessible(true);
        ITelephony telephonyService = (ITelephony) method.invoke(telephonyManager);
        telephonyService.endCall();
    }

如果你这样写可能就是没有办法适配9.0,这个9.0适配也是找了很久,有个哥们说看到谷歌说是这样解决的。完整的解决方案应该是这样的

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    private boolean cutTheCall() {
        TelecomManager telecomManager = (TelecomManager) getApplicationContext().getSystemService(TELECOM_SERVICE);
        if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED || telecomManager == null) {
            return false;
        }

        if (telecomManager.isInCall()) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
                telecomManager.endCall();
            } else {
                try {
                    endCallnew();
                } catch (ClassNotFoundException e) {
                    e.printStackTrace();
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
        return true;
    }

问题四:获取录音文件,这个可是要剑走偏锋了,因为开始Android录音功能,这样只能听到我方的录音,听不到对方录音,但是用户开启自动录音功能(每个手机都有录音功能),或者手动打开录用功能,通过获取手机型号就能拿到指定路径下的录音文件,比如你录音完成时候,系统会提醒你录音文件保存的位置,找文件,上传肯定没问题了。

public String getPath() {
        s.clear();
        Path.clear();
        File parent = Environment.getExternalStorageDirectory();
        File child;
        switch (getDeviceBrand().toUpperCase()) {
            case "HUAWEI":
                // child = new File(parent, "record");
                child = new File(parent, "Sounds/CallRecord/");
                break;
            case "XIAOMI":
                child = new File(parent, "MIUI/sound_recorder/call_rec");
                // child = new File(parent, "MIUI/sound_recorder");
                break;
            case "MEIZU":
                child = new File(parent, "Recorder");
                break;
            case "OPPO":
                child = new File(parent, "Recordings/Call Recordings");
                break;
            case "VIVO":
                child = new File(parent, "Record/Call");
                break;
            case "SAMSUNG":
                child = new File(parent, "Sounds");
                break;
            default:
                child = new File(parent, "");
                break;
        }
        return child.getPath();
    }

问题五:监听电话状态,比如来电,去电,常用的方式是通过server开启广播,通过继承PhoneStateListener,复写onCallStateChanged函数,根据 super.onCallStateChanged(state, phoneNumber);状态来判定电话状态

public class CallListener extends PhoneStateListener {


    @Override
    public void onCallStateChanged(int state, String phoneNumber) {
        super.onCallStateChanged(state, phoneNumber);
        switch (state) {
            case TelephonyManager.CALL_STATE_IDLE://通话状态空闲
                break;
            case TelephonyManager.CALL_STATE_OFFHOOK://通话状态摘机
         
                break;
            case TelephonyManager.CALL_STATE_RINGING://呼叫状态振铃
                break;
        }
    }
}

但是这种方案一般是完全没问题,如果对方是没有开启来电显示呢,onCallStateChanged这个函数中的来电号码就会报空指针异常了,鄙人采用这种方式监听来电,也不用server,节省资源,不容被系统杀死,这样绕过了获取来电导致的异常,一举两得

package com.example.phoneproject.common.phoneing;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.example.phoneproject.common.EventPhone;
import com.example.phoneproject.common.GetMessagePhone;

import org.greenrobot.eventbus.EventBus;

/**
 * author : Liuyh
 * date : 2020/9/7 13:49
 * description :
 * ************************************************
 * Update author :
 * Update time :
 * Update description :
 */
public class PhoneReceiver extends BroadcastReceiver {

    private Context mContext;
    public static boolean isZhujiaoTonghua = false;//主叫通话

    @Override
    public void onReceive(Context context, Intent intent) {
        //   System.out.println("actionSSSSS" + intent.getAction());
        String action = intent.getAction();

        this.mContext = context;
        if (action.equalsIgnoreCase(Intent.ACTION_NEW_OUTGOING_CALL)) {//判断来电还是去电
            //获得相应的系统服务
            TelephonyManager tm = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
            /**
             * 返回电话状态
             *
             * CALL_STATE_IDLE 无任何状态时
             * CALL_STATE_OFFHOOK 接起电话时
             * CALL_STATE_RINGING 电话进来时
             */
            // tm.getCallState();
            if (tm.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
               // Log.d("test", "call state idle...");
                isZhujiaoTonghua = true;
            } else if (tm.getCallState() == TelephonyManager.CALL_STATE_OFFHOOK) {
                //Log.e("start","end");
                isZhujiaoTonghua = true;
            }
//            else if (tm.getCallState() == TelephonyManager.CALL_STATE_RINGING) {
//                Log.d("test", "call state ringing...");
//            }

            // isZhujiaoTonghua=true;
        } else {
            String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
//            if (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_RINGING)) {// 电话正在响铃
//                if (isZhujiaoTonghua) {
//                    System.out.println("CallA" + intent.getAction());
//                }
//            } else
                if (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)) {// 挂断
                if (isZhujiaoTonghua) {
                    isZhujiaoTonghua = false;
                }
            }
//            else if (state.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_OFFHOOK)) {// 摘机,通话状态
//                if (isZhujiaoTonghua) {
//                    System.out.println("CallB" + intent.getAction());
//                }
//            }
        }
    }
}

还要加上清单文件监听呢

<service
            android:name=".CallServer"
            android:enabled="true"
            android:priority = "1000"
            android:exported="true" /> <!-- 挂断电话 -->

鄙人只用到去电,嗯,目前就用到这些。
问题六:实现程序长期后台驻留,嗯,,,这个是个伪命题,没有象苹果那样的方式,Android系统真是英雄为难英雄,解决方案还是有的,公司不差钱,可以做一些定制机,华为,小米都有类似服务,剩下只能安装一些做些设置喽,即便如此,也不能保证就是没有问题

1.确保本软件获取本机通话,录音等权限;
2.设置手机通话为自动录音;
3.请将手机来连接WIFI,保持WIFI信号良好;
4.允许本APP后台运行;
5.取消省电模式,进入省电模式接入充电器;
6.设置休眠状态下保持WLAN连接;

剩下的就是用到长链接与心跳机制,这里就看下一篇吧