Android實(shí)現(xiàn)通話自動(dòng)錄音
最近需要做一個(gè)類似于電話客戶的功能,要求撥打電話能自動(dòng)錄音。所以寫了一個(gè)dome,希望能夠幫到大家。
主要思路就是監(jiān)聽手機(jī)通話狀態(tài)在監(jiān)聽到接聽時(shí)開始錄音,結(jié)束停止錄音。
AndroidManifest中配置
<!-- 權(quán)限 --> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" /> <uses-permission android:name="android.permission.RECORD_AUDIO" /> <uses-permission android:name="android.permission.VIBRATE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_CONTACTS" /> <uses-permission android:name="android.permission.WRITE_CONTACTS" /> <uses-permission android:name="com.android.launcher.permission.READ_SETTINGS" /> <uses-permission android:name="android.permission.READ_CALL_LOG" /> <uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.WRITE_CALL_LOG" /> <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" /> <uses-permission android:name="android.permission.GET_ACCOUNTS" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
當(dāng)然了還要在清單文件中注冊service
public abstract class CommonAdapter<T> extends BaseAdapter{ protected Context mContext; protected List<T> mList; protected int mLayoutId; public CommonAdapter(Context context, List<T> list, int layoutId) { mContext=context; mList=list; mLayoutId=layoutId; } //刷新數(shù)據(jù) public void refresh(List<T> list){ mList=list; notifyDataSetChanged(); } @Override public int getCount() { return mList.size(); } @Override public T getItem(int position) { return mList.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = ViewHolder.getHolder(mContext, mLayoutId, convertView, parent); convertView(holder,mList.get(position)); return holder.getConvertView(); } public abstract void convertView(ViewHolder holder,T t); }
public class RBOutPhoneCallState { Context ctx; public RBOutPhoneCallState(Context ctx) { this.ctx = ctx; } /** * 前臺呼叫狀態(tài) * */ public static final class ForeGroundCallState { public static final String DIALING = "com.sdvdxl.phonerecorder.FORE_GROUND_DIALING"; public static final String ALERTING = "com.sdvdxl.phonerecorder.FORE_GROUND_ALERTING"; public static final String ACTIVE = "com.sdvdxl.phonerecorder.FORE_GROUND_ACTIVE"; public static final String IDLE = "com.sdvdxl.phonerecorder.FORE_GROUND_IDLE"; public static final String DISCONNECTED = "com.sdvdxl.phonerecorder.FORE_GROUND_DISCONNECTED"; } /** * 開始監(jiān)聽呼出狀態(tài)的轉(zhuǎn)變, * 并在對應(yīng)狀態(tài)發(fā)送廣播 */ public void startListen() { new RBReadPhoneLog(ctx).start(); Log.d("Recorder", "開始監(jiān)聽呼出狀態(tài)的轉(zhuǎn)變,并在對應(yīng)狀態(tài)發(fā)送廣播"); } }
public class RBPhoneListener extends PhoneStateListener { public RBRecorder recorder; @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); switch (state) { case TelephonyManager.CALL_STATE_IDLE: // 空閑狀態(tài),即無來電也無去電 Log.i("TelephoneState", "IDLE"); //此處添加一系列功能代碼 if (recorder != null && !recorder.isCommingNumber() && recorder.isStarted()) { Log.i("TelephoneState", "STOP RECORDER"); recorder.stop(); } break; case TelephonyManager.CALL_STATE_RINGING: // 來電響鈴 Log.i("TelephoneState", "RINGING"); //此處添加一系列功能代碼 break; case TelephonyManager.CALL_STATE_OFFHOOK: // 摘機(jī),即接通 Log.i("TelephoneState", "OFFHOOK"); //此處添加一系列功能代碼 if (recorder == null) { recorder = new RBRecorder(); } if (!recorder.isStarted()) { Log.i("TelephoneState", "START RECORDER"); if (incomingNumber != null && incomingNumber.length() >= 8) { //CALLID recorder.setPhoneNumber(String.valueOf(incomingNumber)); } if (!recorder.isCommingNumber() && !recorder.isStarted()) { recorder.start(); } } break; } Log.i("TelephoneState", String.valueOf(incomingNumber)); } }
public class RBReadPhoneLog extends Thread { private Context ctx; private int logCount; private static final String TAG = "LogInfo OutGoing Call"; /** * 前后臺電話 * */ private static class CallViewState { public static final String FORE_GROUND_CALL_STATE = "mForeground"; } /** * 呼叫狀態(tài) * */ private static class CallState { public static final String DIALING = "DIALING"; public static final String ALERTING = "ALERTING"; public static final String ACTIVE = "ACTIVE"; public static final String IDLE = "IDLE"; public static final String DISCONNECTED = "DISCONNECTED"; } public RBReadPhoneLog(Context ctx) { this.ctx = ctx; } /** * 讀取Log流 * 取得呼出狀態(tài)的log * 從而得到轉(zhuǎn)換狀態(tài) */ @Override public void run() { Log.d(TAG, "開始讀取日志記錄"); String[] catchParams = {"logcat", "InCallScreen *:s"}; String[] clearParams = {"logcat", "-c"}; try { Process process=Runtime.getRuntime().exec(catchParams); InputStream is = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(is)); String line = null; while ((line=reader.readLine())!=null) { logCount++; //輸出所有 Log.v(TAG, line); //日志超過512條就清理 if (logCount>512) { //清理日志 Runtime.getRuntime().exec(clearParams) .destroy();//銷毀進(jìn)程,釋放資源 logCount = 0; Log.v(TAG, "-----------清理日志---------------"); } /*---------------------------------前臺呼叫-----------------------*/ //空閑 if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE) && line.contains(RBReadPhoneLog.CallState.IDLE)) { Log.d(TAG, RBReadPhoneLog.CallState.IDLE); } //正在撥號,等待建立連接,即已撥號,但對方還沒有響鈴, if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE) && line.contains(RBReadPhoneLog.CallState.DIALING)) { //發(fā)送廣播 Intent dialingIntent = new Intent(); dialingIntent.setAction(RBOutPhoneCallState.ForeGroundCallState.DIALING); ctx.sendBroadcast(dialingIntent); Log.d(TAG, RBReadPhoneLog.CallState.DIALING); } //呼叫對方 正在響鈴 if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE) && line.contains(RBReadPhoneLog.CallState.ALERTING)) { //發(fā)送廣播 Intent dialingIntent = new Intent(); dialingIntent.setAction(RBOutPhoneCallState.ForeGroundCallState.ALERTING); ctx.sendBroadcast(dialingIntent); Log.d(TAG, RBReadPhoneLog.CallState.ALERTING); } //已接通,通話建立 if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE) && line.contains(RBReadPhoneLog.CallState.ACTIVE)) { //發(fā)送廣播 Intent dialingIntent = new Intent(); dialingIntent.setAction(RBOutPhoneCallState.ForeGroundCallState.ACTIVE); ctx.sendBroadcast(dialingIntent); Log.d(TAG, RBReadPhoneLog.CallState.ACTIVE); } //斷開連接,即掛機(jī) if (line.contains(RBReadPhoneLog.CallViewState.FORE_GROUND_CALL_STATE) && line.contains(RBReadPhoneLog.CallState.DISCONNECTED)) { //發(fā)送廣播 Intent dialingIntent = new Intent(); dialingIntent.setAction(RBOutPhoneCallState.ForeGroundCallState.DISCONNECTED); ctx.sendBroadcast(dialingIntent); Log.d(TAG, RBReadPhoneLog.CallState.DISCONNECTED); } } } catch (IOException e) { e.printStackTrace(); } }
public class RBRecorder { private String phoneNumber; private MediaRecorder mrecorder; private boolean started = false; // 錄音機(jī)是否啟動(dòng) private boolean isCommingNumber = false;// 是否是來電 private String TAG = "Recorder"; public RBRecorder(String phoneNumber) { this.setPhoneNumber(phoneNumber); } public RBRecorder() { } public void start() { started = true; mrecorder = new MediaRecorder(); String fileName = new SimpleDateFormat("yy-MM-dd_HH-mm-ss") .format(new Date(System.currentTimeMillis())) + ".mp3"; String fileSavePath = getFilePath(fileName); File recordName = new File(fileSavePath); try { recordName.createNewFile(); Log.d("recorder", "創(chuàng)建文件" + recordName.getName()); } catch (IOException e) { e.printStackTrace(); } mrecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); mrecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); mrecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); mrecorder.setOutputFile(recordName.getAbsolutePath()); try { mrecorder.prepare(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } mrecorder.start(); started = true; Log.d(TAG, "錄音開始"); } public void stop() { try { if (mrecorder != null) { mrecorder.stop(); // reset mrecorder.release(); mrecorder = null; } started = false; } catch (IllegalStateException e) { e.printStackTrace(); } Log.d(TAG, "錄音結(jié)束"); } public void pause() { } public String getPhoneNumber() { return phoneNumber; } public void setPhoneNumber(String phoneNumber) { this.phoneNumber = phoneNumber; } public boolean isStarted() { return started; } public void setStarted(boolean hasStarted) { this.started = hasStarted; } public boolean isCommingNumber() { return isCommingNumber; } public void setIsCommingNumber(boolean isCommingNumber) { this.isCommingNumber = isCommingNumber; } private String getFilePath(String fileName) { File sdcardDir = null; boolean sdcardExist = Environment.getExternalStorageState().equals( android.os.Environment.MEDIA_MOUNTED); if (sdcardExist) { sdcardDir = Environment.getExternalStorageDirectory(); } String filePath = sdcardDir.toString() + "/Recorder/Recorder"; File file = new File(filePath); if (!file.exists()) { file.mkdirs(); } return filePath + "/" + fileName; } }
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android音頻錄制MediaRecorder之簡易的錄音軟件實(shí)現(xiàn)代碼
- Android簡單的利用MediaRecorder進(jìn)行錄音的實(shí)例代碼
- Android應(yīng)用開發(fā):電話監(jiān)聽和錄音代碼示例
- Android App調(diào)用MediaRecorder實(shí)現(xiàn)錄音功能的實(shí)例
- Android實(shí)現(xiàn)錄音方法(仿微信語音、麥克風(fēng)錄音、發(fā)送語音、解決5.0以上BUG)
- Android實(shí)現(xiàn)錄音功能實(shí)現(xiàn)實(shí)例(MediaRecorder)
- Android實(shí)現(xiàn)語音播放與錄音功能
- android MediaRecorder實(shí)現(xiàn)錄屏?xí)r帶錄音功能
- Android仿微信語音對講錄音功能
- android實(shí)現(xiàn)通話自動(dòng)錄音服務(wù)
相關(guān)文章
Android ListView實(shí)現(xiàn)ImageLoader圖片加載的方法
這篇文章主要介紹了Android ListView實(shí)現(xiàn)ImageLoader圖片加載的方法,結(jié)合實(shí)例形式簡單分析了開源框架Imageloader的功能、使用方法與相關(guān)注意事項(xiàng),需要的朋友可以參考下2017-07-07Android實(shí)現(xiàn)用文字生成圖片的示例代碼
本篇文章主要介紹了Android實(shí)現(xiàn)用文字生成圖片的示例代碼,這里整理了詳細(xì)的代碼,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-08-08Kotlin by lazy關(guān)鍵字深入探究實(shí)現(xiàn)原理
這篇文章主要介紹了by lazy,在kotlin中使用是很常見的,用于實(shí)現(xiàn)懶加載某個(gè)數(shù)據(jù)。而這兩個(gè)單詞不是一體的,其中by是kotlin中的關(guān)鍵字,用于實(shí)現(xiàn)委托;lazy是一個(gè)方法,他的返回值是委托的具體對象2022-11-11Android實(shí)現(xiàn)的可以調(diào)整透明度的圖片查看器實(shí)例
這篇文章主要介紹了Android實(shí)現(xiàn)的可以調(diào)整透明度的圖片查看器,需要的朋友可以參考下2014-07-07Android Studio4.0解決Gradle下載超時(shí)問題
這篇文章主要介紹了Android Studio4.0解決Gradle下載超時(shí)問題,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Android實(shí)現(xiàn)圖片左右滑動(dòng)效果
現(xiàn)在滑動(dòng)效果用的比較多,尤其是在手機(jī)端上面,本文介紹了Android實(shí)現(xiàn)圖片左右滑動(dòng)效果,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧。2016-10-10Android Studio 3.5版本JNI生成SO文件詳解
這篇文章主要介紹了Android Studio 3.5版本JNI生成SO文件詳解,想了解JNI的同學(xué),可以參考下2021-04-04