@@ -9,39 +9,33 @@ import android.os.Bundle;
import android.os.Environment;
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 androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
-
+import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableSet;
-
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.R;
+import eu.siacs.conversations.databinding.ActivityRecordingBinding;
+import eu.siacs.conversations.utils.TimeFrameUtils;
import java.io.File;
import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.Set;
-
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.R;
-import eu.siacs.conversations.databinding.ActivityRecordingBinding;
-import eu.siacs.conversations.ui.util.SettingsUtils;
-import eu.siacs.conversations.utils.TimeFrameUtils;
public class RecordingActivity extends BaseActivity implements View.OnClickListener {
private ActivityRecordingBinding binding;
private MediaRecorder mRecorder;
- private long mStartTime = 0;
+ private Stopwatch stopwatch;
private final CountDownLatch outputFileWrittenLatch = new CountDownLatch(1);
@@ -63,17 +57,48 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.binding = DataBindingUtil.setContentView(this, R.layout.activity_recording);
+ this.binding.timer.setOnClickListener(
+ v -> {
+ onPauseContinue();
+ });
this.binding.cancelButton.setOnClickListener(this);
this.binding.shareButton.setOnClickListener(this);
this.setFinishOnTouchOutside(false);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
}
+
+ private void onPauseContinue() {
+ final var recorder = this.mRecorder;
+ final var stopwatch = this.stopwatch;
+ if (recorder == null
+ || stopwatch == null
+ || Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
+ return;
+ }
+ if (stopwatch.isRunning()) {
+ try {
+ recorder.pause();
+ stopwatch.stop();
+ } catch (final IllegalStateException e) {
+ Log.d(Config.LOGTAG, "could not pause recording", e);
+ }
+ } else {
+ try {
+ recorder.resume();
+ stopwatch.start();
+ } catch (final IllegalStateException e) {
+ Log.d(Config.LOGTAG, "could not resume recording", e);
+ }
+ }
+ }
+
@Override
public void onStart() {
super.onStart();
if (!startRecording()) {
this.binding.shareButton.setEnabled(false);
- this.binding.timer.setTextAppearance(com.google.android.material.R.style.TextAppearance_Material3_BodyMedium);
+ this.binding.timer.setTextAppearance(
+ com.google.android.material.R.style.TextAppearance_Material3_BodyMedium);
// TODO reset font family. make red?
this.binding.timer.setText(R.string.unable_to_start_recording);
}
@@ -93,22 +118,31 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
private static final Set<String> AAC_SENSITIVE_DEVICES =
new ImmutableSet.Builder<String>()
- .add("FP4") // Fairphone 4 https://codeberg.org/monocles/monocles_chat/issues/133
- .add("ONEPLUS A6000") // OnePlus 6 https://github.com/iNPUTmice/Conversations/issues/4329
- .add("ONEPLUS A6003") // OnePlus 6 https://github.com/iNPUTmice/Conversations/issues/4329
- .add("ONEPLUS A6010") // OnePlus 6T https://codeberg.org/monocles/monocles_chat/issues/133
- .add("ONEPLUS A6013") // OnePlus 6T https://codeberg.org/monocles/monocles_chat/issues/133
- .add("Pixel 4a") // Pixel 4a https://github.com/iNPUTmice/Conversations/issues/4223
- .add("WP12 Pro") // Oukitel WP 12 Pro https://github.com/iNPUTmice/Conversations/issues/4223
- .add("Volla Phone X") // Volla Phone X https://github.com/iNPUTmice/Conversations/issues/4223
+ .add("FP4") // Fairphone 4
+ // https://codeberg.org/monocles/monocles_chat/issues/133
+ .add("ONEPLUS A6000") // OnePlus 6
+ // https://github.com/iNPUTmice/Conversations/issues/4329
+ .add("ONEPLUS A6003") // OnePlus 6
+ // https://github.com/iNPUTmice/Conversations/issues/4329
+ .add("ONEPLUS A6010") // OnePlus 6T
+ // https://codeberg.org/monocles/monocles_chat/issues/133
+ .add("ONEPLUS A6013") // OnePlus 6T
+ // https://codeberg.org/monocles/monocles_chat/issues/133
+ .add("Pixel 4a") // Pixel 4a
+ // https://github.com/iNPUTmice/Conversations/issues/4223
+ .add("WP12 Pro") // Oukitel WP 12 Pro
+ // https://github.com/iNPUTmice/Conversations/issues/4223
+ .add("Volla Phone X") // Volla Phone X
+ // https://github.com/iNPUTmice/Conversations/issues/4223
.build();
private boolean startRecording() {
mRecorder = new MediaRecorder();
+ stopwatch = Stopwatch.createUnstarted();
try {
mRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
} catch (final RuntimeException e) {
- Log.e(Config.LOGTAG,"could not set audio source", e);
+ Log.e(Config.LOGTAG, "could not set audio source", e);
return false;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
@@ -123,8 +157,10 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
} else {
outputFormat = MediaRecorder.OutputFormat.MPEG_4;
mRecorder.setOutputFormat(outputFormat);
- if (AAC_SENSITIVE_DEVICES.contains(Build.MODEL) && Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
- // Changing these three settings for AAC sensitive devices for Android<=13 might lead to sporadically truncated (cut-off) voice messages.
+ if (AAC_SENSITIVE_DEVICES.contains(Build.MODEL)
+ && Build.VERSION.SDK_INT <= Build.VERSION_CODES.TIRAMISU) {
+ // Changing these three settings for AAC sensitive devices for Android<=13 might
+ // lead to sporadically truncated (cut-off) voice messages.
mRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.HE_AAC);
mRecorder.setAudioSamplingRate(24_000);
mRecorder.setAudioEncodingBitRate(28_000);
@@ -140,7 +176,7 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
try {
mRecorder.prepare();
mRecorder.start();
- mStartTime = SystemClock.elapsedRealtime();
+ stopwatch.start();
mHandler.postDelayed(mTickExecutor, 100);
Log.d(Config.LOGTAG, "started recording to " + mOutputFile.getAbsolutePath());
return true;
@@ -154,14 +190,17 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
try {
mRecorder.stop();
mRecorder.release();
- } catch (Exception e) {
+ if (stopwatch.isRunning()) {
+ stopwatch.stop();
+ }
+ } catch (final Exception e) {
+ Log.d(Config.LOGTAG, "could not save recording", e);
if (saveFile) {
Toast.makeText(this, R.string.unable_to_save_recording, Toast.LENGTH_SHORT).show();
return;
}
} finally {
mRecorder = null;
- mStartTime = 0;
}
if (!saveFile && mOutputFile != null) {
if (mOutputFile.delete()) {
@@ -256,24 +295,23 @@ public class RecordingActivity extends BaseActivity implements View.OnClickListe
}
private void tick() {
- this.binding.timer.setText(TimeFrameUtils.formatTimePassed(mStartTime, true));
+ this.binding.timer.setText(
+ TimeFrameUtils.formatElapsedTime(stopwatch.elapsed(TimeUnit.MILLISECONDS), true));
}
@Override
public void onClick(final 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;
+ if (view.getId() == R.id.cancel_button) {
+ mHandler.removeCallbacks(mTickExecutor);
+ stopRecording(false);
+ setResult(RESULT_CANCELED);
+ finish();
+ } else if (view.getId() == R.id.share_button) {
+ this.binding.timer.setOnClickListener(null);
+ this.binding.shareButton.setEnabled(false);
+ this.binding.shareButton.setText(R.string.please_wait);
+ mHandler.removeCallbacks(mTickExecutor);
+ mHandler.postDelayed(() -> stopRecording(true), 500);
}
}
}