Android 來去電自動錄音 (三)

 好了,捕捉到了去電過程中各個狀態的轉變,那麼,如何通知給程序呢,我採用的方法是捕獲後立馬給系統發送廣播,然後程序進行廣播接受,接受後在處理錄音事件。要發送廣播,就要發送一個唯一的廣播,爲此,建立如下類,

 

  1. package com.sdvdxl.outgoingcall; 
  2.  
  3. import com.sdvdxl.phonerecorder.ReadLog; 
  4.  
  5. import android.content.Context; 
  6. import android.util.Log; 
  7.  
  8. public class OutgoingCallState { 
  9.     Context ctx; 
  10.     public OutgoingCallState(Context ctx) { 
  11.         this.ctx = ctx; 
  12.     } 
  13.      
  14.     /** 
  15.      * 前臺呼叫狀態 
  16.      * @author sdvdxl 
  17.      * 
  18.      */ 
  19.     public static final class ForeGroundCallState { 
  20.         public static final String DIALING =  
  21.                 "com.sdvdxl.phonerecorder.FORE_GROUND_DIALING"
  22.         public static final String ALERTING =  
  23.                 "com.sdvdxl.phonerecorder.FORE_GROUND_ALERTING"
  24.         public static final String ACTIVE =  
  25.                 "com.sdvdxl.phonerecorder.FORE_GROUND_ACTIVE"
  26.         public static final String IDLE =  
  27.                 "com.sdvdxl.phonerecorder.FORE_GROUND_IDLE"
  28.         public static final String DISCONNECTED =  
  29.                 "com.sdvdxl.phonerecorder.FORE_GROUND_DISCONNECTED"
  30.     } 
  31.      
  32.     /** 
  33.      * 開始監聽呼出狀態的轉變, 
  34.      * 並在對應狀態發送廣播 
  35.      */ 
  36.     public void startListen() { 
  37.         new ReadLog(ctx).start(); 
  38.         Log.d("Recorder""開始監聽呼出狀態的轉變,並在對應狀態發送廣播"); 
  39.     } 
  40.      

程序需要讀取系統日誌權限

  1. <uses-permission android:name="android.permission.READ_LOGS"/> 

然後,在讀取日誌的類中檢測到去電各個狀態的地方發送一個廣播,那麼,讀取日誌的完整代碼如下 
 

  1. package com.sdvdxl.phonerecorder; 
  2.  
  3. import java.io.BufferedReader; 
  4. import java.io.IOException; 
  5. import java.io.InputStream; 
  6. import java.io.InputStreamReader; 
  7.  
  8. import com.sdvdxl.outgoingcall.OutgoingCallState; 
  9.  
  10. import android.content.Context; 
  11. import android.content.Intent; 
  12. import android.util.Log; 
  13.  
  14. /** 
  15.  *  
  16.  * @author mrloong 
  17.  *  找到 日誌中的 
  18.  *  onPhoneStateChanged: mForegroundCall.getState() 這個是前臺呼叫狀態 
  19.  *  mBackgroundCall.getState() 後臺電話 
  20.  *  若 是 DIALING 則是正在撥號,等待建立連接,但對方還沒有響鈴, 
  21.  *  ALERTING 呼叫成功,即對方正在響鈴, 
  22.  *  若是 ACTIVE 則已經接通 
  23.  *  若是 DISCONNECTED 則本號碼呼叫已經掛斷 
  24.  *  若是 IDLE 則是處於 空閒狀態 
  25.  *   
  26.  */ 
  27. public class ReadLog extends Thread { 
  28.     private Context ctx; 
  29.     private int logCount; 
  30.      
  31.     private static final String TAG = "LogInfo OutGoing Call"
  32.      
  33.     /** 
  34.      *  前後臺電話 
  35.      * @author sdvdxl 
  36.      *   
  37.      */ 
  38.     private static class CallViewState { 
  39.         public static final String FORE_GROUND_CALL_STATE = "mForeground"
  40.     } 
  41.      
  42.     /** 
  43.      * 呼叫狀態 
  44.      * @author sdvdxl 
  45.      * 
  46.      */ 
  47.     private static class CallState { 
  48.         public static final String DIALING = "DIALING"
  49.         public static final String ALERTING = "ALERTING"
  50.         public static final String ACTIVE = "ACTIVE"
  51.         public static final String IDLE = "IDLE"
  52.         public static final String DISCONNECTED = "DISCONNECTED"
  53.     } 
  54.      
  55.     public ReadLog(Context ctx) { 
  56.         this.ctx = ctx; 
  57.     } 
  58.      
  59.     /** 
  60.      * 讀取Log流 
  61.      * 取得呼出狀態的log 
  62.      * 從而得到轉換狀態 
  63.      */ 
  64.     @Override 
  65.     public void run() { 
  66.         Log.d(TAG, "開始讀取日誌記錄"); 
  67.          
  68.         String[] catchParams = {"logcat""InCallScreen *:s"}; 
  69.         String[] clearParams = {"logcat""-c"}; 
  70.          
  71.         try { 
  72.             Process process=Runtime.getRuntime().exec(catchParams); 
  73.             InputStream is = process.getInputStream(); 
  74.             BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 
  75.              
  76.             String line = null
  77.             while ((line=reader.readLine())!=null) { 
  78.                 logCount++; 
  79.                 //輸出所有 
  80.             Log.v(TAG, line); 
  81.                  
  82.                 //日誌超過512條就清理 
  83.                 if (logCount>512) { 
  84.                     //清理日誌 
  85.                     Runtime.getRuntime().exec(clearParams) 
  86.                         .destroy();//銷燬進程,釋放資源 
  87.                     logCount = 0
  88.                     Log.v(TAG, "-----------清理日誌---------------"); 
  89.                 }    
  90.                  
  91.                 /*---------------------------------前臺呼叫-----------------------*/ 
  92.                 //空閒 
  93.                 if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE) 
  94.                         && line.contains(ReadLog.CallState.IDLE)) { 
  95.                     Log.d(TAG, ReadLog.CallState.IDLE); 
  96.                 } 
  97.                  
  98.                 //正在撥號,等待建立連接,即已撥號,但對方還沒有響鈴, 
  99.                 if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE) 
  100.                         && line.contains(ReadLog.CallState.DIALING)) { 
  101.                     //發送廣播 
  102.                     Intent dialingIntent = new Intent(); 
  103.                     dialingIntent.setAction(OutgoingCallState.ForeGroundCallState.DIALING); 
  104.                     ctx.sendBroadcast(dialingIntent); 
  105.                      
  106.                     Log.d(TAG, ReadLog.CallState.DIALING); 
  107.                 } 
  108.                  
  109.                 //呼叫對方 正在響鈴 
  110.                 if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE) 
  111.                         && line.contains(ReadLog.CallState.ALERTING)) { 
  112.                     //發送廣播 
  113.                     Intent dialingIntent = new Intent(); 
  114.                     dialingIntent.setAction(OutgoingCallState.ForeGroundCallState.ALERTING); 
  115.                     ctx.sendBroadcast(dialingIntent); 
  116.                      
  117.                     Log.d(TAG, ReadLog.CallState.ALERTING); 
  118.                 } 
  119.                  
  120.                 //已接通,通話建立 
  121.                 if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE) 
  122.                         && line.contains(ReadLog.CallState.ACTIVE)) { 
  123.                     //發送廣播 
  124.                     Intent dialingIntent = new Intent(); 
  125.                     dialingIntent.setAction(OutgoingCallState.ForeGroundCallState.ACTIVE); 
  126.                     ctx.sendBroadcast(dialingIntent); 
  127.                      
  128.                     Log.d(TAG, ReadLog.CallState.ACTIVE); 
  129.                 } 
  130.                  
  131.                 //斷開連接,即掛機 
  132.                 if (line.contains(ReadLog.CallViewState.FORE_GROUND_CALL_STATE) 
  133.                         && line.contains(ReadLog.CallState.DISCONNECTED)) { 
  134.                     //發送廣播 
  135.                     Intent dialingIntent = new Intent(); 
  136.                     dialingIntent.setAction(OutgoingCallState.ForeGroundCallState.DISCONNECTED); 
  137.                     ctx.sendBroadcast(dialingIntent); 
  138.                      
  139.                     Log.d(TAG, ReadLog.CallState.DISCONNECTED); 
  140.                 } 
  141.                  
  142.             } //END while 
  143.              
  144.         } catch (IOException e) { 
  145.             e.printStackTrace(); 
  146.         } //END try-catch 
  147.     } //END run 
  148. //END class ReadLog 

