2、介绍完了来电自动录音,下面就来介绍去电自动录音的实现方法。上面说过,相比来电状态的监听,去电的要麻烦些,甚至这种方法不是通用的,这个主要是因为android api 中没有提供去电状态监听的相应类和方法(也许我刚接触,没有找到)。刚开始网上搜索了一通也没有找到对应的解决方法,大多是 来电监听的,也就是上面的方法。不过中途发现一篇博文(后来就搜不到了),记得是查询系统日志的方式,从中找到去电过程中的各个状态的关键词。无奈之中,最终妥协了此方法。
我的(联想A65上的)去电日志内容如下
过滤关键词为 mforeground- 01-06 16:29:54.225: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:54.245: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:54.631: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:54.645: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:54.742: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:54.766: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:54.873: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:54.877: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:55.108: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:55.125: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : DIALING
- 01-06 16:29:57.030: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : ACTIVE
- 01-06 16:29:57.155: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : ACTIVE
- 01-06 16:29:57.480: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : ACTIVE
- 01-06 16:29:57.598: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : ACTIVE
- 01-06 16:29:59.319: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : DISCONNECTING
- 01-06 16:29:59.373: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : DISCONNECTING
- 01-06 16:30:00.392: D/InCallScreen(251): - onDisconnect: currentlyIdle:true ; mForegroundCall.getState():DISCONNECTED
- 01-06 16:30:00.399: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): - onDisconnect: currentlyIdle:true ; mForegroundCall.getState():DISCONNECTED
- 01-06 16:30:01.042: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : IDLE
- 01-06 16:30:01.070: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : IDLE
- 01-06 16:30:01.558: D/InCallScreen(251): onPhoneStateChanged: mForegroundCall.getState() : IDLE
- 01-06 16:30:01.572: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mForegroundCall.getState() : IDLE
过滤关键词 mbackground
- 01-06 16:29:54.226: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:54.256: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:54.638: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:54.652: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:54.743: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:54.770: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:54.875: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:54.882: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:55.109: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:55.142: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:57.031: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:57.160: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:57.481: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:57.622: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:59.319: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:29:59.373: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:30:01.042: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:30:01.070: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:30:01.559: D/InCallScreen(251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
- 01-06 16:30:01.573: V/LogInfo OutGoing Call(2492): D/InCallScreen( 251): onPhoneStateChanged: mBackgroundCall.getState() : IDLE
从上面的日志可以看到,每一行的末尾的大写英文词就是去电的状态,状态说明如下:
DIALING 拨号,对方还未响铃ACTIVE 对方接通,通话建立DISCONNECTING 通话断开时DISCONNECTED 通话已断开,可以认为是挂机了 由于我拨打的是10010,没有响铃过程(电脑自动接通的够快),还少了一个状态,状态是ALERTING 这个就是对方正在响铃的状态 有了这几个去电状态就好办了,现在我们要做的就是读取系统日志,然后找到这些状态,提取的关键词就是上面提到的 mforeground(前台通话状态) 和 mbackground (后台通话状态)(可能不一样的设备生成的不一样,根据自己具体设备设置,这里只提取前台的),如果读取的这一行日志中 包含 mforground ,再看看是否包含上面的状态的 单词。既然说的如此,那么看看读取系统日志的代码吧- package com.sdvdxl.phonerecorder;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.InputStreamReader;
- import com.sdvdxl.outgoingcall.OutgoingCallState;
- import android.content.Context;
- import android.content.Intent;
- import android.util.Log;
- /**
- *
- * @author sdvdxl
- * 找到 日志中的
- * onPhoneStateChanged: mForegroundCall.getState() 这个是前台呼叫状态
- * mBackgroundCall.getState() 后台电话
- * 若 是 DIALING 则是正在拨号,等待建立连接,但对方还没有响铃,
- * ALERTING 呼叫成功,即对方正在响铃,
- * 若是 ACTIVE 则已经接通
- * 若是 DISCONNECTED 则本号码呼叫已经挂断
- * 若是 IDLE 则是处于 空闲状态
- *
- */
- public class ReadLog extends Thread {
- private Context ctx;
- private int logCount;
- private static final String TAG = "LogInfo OutGoing Call";
- /**
- * 前后台电话
- * @author sdvdxl
- *
- */
- private static class CallViewState {
- public static final String FORE_GROUND_CALL_STATE = "mForeground";
- }
- /**
- * 呼叫状态
- * @author sdvdxl
- *
- */
- 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 ReadLog(Context ctx) {
- this.ctx = ctx;
- }
- /**
- * 读取Log流
- * 取得呼出状态的log
- * 从而得到转换状态
- */
- @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();//销毁进程,释放资源
- logCount = 0;
- Log.v(TAG, "-----------清理日志---------------");
- }
- /*---------------------------------前台呼叫-----------------------*/
- //空闲
- if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE)
- && line.contains(ReadLog.CallState.IDLE)) {
- Log.d(TAG, ReadLog.CallState.IDLE);
- }
- //正在拨号,等待建立连接,即已拨号,但对方还没有响铃,
- if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE)
- && line.contains(ReadLog.CallState.DIALING)) {
- Log.d(TAG, ReadLog.CallState.DIALING);
- }
- //呼叫对方 正在响铃
- if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE)
- && line.contains(ReadLog.CallState.ALERTING)) {
- Log.d(TAG, ReadLog.CallState.ALERTING);
- }
- //已接通,通话建立
- if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE)
- && line.contains(ReadLog.CallState.ACTIVE)) {
- Log.d(TAG, ReadLog.CallState.ACTIVE);
- }
- //断开连接,即挂机
- if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE)
- && line.contains(ReadLog.CallState.DISCONNECTED)) {
- Log.d(TAG, ReadLog.CallState.DISCONNECTED);
- }
- } //END while
- } catch (IOException e) {
- e.printStackTrace();
- } //END try-catch
- } //END run
- } //END class ReadLog
以上代码中,之所以用线程,是为了防止读取日志过程中阻滞主方法的其他方法的执行,影响到程序捕捉对应的电话状态。
未完另附