From 63198c316e722246900026ddaf09ece5f30ab251 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 25 Nov 2023 14:30:34 +0100 Subject: [PATCH] feat: Add poc --- app/build.gradle | 11 ++ app/src/main/AndroidManifest.xml | 8 ++ .../myzel394/alibi/services/VideoService.kt | 111 ++++++++++++++++++ .../java/app/myzel394/alibi/ui/Navigation.kt | 6 +- .../app/myzel394/alibi/ui/screens/POCVideo.kt | 21 ++++ 5 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 app/src/main/java/app/myzel394/alibi/services/VideoService.kt create mode 100644 app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt diff --git a/app/build.gradle b/app/build.gradle index df77255..8f5b385 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -79,6 +79,7 @@ android { buildFeatures { compose true buildConfig = true + viewBinding = true } composeOptions { kotlinCompilerExtensionVersion '1.5.1' @@ -103,6 +104,7 @@ dependencies { implementation "androidx.compose.material:material-icons-extended:1.5.4" implementation 'androidx.appcompat:appcompat:1.6.1' implementation 'androidx.documentfile:documentfile:1.0.1' + implementation 'androidx.lifecycle:lifecycle-service:2.6.2' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' @@ -131,4 +133,13 @@ dependencies { implementation 'com.maxkeppeler.sheets-compose-dialogs:input:1.2.0' implementation 'androidx.activity:activity-ktx:1.8.1' + + def camerax_version = "1.3.0" + implementation "androidx.camera:camera-core:${camerax_version}" + implementation "androidx.camera:camera-camera2:${camerax_version}" + implementation "androidx.camera:camera-lifecycle:${camerax_version}" + implementation "androidx.camera:camera-video:${camerax_version}" + + implementation "androidx.camera:camera-view:${camerax_version}" + implementation "androidx.camera:camera-extensions:${camerax_version}" } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8f67b7c..c0254e2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,9 @@ + + + + + = Build.VERSION_CODES.Q) { + put(MediaStore.MediaColumns.RELATIVE_PATH, "DCIM/Recorded Videos") + } + } + return MediaStoreOutputOptions.Builder( + contentResolver, + MediaStore.Video.Media.EXTERNAL_CONTENT_URI + ) + .setContentValues(contentValues) + .build() + } + + @SuppressLint("MissingPermission") + override fun onCreate() { + super.onCreate() + + val notification = NotificationCompat.Builder( + this, + NotificationHelper.RECORDER_CHANNEL_ID + ).setContentTitle("Video Recorder") + .setContentText("Recording video") + .setSmallIcon(android.R.drawable.ic_media_play) + .build() + + ServiceCompat.startForeground( + this, + NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, + notification, + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA + } else { + 0 + }, + ) + + val cameraProviderFuture = ProcessCameraProvider.getInstance(this) + cameraProviderFuture.addListener({ + // Used to bind the lifecycle of cameras to the lifecycle owner + val cameraProvider = cameraProviderFuture.get() + val recorder = Recorder.Builder() + .setQualitySelector(QualitySelector.from(Quality.HIGHEST)) + .build() + val videoCapture = withOutput(recorder) + // Select back camera as a default + val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA + + // Unbind use cases before rebinding + cameraProvider?.unbindAll() + // Bind use cases to camera + cameraProvider?.bindToLifecycle(this@VideoService, cameraSelector, videoCapture) + + val options = createMediaStoreOutputOptions() + + val recording = videoCapture.output.prepareRecording(this@VideoService, options) + .withAudioEnabled() + + val result = recording.start(ContextCompat.getMainExecutor(this@VideoService), {}) + + scope.launch { + delay(15000) + + result.stop() + + cameraProvider.unbindAll() + stopSelf() + } + }, ContextCompat.getMainExecutor(this)) + } +} \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt b/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt index 985e79d..09384ad 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt @@ -24,6 +24,7 @@ import app.myzel394.alibi.ui.models.AudioRecorderModel import app.myzel394.alibi.ui.screens.AboutScreen import app.myzel394.alibi.ui.screens.AudioRecorderScreen import app.myzel394.alibi.ui.screens.CustomRecordingNotificationsScreen +import app.myzel394.alibi.ui.screens.POCVideo import app.myzel394.alibi.ui.screens.SettingsScreen import app.myzel394.alibi.ui.screens.WelcomeScreen @@ -70,10 +71,7 @@ fun Navigation( scaleOut(targetScale = SCALE_IN) + fadeOut(tween(durationMillis = 150)) } ) { - AudioRecorderScreen( - navController = navController, - audioRecorder = audioRecorder, - ) + POCVideo() } composable( Screen.Settings.route, diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt new file mode 100644 index 0000000..75b0f20 --- /dev/null +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/POCVideo.kt @@ -0,0 +1,21 @@ +package app.myzel394.alibi.ui.screens + +import android.content.Intent +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.platform.LocalContext +import androidx.core.content.ContextCompat +import app.myzel394.alibi.services.VideoService + +@Composable +fun POCVideo() { + val context = LocalContext.current + + LaunchedEffect(Unit) { + val intent = Intent(context, VideoService::class.java) + ContextCompat.startForegroundService(context, intent) + } + + Text(text = "POCVideo") +} \ No newline at end of file