@@ -12,13 +12,11 @@ import androidx.compose.ui.unit.IntSize
1212import androidx.core.content.ContextCompat
1313import androidx.lifecycle.LifecycleOwner
1414import androidx.lifecycle.coroutineScope
15+ import com.darkrockstudios.app.securecamera.encryption.VideoEncryptionService
1516import com.darkrockstudios.app.securecamera.obfuscation.FacialDetection
1617import com.darkrockstudios.app.securecamera.preferences.AppSettingsDataSource
17- import com.darkrockstudios.app.securecamera.security.schemes.EncryptionScheme
1818import com.darkrockstudios.app.securecamera.security.streaming.SecvFileFormat
19- import com.darkrockstudios.app.securecamera.security.streaming.VideoEncryptionHelper
2019import kotlinx.coroutines.*
21- import kotlinx.coroutines.flow.collectLatest
2220import org.koin.core.component.KoinComponent
2321import org.koin.core.component.inject
2422import timber.log.Timber
@@ -47,10 +45,8 @@ class CameraState internal constructor(
4745 private val clock: Clock by inject()
4846 private val facialDetection: FacialDetection by inject()
4947 private val preferences: AppSettingsDataSource by inject()
50- private val encryptionScheme: EncryptionScheme by inject()
5148
5249 private var faceAnalyzer: FacialDetectionAnalyzer ? = null
53- private var videoEncryptionHelper: VideoEncryptionHelper ? = null
5450 private val cameraExecutor: ExecutorService = Executors .newSingleThreadExecutor()
5551 private val analysisExecutor: ExecutorService = Executors .newSingleThreadExecutor()
5652 private val analysisScope: CoroutineScope = CoroutineScope (SupervisorJob () + Dispatchers .Default )
@@ -98,66 +94,13 @@ class CameraState internal constructor(
9894 var recordingDurationMs by mutableLongStateOf(0L )
9995 private set
10096
101- var isEncryptingVideo by mutableStateOf(false )
102- private set
103-
104- var encryptionProgress by mutableFloatStateOf(0f )
105- private set
106-
10797 private var activeRecording: Recording ? = null
10898 private var videoCapture: VideoCapture <Recorder >? = null
10999 private var pendingTempFile: File ? = null
110100 private var pendingOutputFile: File ? = null
111101
112102 init {
113103 observePreferences()
114- initializeEncryptionHelper()
115- }
116-
117- private fun initializeEncryptionHelper () {
118- val streamingScheme = encryptionScheme.getStreamingCapability()
119- if (streamingScheme != null ) {
120- videoEncryptionHelper = VideoEncryptionHelper (streamingScheme)
121- observeEncryptionProgress()
122- } else {
123- Timber .w(" Streaming encryption not available" )
124- }
125- }
126-
127- private fun observeEncryptionProgress () {
128- lifecycleOwner.lifecycle.coroutineScope.launch {
129- videoEncryptionHelper?.encryptionProgress?.collectLatest { progress ->
130- when (progress) {
131- is VideoEncryptionHelper .EncryptionProgress .Idle -> {
132- isEncryptingVideo = false
133- encryptionProgress = 0f
134- }
135-
136- is VideoEncryptionHelper .EncryptionProgress .Starting -> {
137- isEncryptingVideo = true
138- encryptionProgress = 0f
139- }
140-
141- is VideoEncryptionHelper .EncryptionProgress .InProgress -> {
142- isEncryptingVideo = true
143- encryptionProgress = progress.progress
144- }
145-
146- is VideoEncryptionHelper .EncryptionProgress .Completed -> {
147- isEncryptingVideo = false
148- encryptionProgress = 0f
149- videoEncryptionHelper?.resetProgress()
150- }
151-
152- is VideoEncryptionHelper .EncryptionProgress .Error -> {
153- isEncryptingVideo = false
154- encryptionProgress = 0f
155- Timber .e(" Encryption error: ${progress.message} " )
156- videoEncryptionHelper?.resetProgress()
157- }
158- }
159- }
160- }
161104 }
162105
163106 private fun observePreferences () {
@@ -323,8 +266,8 @@ class CameraState internal constructor(
323266 return null
324267 }
325268
326- if (isRecording || isEncryptingVideo ) {
327- Timber .w(" Recording or encryption already in progress" )
269+ if (isRecording) {
270+ Timber .w(" Recording already in progress" )
328271 return null
329272 }
330273
@@ -375,11 +318,9 @@ class CameraState internal constructor(
375318 pendingTempFile = null
376319 pendingOutputFile = null
377320 } else {
378- Timber .i(" Recording complete, starting encryption..." )
379- // Start encryption in background
380- lifecycleOwner.lifecycle.coroutineScope.launch {
381- encryptRecordedVideo(tempFile, outputFile)
382- }
321+ Timber .i(" Recording complete, enqueueing encryption..." )
322+ // Enqueue encryption via ForegroundService
323+ enqueueVideoEncryption(context, tempFile, outputFile)
383324 }
384325 }
385326 }
@@ -389,28 +330,12 @@ class CameraState internal constructor(
389330 }
390331
391332 /* *
392- * Encrypts the recorded video from temp file to final encrypted file.
333+ * Enqueues the recorded video for encryption via the ForegroundService.
334+ * The service handles encryption in the background with progress notifications.
393335 */
394- private suspend fun encryptRecordedVideo (tempFile : File , outputFile : File ) {
395- val helper = videoEncryptionHelper
396- if (helper == null ) {
397- Timber .e(" Video encryption helper not available" )
398- // Fall back to keeping the unencrypted file (rename to .mp4)
399- val fallbackFile = File (outputFile.parent, outputFile.nameWithoutExtension + " .mp4" )
400- tempFile.renameTo(fallbackFile)
401- return
402- }
403-
404- val success = helper.encryptVideoFile(tempFile, outputFile)
405- if (success) {
406- Timber .i(" Video encrypted successfully: ${outputFile.absolutePath} " )
407- } else {
408- Timber .e(" Video encryption failed" )
409- // Keep the temp file as fallback (rename to .mp4)
410- val fallbackFile = File (outputFile.parent, outputFile.nameWithoutExtension + " .mp4" )
411- tempFile.renameTo(fallbackFile)
412- }
413-
336+ private fun enqueueVideoEncryption (context : Context , tempFile : File , outputFile : File ) {
337+ Timber .i(" Enqueueing video encryption: ${tempFile.name} -> ${outputFile.name} " )
338+ VideoEncryptionService .enqueueEncryption(context, tempFile, outputFile)
414339 pendingTempFile = null
415340 pendingOutputFile = null
416341 }
0 commit comments