Aperture: Improve video capture delay handling

Change-Id: I449a6d964b6b08c804bbccfec8311c536fb718a4
diff --git a/app/src/main/java/org/lineageos/aperture/MainActivity.kt b/app/src/main/java/org/lineageos/aperture/MainActivity.kt
index e77f425..290565a 100644
--- a/app/src/main/java/org/lineageos/aperture/MainActivity.kt
+++ b/app/src/main/java/org/lineageos/aperture/MainActivity.kt
@@ -59,7 +59,6 @@
 import androidx.core.view.doOnLayout
 import androidx.core.view.isInvisible
 import androidx.core.view.isVisible
-import androidx.lifecycle.lifecycleScope
 import androidx.preference.PreferenceManager
 import coil.decode.VideoFrameDecoder
 import coil.load
@@ -69,10 +68,6 @@
 import coil.size.Scale
 import com.google.android.material.button.MaterialButton
 import com.google.android.material.slider.Slider
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.sync.Mutex
-import kotlinx.coroutines.sync.withLock
 import org.lineageos.aperture.ui.CountDownView
 import org.lineageos.aperture.ui.GridView
 import org.lineageos.aperture.utils.CameraFacing
@@ -159,7 +154,6 @@
     private val videoQuality: Quality
         get() = sharedPreferences.videoQuality
     private var recording: Recording? = null
-    private val recordingLock = Mutex()
 
     private val sharedPreferences by lazy {
         PreferenceManager.getDefaultSharedPreferences(this)
@@ -398,7 +392,7 @@
                         startShutterAnimation(ShutterAnimation.VideoEnd)
                         return@setOnClickListener
                     }
-                    if (!cameraController.isRecording) {
+                    if (cameraState == CameraState.IDLE) {
                         startShutterAnimation(ShutterAnimation.VideoStart)
                     }
                 }
@@ -408,7 +402,7 @@
             startTimerAndRun {
                 when (cameraMode) {
                     CameraMode.PHOTO -> takePhoto()
-                    CameraMode.VIDEO -> lifecycleScope.launch { captureVideo() }
+                    CameraMode.VIDEO -> captureVideo()
                     else -> {}
                 }
             }
@@ -576,10 +570,12 @@
         )
     }
 
