package eoc.studio.voicecard.audio;
import java.io.File;
import java.io.IOException;
import android.app.ProgressDialog;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.media.MediaPlayer.OnPreparedListener;
import android.media.MediaRecorder;
import android.media.MediaRecorder.OnInfoListener;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import eoc.studio.voicecard.BaseActivity;
import eoc.studio.voicecard.R;
import eoc.studio.voicecard.utils.FileUtility;
public class AudioRecorderActivity extends BaseActivity
{
public static final String EXTRA_KEY_FILEPATH = "file_path";
public static final String EXTRA_KEY_DURATION_MILLISECOND = "duration_millisecond";
private static final String TAG = "AudioRecorderActivity";
private static final int MAX_DURATION_MILLISECONDS = 1000 * 60 * 3;
private static String outputFile = null;
private static final String LAST_SAVED_FILE_NAME = "audio_record_last.3gp";
private File lastSavedFileFolder;
private TextView currentTime;
private TextView duration;
private TextView timeSeparator;
private ImageView back;
private ImageView ok;
private TextView recordingSign;
private LinearLayout initialBar;
private LinearLayout playingBar;
private LinearLayout recordingBar;
private LinearLayout doneBar;
private TextView record;
private TextView open;
private TextView pause;
private TextView resume;
private TextView stopRecording;
private TextView play;
private TextView save;
private TextView delete;
private enum UiState
{
INITIAL, PLAYING, RECORDING, DONE;
}
private UiState currentState = UiState.INITIAL;
private MediaRecorder recorder = null;
private MediaPlayer mediaPlayer = null;
private int audioDuration = 0;
private int recordingTime = 0;
private Handler uiHandler = new Handler();
private ProgressDialog progressDialog;
@Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
lastSavedFileFolder = getFilesDir();
initFromIntent();
initLayout();
}
@Override
public void onResume()
{
super.onResume();
if (currentState != UiState.INITIAL)
{
deleteFile();
resetTimeAndDuration();
}
setUiState(UiState.INITIAL);
}
@Override
public void onPause()
{
super.onPause();
stopUpdateTime();
stopRecording();
stopPlaying();
}
private void initFromIntent()
{
outputFile = getIntent().getStringExtra(EXTRA_KEY_FILEPATH);
Log.d(TAG, "initFromIntent - outputFile: " + outputFile);
}
private void initLayout()
{
setContentView(R.layout.activity_audio_recorder);
findViews();
setListeners();
}
private void findViews()
{
currentTime = (TextView) findViewById(R.id.act_audio_recorder_tv_current_time);
duration = (TextView) findViewById(R.id.act_audio_recorder_tv_duration);
timeSeparator = (TextView) findViewById(R.id.act_audio_recorder_tv_time_separator);
back = (ImageView) findViewById(R.id.act_audio_recorder_iv_back);
ok = (ImageView) findViewById(R.id.act_audio_recorder_iv_ok);
recordingSign = (TextView) findViewById(R.id.act_audio_recorder_tv_recording_sign);
initialBar = (LinearLayout) findViewById(R.id.act_audio_recorder_llyt_initial_bar);
playingBar = (LinearLayout) findViewById(R.id.act_audio_recorder_llyt_playing_bar);
recordingBar = (LinearLayout) findViewById(R.id.act_audio_recorder_llyt_recording_bar);
doneBar = (LinearLayout) findViewById(R.id.act_audio_recorder_llyt_done_bar);
record = (TextView) findViewById(R.id.act_audio_recorder_tv_record);
open = (TextView) findViewById(R.id.act_audio_recorder_tv_open_file);
pause = (TextView) findViewById(R.id.act_audio_recorder_tv_pause);
resume = (TextView) findViewById(R.id.act_audio_recorder_tv_resume);
stopRecording = (TextView) findViewById(R.id.act_audio_recorder_tv_stop_record);
play = (TextView) findViewById(R.id.act_audio_recorder_tv_play);
save = (TextView) findViewById(R.id.act_audio_recorder_tv_save_file);
delete = (TextView) findViewById(R.id.act_audio_recorder_tv_delete);
}
private void setListeners()
{
back.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
switch (currentState)
{
case INITIAL:
setResult(RESULT_CANCELED);
deleteFile();
finish();
break;
case PLAYING:
break;
case RECORDING:
break;
case DONE:
deleteFile();
resetTimeAndDuration();
setUiState(UiState.INITIAL);
break;
}
}
});
ok.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
switch (currentState)
{
case INITIAL:
break;
case PLAYING:
stopPlaying();
stopUpdateTime();
updateDuration(audioDuration);
setUiState(UiState.DONE);
break;
case RECORDING:
break;
case DONE:
Intent data = new Intent();
data.putExtra(EXTRA_KEY_FILEPATH, outputFile);
data.putExtra(EXTRA_KEY_DURATION_MILLISECOND, audioDuration);
Log.d(TAG, "OK - filePath: " + outputFile);
Log.d(TAG, "OK - duration: " + audioDuration);
setResult(RESULT_OK, data);
finish();
break;
}
}
});
record.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (currentState == UiState.INITIAL)
{
startRecording();
setUiState(UiState.RECORDING);
startUpdateTime();
}
}
});
open.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (currentState == UiState.INITIAL)
{
openFile();
}
}
});
resume.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (currentState == UiState.PLAYING)
{
resume.setVisibility(View.GONE);
resumePlaying();
startUpdateTime();
pause.setVisibility(View.VISIBLE);
}
}
});
pause.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (currentState == UiState.PLAYING)
{
pause.setVisibility(View.GONE);
pausePlaying();
stopUpdateTime();
resume.setVisibility(View.VISIBLE);
}
}
});
stopRecording.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (currentState == UiState.RECORDING)
{
stopRecording();
stopUpdateTime();
audioDuration = recordingTime * 1000;
updateDuration(audioDuration);
setUiState(UiState.DONE);
}
}
});
play.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (currentState == UiState.DONE)
{
setUiState(UiState.PLAYING);
startPlaying();
startUpdateTime();
}
}
});
save.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (currentState == UiState.DONE)
{
saveFile();
}
}
});
delete.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v)
{
if (currentState == UiState.DONE)
{
deleteFile();
deleteLastSavedFile();
resetTimeAndDuration();
setUiState(UiState.INITIAL);
}
}
});
}
private void setUiState(UiState state)
{
currentState = state;
Log.d(TAG, "UI State: " + state);
switch (state)
{
case INITIAL:
initialBar.setVisibility(View.VISIBLE);
playingBar.setVisibility(View.GONE);
recordingBar.setVisibility(View.GONE);
doneBar.setVisibility(View.GONE);
back.setVisibility(View.VISIBLE);
ok.setVisibility(View.INVISIBLE);
recordingSign.setVisibility(View.INVISIBLE);
currentTime.setVisibility(View.VISIBLE);
currentTime.setText("0:00");
currentTime.setTextColor(getResources().getColor(R.color.audio_recorder_initial_time));
timeSeparator.setVisibility(View.VISIBLE);
timeSeparator.setTextColor(getResources().getColor(
R.color.audio_recorder_duration_max_color));
duration.setVisibility(View.VISIBLE);
duration.setText("3:00");
duration.setTextColor(getResources()
.getColor(R.color.audio_recorder_duration_max_color));
break;
case PLAYING:
playingBar.setVisibility(View.VISIBLE);
initialBar.setVisibility(View.GONE);
recordingBar.setVisibility(View.GONE);
doneBar.setVisibility(View.GONE);
back.setVisibility(View.INVISIBLE);
ok.setVisibility(View.VISIBLE);
recordingSign.setVisibility(View.INVISIBLE);
currentTime.setVisibility(View.VISIBLE);
currentTime.setText("0:00");
currentTime.setTextColor(getResources().getColor(R.color.audio_recorder_recoding_time));
timeSeparator.setVisibility(View.VISIBLE);
timeSeparator.setTextColor(getResources().getColor(
R.color.audio_recorder_duration_max_color));
duration.setVisibility(View.VISIBLE);
duration.setTextColor(getResources().getColor(R.color.audio_recorder_done_time));
resume.setVisibility(View.GONE);
pause.setVisibility(View.VISIBLE);
break;
case RECORDING:
recordingBar.setVisibility(View.VISIBLE);
initialBar.setVisibility(View.GONE);
playingBar.setVisibility(View.GONE);
doneBar.setVisibility(View.GONE);
back.setVisibility(View.INVISIBLE);
ok.setVisibility(View.INVISIBLE);
recordingSign.setVisibility(View.VISIBLE);
currentTime.setVisibility(View.VISIBLE);
currentTime.setTextColor(getResources().getColor(R.color.audio_recorder_recoding_time));
timeSeparator.setVisibility(View.VISIBLE);
timeSeparator.setTextColor(getResources().getColor(
R.color.audio_recorder_duration_max_color));
duration.setVisibility(View.VISIBLE);
duration.setText("3:00");
duration.setTextColor(getResources()
.getColor(R.color.audio_recorder_duration_max_color));
break;
case DONE:
doneBar.setVisibility(View.VISIBLE);
initialBar.setVisibility(View.GONE);
playingBar.setVisibility(View.GONE);
recordingBar.setVisibility(View.GONE);
back.setVisibility(View.VISIBLE);
ok.setVisibility(View.VISIBLE);
recordingSign.setVisibility(View.INVISIBLE);
currentTime.setVisibility(View.GONE);
timeSeparator.setVisibility(View.GONE);
duration.setVisibility(View.VISIBLE);
duration.setTextColor(getResources().getColor(R.color.audio_recorder_done_time));
break;
}
}
private void openFile()
{
File lastSavedFile = new File(lastSavedFileFolder, LAST_SAVED_FILE_NAME);
if (lastSavedFile.exists())
{
progressDialog = ProgressDialog.show(this, getString(R.string.processing),
getString(R.string.please_wait), true, false);
deleteFile();
if (FileUtility.copyFile(lastSavedFile, new File(outputFile)))
{
setUiState(UiState.PLAYING);
startPlaying();
startUpdateTime();
}
else
{
Log.e(TAG, "openFile - file copy failed");
}
progressDialog.dismiss();
}
else
{
Toast.makeText(this, getResources().getString(R.string.not_found_audio_file), Toast.LENGTH_SHORT).show();
}
}
private void saveFile()
{
File fileToSave = new File(outputFile);
File lastSavedFile = new File(lastSavedFileFolder, LAST_SAVED_FILE_NAME);
if (fileToSave.exists())
{
progressDialog = ProgressDialog.show(this, getString(R.string.processing),
getString(R.string.please_wait), true, false);
deleteLastSavedFile();
if (FileUtility.copyFile(fileToSave, lastSavedFile))
{
Toast.makeText(this, getResources().getString(R.string.save), Toast.LENGTH_SHORT).show();
}
else
{
Log.e(TAG, "saveFile - file copy failed");
}
progressDialog.dismiss();
}
else
{
Log.e(TAG, "saveFile - nothing to save");
}
}
private void deleteFile()
{
File file = new File(outputFile);
if (file.exists())
{
if (file.delete())
{
Log.d(TAG, "deleteFile - file deleted");
}
else
{
Log.w(TAG, "deleteFile - file not deleted");
}
}
}
private void deleteLastSavedFile()
{
File lastSavedFile = new File(lastSavedFileFolder, LAST_SAVED_FILE_NAME);
if (lastSavedFile.exists())
{
if (lastSavedFile.delete())
{
Log.d(TAG, "deleteLastFile - lastFile deleted");
}
else
{
Log.w(TAG, "deleteLastFile - lastFile not deleted");
}
}
}
private void startPlaying()
{
try
{
mediaPlayer = new MediaPlayer();
mediaPlayer.setDataSource(outputFile);
mediaPlayer.prepare();
mediaPlayer.setOnPreparedListener(new OnPreparedListener()
{
@Override
public void onPrepared(MediaPlayer mp)
{
mp.start();
audioDuration = mp.getDuration();
updateDuration(audioDuration);
}
});
mediaPlayer.setOnCompletionListener(new OnCompletionListener()
{
@Override
public void onCompletion(MediaPlayer mp)
{
setUiState(UiState.DONE);
stopUpdateTime();
}
});
mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener()
{
@Override
public boolean onError(MediaPlayer mp, int what, int extra)
{
Log.e(TAG, "media player error! " + what + ", " + extra);
quitByError();
return false;
}
});
}
catch (IOException e)
{
Log.e(TAG, "prepare() failed");
quitByError();
}
}
private void pausePlaying()
{
mediaPlayer.pause();
}
private void resumePlaying()
{
mediaPlayer.start();
}
private void stopPlaying()
{
if (mediaPlayer != null)
{
mediaPlayer.release();
mediaPlayer = null;
}
}
private void startRecording()
{
recorder = new MediaRecorder();
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
recorder.setOutputFile(outputFile);
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_WB);
recorder.setAudioEncodingBitRate(12200);
recorder.setAudioSamplingRate(8000);
recorder.setMaxDuration(MAX_DURATION_MILLISECONDS);
recorder.setOnInfoListener(new OnInfoListener()
{
@Override
public void onInfo(MediaRecorder mr, int what, int extra)
{
switch (what)
{
case MediaRecorder.MEDIA_RECORDER_INFO_MAX_DURATION_REACHED:
stopRecording();
stopUpdateTime();
audioDuration = MAX_DURATION_MILLISECONDS;
updateDuration(audioDuration);
setUiState(UiState.DONE);
break;
}
}
});
recorder.setOnErrorListener(new MediaRecorder.OnErrorListener()
{
@Override
public void onError(MediaRecorder mr, int what, int extra)
{
Log.e(TAG, "media recorder error! " + what + ", " + extra);
quitByError();
}
});
try
{
recorder.prepare();
}
catch (IOException e)
{
Log.e(TAG, "prepare() failed");
}
recorder.start();
}
private void stopRecording()
{
if (recorder != null)
{
recorder.stop();
recorder.release();
recorder = null;
}
}
private Runnable updateTimeAction = new Runnable()
{
@Override
public void run()
{
if (currentState == UiState.RECORDING)
{
recordingTime++;
int min = recordingTime / 60;
int sec = recordingTime % 60;
currentTime.setText(min + ":" + String.format("%02d", sec));
uiHandler.postDelayed(updateTimeAction, 1000);
}
else if (currentState == UiState.PLAYING && mediaPlayer != null)
{
int ms = mediaPlayer.getCurrentPosition();
int min = ms / 1000 / 60;
int sec = ms / 1000 % 60;
currentTime.setText(min + ":" + String.format("%02d", sec));
uiHandler.postDelayed(updateTimeAction, 500);
}
}
};
private void startUpdateTime()
{
uiHandler.removeCallbacks(updateTimeAction);
if (currentState == UiState.RECORDING)
{
uiHandler.postDelayed(updateTimeAction, 1000);
}
else if (currentState == UiState.PLAYING)
{
uiHandler.post(updateTimeAction);
}
}
private void stopUpdateTime()
{
uiHandler.removeCallbacks(updateTimeAction);
}
private void updateDuration(int ms)
{
int min = ms / 1000 / 60;
int sec = ms / 1000 % 60;
String text = min + ":" + String.format("%02d", sec);
duration.setText(text);
}
private void resetTimeAndDuration()
{
Log.d(TAG, "resetTimeAndDuration");
audioDuration = 0;
recordingTime = 0;
}
private void quitByError()
{
Log.e(TAG, "quit by error");
deleteFile();
setResult(RESULT_CANCELED);
finish();
}
}