71.android 簡單的電話錄音並儲存到本地(來電和去電都支援)
阿新 • • 發佈:2018-12-12
//第一步 先加許可權 在AndroidManifest.xml裡:
//有打電話的許可權,讀寫許可權,還有錄音許可權。
<uses-permission android:name="android.permission.CALL_PHONE" /> <uses-permission android:name="android.permission.READ_PHONE_STATE"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.RECORD_AUDIO"/>
//在AndroidManifest.xml裡再宣告自定義的Service:<service android:name=".TelService"/>
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".TelService"/> </application>
//第二步 自定義TelService類繼承Service:
//來電錄音或去電錄音
//既然來電錄音,當然要開啟一個後臺服務。
//所以先寫一個TelService,然後得到TelephonyManager。
public class TelService extends Service { TelListener telListener; TelephonyManager manager; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Log.e("TAG——TelService", "啟動了。。。。。。。。。。。。。。。。。。。。。。。。。。。====------》》》》》》"); if (manager == null) { manager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); } if (telListener == null) { telListener = TelListener.getInstense(this); } telListener.setRecordState(true); manager.listen(telListener, PhoneStateListener.LISTEN_CALL_STATE); } @Override public void onDestroy() { Log.e("TAG——TelService", "銷燬了。。。。。。。。。。。。。。。。。。。。。。。。。。。====------》》》》》》"); telListener.setRecordState(false); super.onDestroy(); } }
//第三步 寫個TelListener類繼承PhoneStateListener:
//這個監聽是繼承PhoneStateListener,裡面有個方法onCallStateChanged,這個方法一直在監聽電話的狀態。
//一般來電是用到三個狀態CALL_STATE_IDLE:空閒
//CALL_STATE_RINGING:來電
//CALL_STATE_OFFHOOK:接通,
//一般來電的電話狀態的變化是:空閒-》來電-》接通-》空閒,這是其整個過程。
//而去電時是沒有CALL_STATE_RINGING: 來電這個狀態的。
public class TelListener extends PhoneStateListener { private MediaRecorder mediaRecorder; private String recordPath; static boolean recordState = false;// 是否開啟了服務 private boolean isRecording = false;// 時候正在錄音 private boolean isOffhooked = false;// 是否已經接通 // private boolean isRinging = false;// 來電標識 private Context context; private String number = ""; private String createTime; private static TelListener telListener; private TelListener(Context context) { this.context = context; } public static TelListener getInstense(Context context) { if (telListener == null) { telListener = new TelListener(context); } return telListener; } public void setRecordState(boolean state) { recordState = state; } @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); if (recordState) { if (!TextUtils.isEmpty(incomingNumber)) { number = incomingNumber; } switch (state) { case TelephonyManager.CALL_STATE_IDLE:// 空閒 Log.e("TAG1", "===============CALL_STATE_IDLE空閒=============="); // 音訊資料上傳到伺服器 if (isRecording) { stopRecord(mediaRecorder); isRecording = false; if (!TextUtils.isEmpty(recordPath) && isOffhooked) { isOffhooked = false; //這裡可以寫一些錄完音之後的一些後學操作 //也可以寫一個回撥 } } // isRinging = false; break; case TelephonyManager.CALL_STATE_RINGING:// 來電 Log.e("TAG2", "===============CALL_STATE_RINGING來電=============="); // isRinging = true; break; case TelephonyManager.CALL_STATE_OFFHOOK:// 接通 Log.e("TAG3", "===============CALL_STATE_OFFHOOK接通=============="); if (!isRecording) { startRecordAudio(number); number = ""; isRecording = true; isOffhooked = true; } break; default: break; } } } /** * 描述:開始錄音 */ private void startRecordAudio(String number) { mediaRecorder = new MediaRecorder(); // 存放的檔案路徑 File soundFile = null; try { soundFile = new File(Environment.getExternalStorageDirectory() .getCanonicalPath() + "/song"); createTime = MessageFormat.format("{0,date,yyyy-MM-dd-HH-mm-ss}", new Object[]{new Date(System.currentTimeMillis())}); //把號碼值空 if (TextUtils.isEmpty(number)) { number = ""; } File file = new File(soundFile, number + "電話錄音" + createTime + ".amr"); recordPath = file.getAbsolutePath(); // 錄音 new MediaRecordUtil(context).StartMediaRecord(file, mediaRecorder); Log.e("TAGXX", file.length() + "-------------------" + recordPath.length() + "-----------------" + soundFile.length()); } catch (IOException e) { e.printStackTrace(); } if (!soundFile.exists()) { try { soundFile.mkdirs(); } catch (Exception e) { e.printStackTrace(); } } } /** * 停止錄音 * * @param mediaRecorder */ private void stopRecord(MediaRecorder mediaRecorder) { if (mediaRecorder != null) { new MediaRecordUtil(context).StopmediaRecorder(mediaRecorder); } } }
//第四步 寫個MediaRecordUtil類繼承Activity:
//接下來這個就是錄音類,這裡是使用的MediaRecorder,這個錄音類在接通狀態下執行。
public class MediaRecordUtil extends Activity { private Context mContext; public MediaRecordUtil(Context context) { mContext = context; } public void StartMediaRecord(File soundFile, MediaRecorder mediaRecorder) { // 先檢測下是否含有SDCard if (!Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { Toast.makeText(mContext, "SD卡不存在,請插入SD卡", Toast.LENGTH_LONG) .show(); return; } try { // 建立音訊輸出的檔案路徑soundFile // 設定錄音的來源為麥克風 // 華為,酷派可以 //----------------------------------重要------------------------------------------------- //VOICE_CALL:語音呼叫,VOICE_COMMUNICATION:語音通訊,MIC:麥克風,VOICE_RECOGNITION:語音識別。 // VOICE_DOWNLINK:語音下行鏈路,VOICE_UPLINK:語音上行鏈路。 //經過我的測試發現以下問題,測試手機:紅米note4。 //小米手機設定MediaRecorder.AudioSource設定呼叫的時候, // 呼叫MIC可以正常保存錄音,VOICE_COMMUNICATION也可以,VOICE_RECOGNITION也可以, // 但是設定為VOICE_CALL就不行,VOICE_DOWNLINK也不行,VOICE_UPLINK也不行。 //如果設定成VOICE_CALL,那麼儲存後的檔案大小會為0b,就是為空。 //例如:mediaRecorder.setAudioSource(MediaRecorder.AudioSource.VOICE_COMMUNICATION); //------------------------------------------------------------------------------------------ if ("xiaomi".equalsIgnoreCase(android.os.Build.BRAND)) { mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); } else { mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC); } // 設定錄製的聲音輸出格式 mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.AMR_NB); // 設定聲音的編碼格式 mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB); // 設定錄音的輸出檔案路徑 mediaRecorder.setOutputFile(soundFile.getAbsolutePath()); // 做預期準備 mediaRecorder.prepare(); // 開始錄音 mediaRecorder.start(); } catch (Exception e) { e.printStackTrace(); } } /** * 停止錄音 **/ public void StopmediaRecorder(MediaRecorder mediaRecorder) { try { if (mediaRecorder != null) { mediaRecorder.stop(); // 釋放資源 mediaRecorder.release(); mediaRecorder = null; } } catch (IllegalStateException e) { e.printStackTrace(); } } /** * 刪除錄音檔案 **/ public void DeleteAudio(File soundFile) { if (soundFile.exists()) { // 判斷檔案是否存在 if (soundFile.isFile()) { // 判斷是否是檔案 soundFile.delete(); // delete()方法 你應該知道 是刪除的意思; } } } }
//第五步 在Activity裡去電(來電時)使用:
//Activity裡我寫了個Button按鈕,點選就打電話,並且開啟這個監聽的服務。
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private Button btn_recorder; //撥號請求碼 public static final int REQUEST_CALL_PERMISSION = 10111; //布林值用來點選按鈕開啟或者關閉錄音 boolean isOpening = false; //錄音許可權初始化 private static final int READ_PHONE_STATE = 1; private static String[] CALLS_STATE = { Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.RECORD_AUDIO, }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); //呼叫請求6.0錄音許可權的方法 verifyStoragePermissions(this); } private void initView() { btn_recorder = (Button) findViewById(R.id.btn_recorder); btn_recorder.setOnClickListener(this); } //點選事件,點選開始給10086,並且啟動了錄音監聽服務 @Override public void onClick(View v) { switch (v.getId()) { case R.id.btn_recorder: call("tel:" + "10086"); Intent intent = new Intent(MainActivity.this, TelService.class); startService(intent); // if (isOpening) { // stopService(intent); // btn_recorder.setText("開啟"); // isOpening = false; // Toast.makeText(this, "關閉錄音功能", Toast.LENGTH_SHORT).show(); // } else { // startService(intent); // btn_recorder.setText("關閉"); // isOpening = true; // Toast.makeText(this, "開啟錄音功能", Toast.LENGTH_SHORT).show(); // } break; } } //打電話申請許可權, public boolean checkReadPermission(String string_permission, int request_code) { boolean flag = false; //已有許可權 if (ContextCompat.checkSelfPermission(this, string_permission) == PackageManager.PERMISSION_GRANTED) { flag = true; } else { //申請許可權 ActivityCompat.requestPermissions(this, new String[]{string_permission}, request_code); } return flag; } //邏輯判斷,是否允許打電話許可權 @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { switch (requestCode) { //撥打電話 case REQUEST_CALL_PERMISSION: //失敗,吐司 if (permissions.length != 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) { Toast.makeText(this, "請允許撥號許可權後再試", Toast.LENGTH_SHORT).show(); } else { //成功,直接呼叫開始撥打方法 call("tel:" + "10086"); } break; } } //申請到許可權後打電話 public void call(String telPhone) { if (checkReadPermission(Manifest.permission.CALL_PHONE, REQUEST_CALL_PERMISSION)) { Intent intent = new Intent(Intent.ACTION_CALL, Uri.parse(telPhone)); startActivity(intent); } } //6.0錄音動態許可權 public static void verifyStoragePermissions(Activity activity) { int permission = ActivityCompat.checkSelfPermission(activity, Manifest.permission.READ_PHONE_STATE); if (permission != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions(activity, CALLS_STATE, READ_PHONE_STATE); } } }
//我的Activity佈局,就一個Button按鈕:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.hasee.a926luyin.MainActivity"> <Button android:id="@+id/btn_recorder" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="錄音" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </android.support.constraint.ConstraintLayout>
//最後我的這個錄音的檔案是存到我手機儲存裡了,因為我手機裡SD卡,如果有SD卡那麼你就去SD卡的song資料夾裡找這個錄音檔案,如果沒有SD卡,那麼就去你手機儲存裡找這個song資料夾。 話說現在的手機應該都不裝SD卡了吧!
//----------------------------------------------------------------完-----------------------------------------------------------------------