cheogram/src/main/java/eu/siacs/conversations/ui/RecordingActivity.java
2018-04-23 12:07:19 +02:00

189 lines
5.6 KiB
Java

package eu.siacs.conversations.ui;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.media.MediaRecorder;
import android.net.Uri;
import android.os.Bundle;
import android.os.FileObserver;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.R;
import eu.siacs.conversations.databinding.ActivityRecordingBinding;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.utils.ThemeHelper;
public class RecordingActivity extends Activity implements View.OnClickListener {
public static String STORAGE_DIRECTORY_TYPE_NAME = "Recordings";
private ActivityRecordingBinding binding;
private MediaRecorder mRecorder;
private long mStartTime = 0;
private Handler mHandler = new Handler();
private Runnable mTickExecutor = new Runnable() {
@Override
public void run() {
tick();
mHandler.postDelayed(mTickExecutor, 100);
}
};
private File mOutputFile;
private boolean mShouldFinishAfterWrite = false;
private FileObserver mFileObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(ThemeHelper.findDialog(this));
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this,R.layout.activity_recording);
this.binding.cancelButton.setOnClickListener(this);
this.binding.shareButton.setOnClickListener(this);
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
@Override
protected void onStart() {
super.onStart();
if (!startRecording()) {
this.binding.shareButton.setEnabled(false);
Toast.makeText(this, R.string.unable_to_start_recording, Toast.LENGTH_SHORT).show();
}
}
@Override
protected void onStop() {
super.onStop();
if (mRecorder != null) {
mHandler.removeCallbacks(mTickExecutor);
stopRecording(false);
}
if (mFileObserver != null) {
mFileObserver.stopWatching();
}
}
private boolean startRecording() {
mRecorder = new MediaRecorder();
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
mRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
mRecorder.setAudioEncodingBitRate(48000);
mRecorder.setAudioSamplingRate(16000);
setupOutputFile();
mRecorder.setOutputFile(mOutputFile.getAbsolutePath());
try {
mRecorder.prepare();
mRecorder.start();
mStartTime = SystemClock.elapsedRealtime();
mHandler.postDelayed(mTickExecutor, 100);
Log.d("Voice Recorder", "started recording to " + mOutputFile.getAbsolutePath());
return true;
} catch (Exception e) {
Log.e("Voice Recorder", "prepare() failed " + e.getMessage());
return false;
}
}
protected void stopRecording(boolean saveFile) {
mShouldFinishAfterWrite = saveFile;
mRecorder.stop();
mRecorder.release();
mRecorder = null;
mStartTime = 0;
if (!saveFile && mOutputFile != null) {
if (mOutputFile.delete()) {
Log.d(Config.LOGTAG,"deleted canceled recording");
}
}
}
private static File generateOutputFilename(Context context) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmssSSS", Locale.US);
String filename = "RECORDING_" + dateFormat.format(new Date()) + ".m4a";
return new File(FileBackend.getConversationsDirectory(context, STORAGE_DIRECTORY_TYPE_NAME) + "/" + filename);
}
private void setupOutputFile() {
mOutputFile = generateOutputFilename(this);
File parentDirectory = mOutputFile.getParentFile();
if (parentDirectory.mkdirs()) {
Log.d(Config.LOGTAG, "created " + parentDirectory.getAbsolutePath());
}
File noMedia = new File(parentDirectory, ".nomedia");
if (!noMedia.exists()) {
try {
if (noMedia.createNewFile()) {
Log.d(Config.LOGTAG, "created nomedia file in " + parentDirectory.getAbsolutePath());
}
} catch (IOException e) {
Log.d(Config.LOGTAG, "unable to create nomedia file in " + parentDirectory.getAbsolutePath(), e);
}
}
setupFileObserver(parentDirectory);
}
private void setupFileObserver(File directory) {
mFileObserver = new FileObserver(directory.getAbsolutePath()) {
@Override
public void onEvent(int event, String s) {
if (s != null && s.equals(mOutputFile.getName()) && event == FileObserver.CLOSE_WRITE) {
if (mShouldFinishAfterWrite) {
setResult(Activity.RESULT_OK, new Intent().setData(Uri.fromFile(mOutputFile)));
finish();
}
}
}
};
mFileObserver.startWatching();
}
@SuppressLint("SetTextI18n")
private void tick() {
long time = (mStartTime < 0) ? 0 : (SystemClock.elapsedRealtime() - mStartTime);
int minutes = (int) (time / 60000);
int seconds = (int) (time / 1000) % 60;
int milliseconds = (int) (time / 100) % 10;
this.binding.timer.setText(minutes + ":" + (seconds < 10 ? "0" + seconds : seconds) + "." + milliseconds);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.cancel_button:
mHandler.removeCallbacks(mTickExecutor);
stopRecording(false);
setResult(RESULT_CANCELED);
finish();
break;
case R.id.share_button:
this.binding.shareButton.setEnabled(false);
this.binding.shareButton.setText(R.string.please_wait);
mHandler.removeCallbacks(mTickExecutor);
mHandler.postDelayed(() -> stopRecording(true), 500);
break;
}
}
}