1. 程式人生 > >71.android 簡單的電話錄音並儲存到本地(來電和去電都支援)

71.android 簡單的電話錄音並儲存到本地(來電和去電都支援)

 //第一步 先加許可權 在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卡了吧!

//----------------------------------------------------------------完-----------------------------------------------------------------------