發送了廣播,那麼就要有接受者,定義接收者如下
(關於錄音機的代碼可以先忽略)

  1. package com.sdvdxl.phonerecorder; 
  2.  
  3. import android.content.BroadcastReceiver; 
  4. import android.content.Context; 
  5. import android.content.Intent; 
  6. import android.util.Log; 
  7.  
  8. import com.sdvdxl.outgoingcall.OutgoingCallState; 
  9.  
  10. public class OutgoingCallReciver extends BroadcastReceiver { 
  11.     static final String TAG = "Recorder"
  12.     private MyRecorder recorder; 
  13.      
  14.     public OutgoingCallReciver() { 
  15.         recorder = new MyRecorder(); 
  16.     } 
  17.      
  18.     public  OutgoingCallReciver (MyRecorder recorder) { 
  19.         this.recorder = recorder; 
  20.     } 
  21.      
  22.     @Override 
  23.     public void onReceive(Context ctx, Intent intent) { 
  24.         String phoneState = intent.getAction(); 
  25.          
  26.         if (phoneState.equals(Intent.ACTION_NEW_OUTGOING_CALL)) { 
  27.             String phoneNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);//撥出號碼 
  28.             recorder.setPhoneNumber(phoneNum); 
  29.             recorder.setIsCommingNumber(false); 
  30.             Log.d(TAG, "設置爲去電狀態"); 
  31.             Log.d(TAG, "去電狀態 呼叫:" + phoneNum); 
  32.         } 
  33.          
  34.         if (phoneState.equals(OutgoingCallState.ForeGroundCallState.DIALING)) { 
  35.             Log.d(TAG, "正在撥號..."); 
  36.         } 
  37.          
  38.         if (phoneState.equals(OutgoingCallState.ForeGroundCallState.ALERTING)) { 
  39.             Log.d(TAG, "正在呼叫..."); 
  40.         } 
  41.          
  42.         if (phoneState.equals(OutgoingCallState.ForeGroundCallState.ACTIVE)) { 
  43.             if (!recorder.isCommingNumber() && !recorder.isStarted()) { 
  44.                 Log.d(TAG, "去電已接通 啓動錄音機"); 
  45.                 recorder.start(); 
  46.                  
  47.             } 
  48.         } 
  49.          
  50.         if (phoneState.equals(OutgoingCallState.ForeGroundCallState.DISCONNECTED)) { 
  51.             if (!recorder.isCommingNumber() && recorder.isStarted()) { 
  52.                 Log.d(TAG, "已掛斷 關閉錄音機"); 
  53.                 recorder.stop(); 
  54.             } 
  55.         } 
  56.     } 
  57.  

