package net.coding.program.common.widget.input; import android.content.Context; import android.graphics.Color; import android.graphics.drawable.AnimationDrawable; import android.media.AudioFormat; import android.media.MediaRecorder; import android.os.Bundle; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.support.v7.app.AppCompatActivity; import android.util.AttributeSet; import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageButton; import android.widget.TextView; import android.widget.Toast; import net.coding.program.MyApp; import net.coding.program.R; import net.coding.program.common.Global; import net.coding.program.common.util.FileUtil; import net.coding.program.common.widget.SoundWaveView; import net.coding.program.maopao.item.ContentAreaImages; import net.coding.program.message.AmrAudioRecorder; import org.androidannotations.annotations.AfterViews; import org.androidannotations.annotations.EViewGroup; import org.androidannotations.annotations.LongClick; import org.androidannotations.annotations.Touch; import org.androidannotations.annotations.ViewById; import java.io.File; import java.util.UUID; /** * Created by chenchao on 16/1/21. * 按下发语音模块 */ @EViewGroup(R.layout.input_view_voice_view) public class VoiceView extends FrameLayout { private AppCompatActivity activity; private AnimationDrawable voiceRecrodAnimtion; private AmrAudioRecorder mAmrAudioRecorder; private boolean isRecoding; private String out = null; private float touchY; @ViewById ViewGroup soundWaveLayout; @ViewById ImageButton voiceRecordButton; @ViewById SoundWaveView soundWaveLeft, soundWaveRight; @ViewById TextView recordTime, tips_hold_to_talk; public VoiceView(Context context, AttributeSet attrs) { super(context, attrs); activity = (AppCompatActivity) getContext(); } @AfterViews void initVoiceView() { voiceRecrodAnimtion = (AnimationDrawable) voiceRecordButton.getBackground(); } private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { Bundle data = msg.getData(); long dur = (long) data.get("duration"); double volume = (double) data.get("volume"); float db = (float) volume * 1.618f; soundWaveLeft.setVolume(db); soundWaveRight.setVolume(db); if (dur >= 55000) { recordTime.setTextColor(0xFFFF3C30); } else { recordTime.setTextColor(0xFF50AEEA); } int t = (int) dur / 1000; int min = 0; int sec = 0; if (dur < 60) { sec = t; } else { min = t / 60; sec = t % 60; } String m = min < 10 ? "0" + min : "" + min; String s = sec < 10 ? "0" + sec : "" + sec; recordTime.setText(m + ":" + s); //录音时长在60.05s到60.5s的范围内时停止录音 if (dur > 60100 && dur < 60500) { sendVoice(); } } }; private void sendVoice() { tips_hold_to_talk.setText(R.string.hold_to_talk); soundWaveLayout.setVisibility(View.GONE); long recordDuration = stopRecord(); if (recordDuration > 0l && out != null) { Log.w("test", "recordDuration=" + recordDuration); if (recordDuration >= 1000l && new File(out).length() > 100) { //录音发送 VoiceRecordCompleteCallback callback = (VoiceRecordCompleteCallback) activity; callback.recordFinished(recordDuration >= 60000 ? 60000 : recordDuration, out); } else { cancelRecord(); showToast(R.string.voice_can_not_send_because_duration_too_short); } } out = null; } private void pause() { try { if (mAmrAudioRecorder != null) { isRecoding = false; mAmrAudioRecorder.pause(); } } catch (Exception e) { if (out != null) { File f = new File(out); if (f.exists()) { f.delete(); } out = null; } } } private boolean isTouchInside(int x, int y) { int w = voiceRecordButton.getMeasuredWidth(); int h = voiceRecordButton.getMeasuredHeight(); if (x >= 0 && x <= w && y >= 0 && y <= h) { int centX = w / 2; int centY = h / 2; return Math.sqrt((x - centX) * (x - centX) + (y - centY) * (y - centY)) <= w / 2; } return false; } private void reset() { try { mAmrAudioRecorder.continueRecord(); isRecoding = true; } catch (Exception e) { e.printStackTrace(); mAmrAudioRecorder.stop(); } } @LongClick boolean voiceRecordButton() { if (activity instanceof ContentAreaImages.VoicePlayCallBack) { ContentAreaImages.VoicePlayCallBack voicePlayCallBack = (ContentAreaImages.VoicePlayCallBack) activity; voicePlayCallBack.onStopPlay(); } //开始录音... startRecord(); return true; } @Touch boolean voiceRecordButton(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL) { //long nowTime = System.currentTimeMillis(); float nowY = event.getRawY(); if (nowY - touchY <= -100) { //上滑取消录音发送 cancelRecord(); showToast(R.string.record_has_canceled); } else { sendVoice(); } return false; } else if (event.getAction() == MotionEvent.ACTION_DOWN) { touchY = event.getRawY(); return false; } else if (event.getAction() == MotionEvent.ACTION_MOVE) { if (out != null) { if (!isTouchInside((int) event.getX(), (int) event.getY())) { if (isRecoding) { tips_hold_to_talk.setVisibility(View.VISIBLE); tips_hold_to_talk.setText(R.string.loosen_to_cancel); soundWaveLayout.setVisibility(View.GONE); pause(); } } else { if (!isRecoding) { touchY = event.getRawY(); tips_hold_to_talk.setVisibility(View.GONE); tips_hold_to_talk.setText(R.string.hold_to_talk); soundWaveLayout.setVisibility(View.VISIBLE); reset(); } } } } return false; } private void cancelRecord() { stopRecord(); isRecoding = false; if (out != null) { File f = new File(out); f.delete(); out = null; } } private long stopRecord() { isRecoding = false; //voiceRecrodAnimtion.stop(); voiceRecrodAnimtion.selectDrawable(0); tips_hold_to_talk.setVisibility(View.VISIBLE); soundWaveLayout.setVisibility(View.GONE); recordTime.setTextColor(0xFF50AEEA); if (mAmrAudioRecorder == null) { return 0L; } mAmrAudioRecorder.stop(); long dur = mAmrAudioRecorder.getDuration(); mAmrAudioRecorder = null; return dur; } private void startRecord() { if (Global.sVoiceDir == null) { try { Global.sVoiceDir = FileUtil.getDestinationInExternalFilesDir(activity, Environment.DIRECTORY_MUSIC, FileUtil.DOWNLOAD_FOLDER).getAbsolutePath(); } catch (Exception e) { Global.errorLog(e); } finally { if (Global.sVoiceDir == null) { showToast(R.string.record_failed_no_enough_storage_space); stopRecord(); return; } } } voiceRecrodAnimtion.selectDrawable(1); tips_hold_to_talk.setVisibility(View.GONE); soundWaveLayout.setVisibility(View.VISIBLE); recordTime.setText("00:00"); soundWaveLeft.reSet(); soundWaveRight.reSet(); out = Global.sVoiceDir + File.separator + "coding_voice_" + UUID.randomUUID().toString() + ".amr"; mAmrAudioRecorder = new AmrAudioRecorder(MediaRecorder.AudioSource.MIC, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT, out); mAmrAudioRecorder.setVoiceRecordingCallBack(mVoiceRecordingCallBack); mAmrAudioRecorder.prepare(); mAmrAudioRecorder.start(); if (AmrAudioRecorder.State.ERROR == mAmrAudioRecorder.getState()) { showToast(R.string.record_failed); } else { isRecoding = true; } } private AmrAudioRecorder.VoiceRecordingCallBack mVoiceRecordingCallBack = new AmrAudioRecorder.VoiceRecordingCallBack() { @Override public void onRecord(long duration, double volume) { Message m = Message.obtain(); Bundle data = new Bundle(); data.putDouble("volume", volume); data.putLong("duration", duration); m.setData(data); mHandler.sendMessage(m); } }; private void showToast(int rid) { TextView tv = new TextView(activity); tv.setText(rid); tv.setTextSize(16); tv.setTextColor(Color.WHITE); tv.setBackgroundResource(R.drawable.tips_background); tv.setWidth((int) (MyApp.sWidthPix * 0.7)); tv.setHeight(Global.dpToPx(48)); tv.setGravity(Gravity.CENTER); Toast toast = new Toast(activity); toast.setDuration(Toast.LENGTH_SHORT); toast.setGravity(Gravity.TOP | Gravity.CENTER_HORIZONTAL, 0, activity.getSupportActionBar().getHeight() + 30); toast.setView(tv); toast.show(); } }