-    private suspend fun captureVideo() = recordingLock.withLock {
-        if (cameraController.isRecording) {
-            // Stop the current recording session.
-            recording?.stop()
+    private fun captureVideo() {
+        if (cameraState != CameraState.IDLE) {
+            if (cameraController.isRecording) {
+                // Stop the current recording session.
+                recording?.stop()
+            }
             return
         }
 
@@ -590,66 +586,65 @@
         val outputOptions = StorageUtils.getVideoMediaStoreOutputOptions(contentResolver, location)
 
         // Play shutter sound
-        if (cameraSoundsUtils.playStartVideoRecording()) {
-            // Delay startRecording() by 500ms to avoid recording shutter sound
-            delay(500)
-        }
+        val delayTime = if (cameraSoundsUtils.playStartVideoRecording()) 500L else 0L
 
-        // Start recording
-        recording = cameraController.startRecording(
-            outputOptions,
-            audioConfig,
-            cameraExecutor
-        ) {
-            val updateRecordingStatus = { enabled: Boolean, duration: Long ->
-                // Hide mode buttons
-                photoModeButton.isInvisible = enabled
-                videoModeButton.isInvisible = enabled
-                qrModeButton.isInvisible = enabled
+        handler.postDelayed({
+            // Start recording
+            recording = cameraController.startRecording(
+                outputOptions,
+                audioConfig,
+                cameraExecutor
+            ) {
+                val updateRecordingStatus = { enabled: Boolean, duration: Long ->
+                    // Hide mode buttons
+                    photoModeButton.isInvisible = enabled
+                    videoModeButton.isInvisible = enabled
+                    qrModeButton.isInvisible = enabled
 
-                // Update duration text and visibility state
-                videoDuration.text = TimeUtils.convertNanosToString(duration)
-                videoDuration.isVisible = enabled
+                    // Update duration text and visibility state
+                    videoDuration.text = TimeUtils.convertNanosToString(duration)
+                    videoDuration.isVisible = enabled
 
-                // Update video recording pause/resume button visibility state
-                if (duration == 0L) {
-                    flipCameraButton.isInvisible = enabled
-                    videoRecordingStateButton.isVisible = enabled
+                    // Update video recording pause/resume button visibility state
+                    if (duration == 0L) {
+                        flipCameraButton.isInvisible = enabled
+                        videoRecordingStateButton.isVisible = enabled
+                    }
+                }
+
+                when (it) {
+                    is VideoRecordEvent.Start -> runOnUiThread {
+                        cameraState = CameraState.RECORDING_VIDEO
+                        startVideoRecordingStateAnimation(VideoRecordingStateAnimation.Init)
+                    }
+                    is VideoRecordEvent.Pause -> runOnUiThread {
+                        cameraState = CameraState.RECORDING_VIDEO_PAUSED
+                        startVideoRecordingStateAnimation(VideoRecordingStateAnimation.ResumeToPause)
+                    }
+                    is VideoRecordEvent.Resume -> runOnUiThread {
+                        cameraState = CameraState.RECORDING_VIDEO
+                        startVideoRecordingStateAnimation(VideoRecordingStateAnimation.PauseToResume)
+                    }
+                    is VideoRecordEvent.Status -> runOnUiThread {
+                        updateRecordingStatus(true, it.recordingStats.recordedDurationNanos)
+                    }
+                    is VideoRecordEvent.Finalize -> {
+                        runOnUiThread {
+                            startShutterAnimation(ShutterAnimation.VideoEnd)
+                            updateRecordingStatus(false, 0)
+                        }
+                        cameraSoundsUtils.playStopVideoRecording()
+                        if (it.error != VideoRecordEvent.Finalize.ERROR_NO_VALID_DATA) {
+                            sharedPreferences.lastSavedUri = it.outputResults.outputUri
+                            Log.d(LOG_TAG, "Video capture succeeded: ${it.outputResults.outputUri}")
+                            tookSomething = true
+                        }
+                        cameraState = CameraState.IDLE
+                        recording = null
+                    }
                 }
             }
-
-            when (it) {
-                is VideoRecordEvent.Start -> runOnUiThread {
-                    cameraState = CameraState.RECORDING_VIDEO
-                    startVideoRecordingStateAnimation(VideoRecordingStateAnimation.Init)
-                }
-                is VideoRecordEvent.Pause -> runOnUiThread {
-                    cameraState = CameraState.RECORDING_VIDEO_PAUSED
-                    startVideoRecordingStateAnimation(VideoRecordingStateAnimation.ResumeToPause)
-                }
-                is VideoRecordEvent.Resume -> runOnUiThread {
-                    cameraState = CameraState.RECORDING_VIDEO
-                    startVideoRecordingStateAnimation(VideoRecordingStateAnimation.PauseToResume)
-                }
-                is VideoRecordEvent.Status -> runOnUiThread {
-                    updateRecordingStatus(true, it.recordingStats.recordedDurationNanos)
-                }
-                is VideoRecordEvent.Finalize -> {
-                    runOnUiThread {
-                        startShutterAnimation(ShutterAnimation.VideoEnd)
-                        updateRecordingStatus(false, 0)
-                    }
-                    cameraSoundsUtils.playStopVideoRecording()
-                    if (it.error != VideoRecordEvent.Finalize.ERROR_NO_VALID_DATA) {
-                        sharedPreferences.lastSavedUri = it.outputResults.outputUri
-                        Log.d(LOG_TAG, "Video capture succeeded: ${it.outputResults.outputUri}")
-                        tookSomething = true
-                    }
-                    cameraState = CameraState.IDLE
-                    recording = null
-                }
-            }
-        }
+        }, delayTime)
     }
 
     /**