其中有這麼一段代碼

  1. String phoneState = intent.getAction();  
  2.           
  3.         if (phoneState.equals(Intent.ACTION_NEW_OUTGOING_CALL)) {  
  4.             String phoneNum = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);//撥出號碼  
  5.             recorder.setPhoneNumber(phoneNum);  
  6.             recorder.setIsCommingNumber(false);  
  7.             Log.d(TAG, "設置爲去電狀態");  
  8.             Log.d(TAG, "去電狀態 呼叫:" + phoneNum);  
  9.         }  

這裏是接收系統發出的廣播,用於接收去電廣播。這樣,就獲得了去電狀態。

3、有了以上主要代碼,可以說,來去電監聽功能算是完成了,下面創建一個service來運行監聽
 

  1. package com.sdvdxl.service; 
  2.  
  3. import android.app.Service; 
  4. import android.content.Context; 
  5. import android.content.Intent; 
  6. import android.content.IntentFilter; 
  7. import android.os.IBinder; 
  8. import android.telephony.PhoneStateListener; 
  9. import android.telephony.TelephonyManager; 
  10. import android.util.Log; 
  11. import android.widget.Toast; 
  12.  
  13. import com.sdvdxl.outgoingcall.OutgoingCallState; 
  14. import com.sdvdxl.phonerecorder.MyRecorder; 
  15. import com.sdvdxl.phonerecorder.OutgoingCallReciver; 
  16. import com.sdvdxl.phonerecorder.TelListener; 
  17.  
  18. public class PhoneCallStateService extends Service { 
  19.     private OutgoingCallState outgoingCallState; 
  20.     private OutgoingCallReciver outgoingCallReciver; 
  21.     private MyRecorder recorder; 
  22.      
  23.     @Override 
  24.     public void onCreate() { 
  25.         super.onCreate(); 
  26.          
  27.         //------以下應放在onStartCommand中,但2.3.5以下版本不會因service重新啓動而重新調用-------- 
  28.         //監聽電話狀態,如果是打入且接聽 或者 打出 則開始自動錄音 
  29.         //通話結束,保存文件到外部存儲器上 
  30.         Log.d("Recorder""正在監聽中..."); 
  31.         recorder = new MyRecorder(); 
  32.         outgoingCallState = new OutgoingCallState(this); 
  33.         outgoingCallReciver = new OutgoingCallReciver(recorder); 
  34.         outgoingCallState.startListen(); 
  35.         Toast.makeText(this"服務已啓動", Toast.LENGTH_LONG).show(); 
  36.          
  37.         //去電 
  38.         IntentFilter outgoingCallFilter = new IntentFilter(); 
  39.         outgoingCallFilter.addAction(OutgoingCallState.ForeGroundCallState.IDLE); 
  40.         outgoingCallFilter.addAction(OutgoingCallState.ForeGroundCallState.DIALING); 
  41.         outgoingCallFilter.addAction(OutgoingCallState.ForeGroundCallState.ALERTING); 
  42.         outgoingCallFilter.addAction(OutgoingCallState.ForeGroundCallState.ACTIVE); 
  43.         outgoingCallFilter.addAction(OutgoingCallState.ForeGroundCallState.DISCONNECTED); 
  44.          
  45.         outgoingCallFilter.addAction("android.intent.action.PHONE_STATE"); 
  46.         outgoingCallFilter.addAction("android.intent.action.NEW_OUTGOING_CALL"); 
  47.          
  48.         //註冊接收者 
  49.         registerReceiver(outgoingCallReciver, outgoingCallFilter); 
  50.          
  51.         //來電 
  52.         TelephonyManager telmgr = (TelephonyManager)getSystemService( 
  53.                 Context.TELEPHONY_SERVICE); 
  54.         telmgr.listen(new TelListener(recorder), PhoneStateListener.LISTEN_CALL_STATE); 
  55.          
  56.          
  57.     } 
  58.      
  59.     @Override 
  60.     public IBinder onBind(Intent intent) { 
  61.         // TODO Auto-generated method stub 
  62.         return null
  63.     } 
  64.  
  65.     @Override 
  66.     public void onDestroy() { 
  67.         super.onDestroy(); 
  68.         unregisterReceiver(outgoingCallReciver); 
  69.         Toast.makeText( 
  70.                 this"已關閉電話監聽服務", Toast.LENGTH_LONG) 
  71.                 .show(); 
  72.         Log.d("Recorder""已關閉電話監聽服務"); 
  73.     } 
  74.  
  75.     @Override 
  76.     public int onStartCommand(Intent intent, int flags, int startId) { 
  77.          
  78.         return START_STICKY; 
  79.     } 
  80.  

註冊以下service
 

  1. <service android:name="com.sdvdxl.service.PhoneCallStateService" /> 

到此爲止,來去電狀態的監聽功能算是完成了,剩下一個錄音機,附上錄音機代碼如下
 

  1. package com.sdvdxl.phonerecorder; 
  2.  
  3. import java.io.File; 
  4. import java.io.IOException; 
  5. import java.text.SimpleDateFormat; 
  6. import java.util.Date; 
  7.  
  8. import android.media.MediaRecorder; 
  9. import android.os.Environment; 
  10. import android.util.Log; 
  11.  
  12. public class MyRecorder { 
  13.     private String phoneNumber; 
  14.     private MediaRecorder mrecorder; 
  15.     private boolean started = false//錄音機是否已經啓動 
  16.     private boolean isCommingNumber = false;//是否是來電 
  17.     private String TAG = "Recorder"
  18.      
  19.      
  20.     public MyRecorder(String phoneNumber) { 
  21.         this.setPhoneNumber(phoneNumber); 
  22.     } 
  23.      
  24.     public MyRecorder() { 
  25.     } 
  26.  
  27.     public void start() { 
  28.         started = true
  29.         mrecorder = new MediaRecorder(); 
  30.          
  31.         File recordPath = new File( 
  32.                 Environment.getExternalStorageDirectory() 
  33.                 , "/My record");  
  34.         if (!recordPath.exists()) { 
  35.             recordPath.mkdirs(); 
  36.             Log.d("recorder""創建目錄"); 
  37.         } 
  38.          
  39.         String callDir = "呼出"
  40.         if (isCommingNumber) { 
  41.             callDir = "呼入"
  42.         } 
  43.         String fileName = callDir + "-" + phoneNumber + "-"  
  44.                 + new SimpleDateFormat("yy-MM-dd_HH-mm-ss"
  45.                     .format(new Date(System.currentTimeMillis())) + ".mp3";//實際是3gp 
  46.         File recordName = new File(recordPath, fileName); 
  47.          
  48.         try { 
  49.             recordName.createNewFile(); 
  50.             Log.d("recorder""創建文件" + recordName.getName()); 
  51.         } catch (IOException e) { 
  52.             e.printStackTrace(); 
  53.         } 
  54.          
  55.         mrecorder.setAudioSource(MediaRecorder.AudioSource.DEFAULT); 
  56.         mrecorder.setOutputFormat(MediaRecorder.OutputFormat.DEFAULT); 
  57.         mrecorder.setAudioEncoder(MediaRecorder.AudioEncoder.DEFAULT); 
  58.          
  59.         mrecorder.setOutputFile(recordName.getAbsolutePath()); 
  60.          
  61.         try { 
  62.             mrecorder.prepare(); 
  63.         } catch (IllegalStateException e) { 
  64.             e.printStackTrace(); 
  65.         } catch (IOException e) { 
  66.             e.printStackTrace(); 
  67.         } 
  68.         mrecorder.start(); 
  69.         started = true
  70.         Log.d(TAG , "錄音開始"); 
  71.     } 
  72.      
  73.     public void stop() { 
  74.         try { 
  75.             if (mrecorder!=null) { 
  76.                 mrecorder.stop(); 
  77.                 mrecorder.release(); 
  78.                 mrecorder = null
  79.             } 
  80.             started = false
  81.         } catch (IllegalStateException e) { 
  82.             e.printStackTrace(); 
  83.         } 
  84.          
  85.          
  86.         Log.d(TAG , "錄音結束"); 
  87.     } 
  88.      
  89.     public void pause() { 
  90.          
  91.     } 
  92.  
  93.     public String getPhoneNumber() { 
  94.         return phoneNumber; 
  95.     } 
  96.  
  97.     public void setPhoneNumber(String phoneNumber) { 
  98.         this.phoneNumber = phoneNumber; 
  99.     } 
  100.  
  101.     public boolean isStarted() { 
  102.         return started; 
  103.     } 
  104.  
  105.     public void setStarted(boolean hasStarted) { 
  106.         this.started = hasStarted; 
  107.     } 
  108.  
  109.     public boolean isCommingNumber() { 
  110.         return isCommingNumber; 
  111.     } 
  112.  
  113.     public void setIsCommingNumber(boolean isCommingNumber) { 
  114.         this.isCommingNumber = isCommingNumber; 
  115.     } 
  116.  

寫到這兒,算是完成了來去電自動錄音的所有功能,如有不懂,或者更好的建議歡迎評論。

另附 工程源代碼 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章