diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..26d3352
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,3 @@
+# Default ignored files
+/shelf/
+/workspace.xml
diff --git a/.idea/.name b/.idea/.name
new file mode 100644
index 0000000..4e1fd7f
--- /dev/null
+++ b/.idea/.name
@@ -0,0 +1 @@
+Wittrail-Android
\ No newline at end of file
diff --git a/.idea/compiler.xml b/.idea/compiler.xml
new file mode 100644
index 0000000..b589d56
--- /dev/null
+++ b/.idea/compiler.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
new file mode 100644
index 0000000..0c0c338
--- /dev/null
+++ b/.idea/deploymentTargetDropDown.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
new file mode 100644
index 0000000..0897082
--- /dev/null
+++ b/.idea/gradle.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..44ca2d9
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
new file mode 100644
index 0000000..fdf8d99
--- /dev/null
+++ b/.idea/kotlinc.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/migrations.xml b/.idea/migrations.xml
new file mode 100644
index 0000000..f8051a6
--- /dev/null
+++ b/.idea/migrations.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..8978d23
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 1c1c931..3199ec4 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -48,17 +48,22 @@ android {
}
}
}
-
+val cameraxVersion = "1.3.1"
dependencies {
-
- implementation("androidx.core:core-ktx:1.10.1")
- implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.6.1")
- implementation("androidx.activity:activity-compose:1.7.0")
+ implementation("androidx.camera:camera-camera2:$cameraxVersion")
+ implementation("androidx.camera:camera-lifecycle:$cameraxVersion")
+ implementation("androidx.camera:camera-video:$cameraxVersion")
+ implementation("androidx.camera:camera-view:$cameraxVersion")
+ implementation("androidx.core:core-ktx:1.12.0")
+ implementation("androidx.lifecycle:lifecycle-runtime-ktx:2.7.0")
+ implementation("androidx.activity:activity-compose:1.8.2")
implementation(platform("androidx.compose:compose-bom:2023.08.00"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.ui:ui-graphics")
implementation("androidx.compose.ui:ui-tooling-preview")
implementation("androidx.compose.material3:material3")
+ implementation("androidx.appcompat:appcompat:1.6.1")
+ implementation("androidx.lifecycle:lifecycle-service:2.7.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.5")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.1")
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index ea712c3..15806b3 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,6 +2,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+ // Handle Permission granted/rejected
+ var permissionGranted = true
+ permissions.entries.forEach {
+ if (it.key in REQUIRED_PERMISSIONS && !it.value)
+ permissionGranted = false
+ }
+ if (!permissionGranted) {
+ Toast.makeText(baseContext,
+ "Permission request denied",
+ Toast.LENGTH_SHORT).show()
+ } else {
+ Log.e("main", "INIT START CAMERA")
+ initStartCamera()
+ }
+ }
+
+ private fun hasCameraPermission() =
+ ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED
+
+ private fun requestCameraPermission() {
+ ActivityCompat.requestPermissions(
+ this, arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION
+ )
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun initStartCamera(){
+ startFrontCameraButton.setOnClickListener {
+ useFrontCamera = true
+ if (hasCameraPermission()) {
+ startRecordingService(useFrontCamera)
+ } else {
+ requestCameraPermission()
+ }
+ }
+
+ startBackCameraButton.setOnClickListener {
+ useFrontCamera = false
+ if (hasCameraPermission()) {
+ startRecordingService(useFrontCamera)
+ } else {
+ requestCameraPermission()
+ }
+ }
+
+ stopCameraButton.setOnClickListener {
+ stopRecordingService()
+ }
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun startRecordingService(useFrontCamera: Boolean) {
+ Log.e("main", "startRecordingService")
+ val serviceIntent = Intent(this, RecordingService::class.java).apply {
+ action = RecordingService.ACTION_START_RECORDING
+ putExtra("useFrontCamera", useFrontCamera)
+ }
+ startForegroundService(serviceIntent)
+ // startService(serviceIntent)
+ }
+
+ private fun stopRecordingService() {
+ Log.e("main", "stopRecordingService")
+ val serviceIntent = Intent(this, RecordingService::class.java).apply {
+ action = RecordingService.ACTION_STOP_RECORDING
+ }
+ stopForeground(STOP_FOREGROUND_DETACH)
+ stopService(serviceIntent)
+ }
+
+}
diff --git a/app/src/main/java/com/urkob/wittrail_android/RecordingService.kt b/app/src/main/java/com/urkob/wittrail_android/RecordingService.kt
new file mode 100644
index 0000000..8ae3180
--- /dev/null
+++ b/app/src/main/java/com/urkob/wittrail_android/RecordingService.kt
@@ -0,0 +1,213 @@
+package com.urkob.wittrail_android
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.content.ContentValues
+import android.content.Intent
+import android.os.Build
+import android.provider.MediaStore
+import android.util.Log
+import android.widget.Toast
+import androidx.camera.core.CameraSelector
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.video.MediaStoreOutputOptions
+import androidx.camera.video.Quality
+import androidx.camera.video.QualitySelector
+import androidx.camera.video.Recorder
+import androidx.camera.video.Recording
+import androidx.camera.video.VideoCapture
+import androidx.camera.video.VideoRecordEvent
+import androidx.core.app.NotificationCompat
+import androidx.core.content.ContextCompat
+import androidx.lifecycle.LifecycleService
+import com.google.common.util.concurrent.ListenableFuture
+import java.text.SimpleDateFormat
+import java.util.Locale
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class RecordingService : LifecycleService() {
+ private lateinit var cameraProviderFuture: ListenableFuture
+ private val tag = "RecordingService"
+ private val fileNameFormat = "yyyy-MM-dd-HH-mm-ss-SSS"
+ private var useFrontCamera = false
+ private var videoCapture: VideoCapture? = null
+ private var recording: Recording? = null
+ private lateinit var cameraExecutor: ExecutorService
+
+ override fun onCreate() {
+ super.onCreate()
+ createNotificationChannel()
+ startForeground(NOTIFICATION_ID, createNotification())
+
+ cameraExecutor = Executors.newSingleThreadExecutor()
+ cameraProviderFuture = ProcessCameraProvider.getInstance(this)
+
+ Log.e(tag, "onCreate")
+ cameraProviderFuture.addListener({
+ // Initialize videoCapture here
+ val recorder = Recorder.Builder()
+ .setQualitySelector(QualitySelector.from(Quality.HIGHEST))
+ .build()
+
+ videoCapture = VideoCapture.withOutput(recorder)
+
+ // Now we can start the camera
+ startCamera()
+ }, ContextCompat.getMainExecutor(this))
+
+ Log.e(tag, "END onCreate")
+ }
+
+ private fun createNotificationChannel() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val serviceChannel = NotificationChannel(
+ CHANNEL_ID,
+ "Foreground Service Channel",
+ NotificationManager.IMPORTANCE_DEFAULT
+ )
+ val manager = getSystemService(NotificationManager::class.java)
+ manager.createNotificationChannel(serviceChannel)
+ }
+ }
+
+ private fun createNotification(): Notification {
+ val notificationIntent = Intent(this, MainActivity::class.java)
+ val pendingIntent = PendingIntent.getActivity(
+ this,
+ 0,
+ notificationIntent,
+ PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
+ )
+
+ return NotificationCompat.Builder(this, CHANNEL_ID)
+ .setContentTitle("Recording Service")
+ .setContentText("Recording is running in the background")
+ .setSmallIcon(R.drawable.ic_launcher_foreground) // Replace with your own drawable resource
+ .setContentIntent(pendingIntent)
+ .setTicker("Ticker text")
+ .build()
+ }
+
+
+ override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
+ useFrontCamera = intent?.getBooleanExtra("useFrontCamera", false) ?: false
+ when (intent?.action) {
+ ACTION_START_RECORDING -> {
+ Log.e(tag, ACTION_START_RECORDING)
+ captureVideo()
+ }
+ ACTION_STOP_RECORDING -> {
+ Log.e(tag, ACTION_STOP_RECORDING)
+
+ stopRecording()
+ // return START_NOT_STICKY
+ }
+ }
+ // return START_STICKY
+ return super.onStartCommand(intent, flags, startId)
+ }
+
+// override fun onDestroy() {
+// Log.e(tag, "ON DESTROY IS CALLED SHOUlD STOP CAMERA")
+// super.onDestroy()
+// }
+
+ private fun startCamera() {
+ Log.e(tag, "startCamera")
+ // Used to bind the lifecycle of cameras to the lifecycle owner
+ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
+ val cameraSelector = if (useFrontCamera) CameraSelector.DEFAULT_FRONT_CAMERA else CameraSelector.DEFAULT_BACK_CAMERA
+ try {
+ // Unbind use cases before rebinding
+ cameraProvider.unbindAll()
+
+ // Bind use cases to camera
+ cameraProvider.bindToLifecycle(this, cameraSelector, videoCapture)
+
+ } catch(exc: Exception) {
+ Log.e(tag, "Use case binding failed", exc)
+ }
+ }
+
+ // Implements VideoCapture use case, including start and stop capturing.
+ private fun captureVideo() {
+ Log.e(tag, "START CAPTURE VIDEO")
+ val videoCapture = this.videoCapture ?: return
+
+ val curRecording = recording
+ if (curRecording != null) {
+ Log.e(tag, "curRecording != null")
+ // Stop the current recording session.
+ curRecording.stop()
+ recording = null
+ return
+ }
+
+ // create and start a new recording session
+ val name = SimpleDateFormat(fileNameFormat, Locale.US)
+ .format(System.currentTimeMillis())
+ val contentValues = ContentValues().apply {
+ put(MediaStore.MediaColumns.DISPLAY_NAME, name)
+ put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4")
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ put(MediaStore.Video.Media.RELATIVE_PATH, "Movies/wittrail")
+ }
+ }
+ Log.e(tag, "contentValues")
+ val mediaStoreOutputOptions = MediaStoreOutputOptions
+ .Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
+ .setContentValues(contentValues)
+ .build()
+ Log.e(tag, "mediaStoreOutputOptions")
+ recording = videoCapture.output
+ .prepareRecording(this, mediaStoreOutputOptions)
+ .start(ContextCompat.getMainExecutor(this)) { recordEvent ->
+ when(recordEvent) {
+ is VideoRecordEvent.Start -> {
+ // TODO: should only display stop button
+ Log.e(tag, "START RECORDING")
+ }
+ is VideoRecordEvent.Finalize -> {
+ Log.e(tag, "ON FINALIZE")
+ if (!recordEvent.hasError()) {
+ Log.d(tag, "Saved URI: " + recordEvent.outputResults.outputUri)
+ val msg = "Video capture succeeded: " +
+ "${recordEvent.outputResults.outputUri}"
+ Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT)
+ .show()
+ Log.d(tag, msg)
+ } else {
+ Log.e(tag, "Video capture ends with error: " +
+ "${recordEvent.error} $recordEvent")
+ Log.d(tag, "Saved URI: " + recordEvent.outputResults.outputUri)
+ recording?.close()
+ recording = null
+ }
+ Log.e(tag, "RECORDING STOPPED")
+ }
+ }
+ }
+ }
+ companion object {
+ const val ACTION_START_RECORDING = "com.urkob.wittrail_android.action.START_RECORDING"
+ const val ACTION_STOP_RECORDING = "com.urkob.wittrail_android.action.STOP_RECORDING"
+ private const val CHANNEL_ID = "ForegroundServiceChannel"
+ private const val NOTIFICATION_ID = 1
+ }
+ private fun stopRecording() {
+ Log.e(tag, "stopRecording")
+
+ val curRecording = recording
+ if (curRecording != null) {
+ Log.e(tag, "stopRecording curRecording != null Stop the current recording session")
+ curRecording.stop()
+ recording = null
+ return
+ }
+ }
+}
+
diff --git a/app/src/main/java/com/urkob/wittrail_android/RecordingService.kt.txt b/app/src/main/java/com/urkob/wittrail_android/RecordingService.kt.txt
new file mode 100644
index 0000000..873b945
--- /dev/null
+++ b/app/src/main/java/com/urkob/wittrail_android/RecordingService.kt.txt
@@ -0,0 +1,236 @@
+package com.urkob.wittrail_android
+
+import android.app.Notification
+import android.app.NotificationChannel
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.app.Service
+import android.content.Intent
+import android.media.MediaScannerConnection
+import android.net.Uri
+import android.os.Build
+import android.os.IBinder
+import android.provider.MediaStore
+import android.util.Log
+import android.widget.Toast
+import androidx.camera.core.CameraSelector
+import androidx.camera.core.Preview
+import androidx.camera.lifecycle.ProcessCameraProvider
+import androidx.camera.video.MediaStoreOutputOptions
+import androidx.camera.video.Recorder
+import androidx.camera.video.Recording
+import androidx.camera.video.VideoCapture
+import androidx.core.app.NotificationCompat
+import androidx.core.content.ContextCompat
+import com.google.common.util.concurrent.ListenableFuture
+import java.io.File
+import java.text.SimpleDateFormat
+import java.util.Locale
+import java.util.concurrent.ExecutorService
+import java.util.concurrent.Executors
+
+
+class RecordingServices : Service() {
+ private lateinit var cameraExecutor: ExecutorService
+ private lateinit var cameraProviderFuture: ListenableFuture
+ private var recording: Recording? = null
+ private lateinit var videoCapture: VideoCapture
+
+ private val notificationChannelId = "RECORDING_CHANNEL"
+ private val notificationId = 1
+ private var videoFile: File? = null
+
+ override fun onCreate() {
+ super.onCreate()
+ cameraExecutor = Executors.newSingleThreadExecutor()
+ }
+
+ override fun onBind(intent: Intent): IBinder? {
+ return null
+ }
+
+ private fun bindCamera() {
+ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
+ val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+ // You need to build the use cases. For example:
+ val previewUseCase = Preview.Builder().build()
+ val videoCaptureUseCase = VideoCapture.withOutput(Recorder.Builder().build())
+
+ try {
+ cameraProvider.unbindAll()
+ cameraProvider.bindToLifecycle(this, cameraSelector, previewUseCase, videoCaptureUseCase)
+ } catch (exc: Exception) {
+ Log.e(TAG, "Use case binding failed", exc)
+ }
+ }
+
+ private fun startRecording() {
+ val mediaStoreOutputOptions = MediaStoreOutputOptions.Builder(contentResolver, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
+ .build()
+
+ val outputOptions = VideoCapture.OutputFileOptions.Builder(videoFile).build()
+ // Start recording
+ videoCapture.startRecording(outputOptions, cameraExecutor, object : VideoCapture.OnVideoSavedCallback {
+ fun onVideoSaved(outputFileResults: VideoCapture.OutputFileResults) {
+ val savedUri = outputFileResults.savedUri ?: Uri.fromFile(videoFile)
+ Log.d(TAG, "Video File Saved at $savedUri")
+ // Here you can handle the saved video file
+ }
+
+ fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
+ Log.e(TAG, "Video capture error: $message", cause)
+ }
+ })
+ }
+
+
+ private val captureListener = object : VideoCapture.OnVideoSavedCallback {
+ fun onVideoSaved(file: File) {
+ Log.d(TAG, "Video File: $file")
+ // Here you can handle the saved video file
+ }
+ fun onError(videoCaptureError: Int, message: String, cause: Throwable?) {
+ Log.e(TAG, "Video capture error: $message", cause)
+ }
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ cameraExecutor.shutdown()
+ recording?.stop() // Stop the recording
+ }
+
+ // Helper function to create a file
+ private fun createFile(baseFolder: File, format: String, extension: String) =
+ File(baseFolder, SimpleDateFormat(format, Locale.US)
+ .format(System.currentTimeMillis()) + extension)
+
+ companion object {
+ private const val TAG = "RecordingService"
+ private const val FILENAME = "yyyy-MM-dd-HH-mm-ss-SSS"
+ private const val VIDEO_EXTENSION = ".mp4"
+ private val outputDirectory: File by lazy {
+ getOutputDirectory()
+ }
+ }
+
+ // Method to get the output directory
+ private fun getOutputDirectory(): File {
+ val mediaDir = externalMediaDirs.firstOrNull()?.let {
+ File(it, resources.getString(R.string.app_name)).apply { mkdirs() }
+ }
+ return if (mediaDir != null && mediaDir.exists())
+ mediaDir else filesDir
+ }
+
+ override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
+ createNotificationChannel()
+ startForeground(notificationId, createNotification())
+
+ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
+ val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+ val previewUseCase = Preview.Builder().build()
+ val videoCaptureUseCase = VideoCapture.withOutput(Recorder.Builder().build())
+
+ try {
+ cameraProvider.unbindAll()
+ cameraProvider.bindToLifecycle(this, cameraSelector, previewUseCase, videoCaptureUseCase)
+ } catch (exc: Exception) {
+ Log.e(TAG, "Use case binding failed", exc)
+ }
+
+ cameraProviderFuture = ProcessCameraProvider.getInstance(this)
+ cameraProviderFuture.addListener(Runnable {
+ val cameraProvider = cameraProviderFuture.get()
+ bindCamera()
+ }, ContextCompat.getMainExecutor(this))
+
+ return START_STICKY
+ }
+
+ private fun startCamera() {
+ val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
+
+ val preview = Preview.Builder()
+ .build()
+ .also {
+ it.setSurfaceProvider(viewBinding.viewFinder.surfaceProvider)
+ }
+
+ val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
+
+ val videoCapture = VideoCapture.withOutput(Recorder.Builder().build())
+
+
+ try {
+ cameraProvider.unbindAll()
+ cameraProvider.bindToLifecycle(
+ this, cameraSelector, preview)
+
+ cameraProvider.bindToLifecycle(
+ this, cameraSelector, preview, imageCapture, videoCapture)
+ } catch (exc: Exception) {
+ Log.e(TAG, "Use case binding failed", exc)
+ }
+ }
+
+
+ private fun stopRecording() {
+ try {
+ Log.d("RecordingService", "Recording stopped. File saved at: ${videoFile?.absolutePath}")
+ // Now scan the file
+ videoFile?.let { file ->
+ Log.d("RecordingService", "Recording stopped. File saved at: ${file.absolutePath}")
+ scanFile(file) // Use 'let' to ensure videoFile is not null when calling scanFile
+ }
+ } catch (e: RuntimeException) {
+ e.printStackTrace()
+ Toast.makeText(this, "Recording stop failed: ${e.message}", Toast.LENGTH_SHORT).show()
+ }
+ }
+
+
+ private fun scanFile(file: File) {
+ MediaScannerConnection.scanFile(
+ this@`RecordingService.txt`,
+ arrayOf(file.absolutePath),
+ null
+ ) { path: String?, uri: Uri? ->
+ Log.d("RecordingService", "Scanned $path:")
+ Log.d("RecordingService", "-> Uri = $uri")
+ }
+ }
+
+
+ private fun createNotification(): Notification {
+ val notificationIntent = Intent(this, MainActivity::class.java)
+ // val pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0)
+
+ val pendingIntent = PendingIntent.getActivity(
+ this, 0, notificationIntent,
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
+ )
+
+ return NotificationCompat.Builder(this, notificationChannelId)
+ .setContentTitle("Recording Service")
+ .setContentText("Recording in progress...")
+ .setSmallIcon(android.R.drawable.ic_dialog_info)
+ .setContentIntent(pendingIntent)
+ .build()
+ }
+
+ private fun createNotificationChannel() {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val serviceChannel = NotificationChannel(
+ notificationChannelId,
+ "Foreground Service Channel",
+ NotificationManager.IMPORTANCE_DEFAULT
+ )
+
+ val manager = getSystemService(NotificationManager::class.java)
+ manager.createNotificationChannel(serviceChannel)
+ }
+ }
+}
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..b364530
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/values/themes.xml b/app/src/main/res/values/themes.xml
index 01a29e6..b6c038d 100644
--- a/app/src/main/res/values/themes.xml
+++ b/app/src/main/res/values/themes.xml
@@ -1,5 +1,9 @@
-
-
\ No newline at end of file
+
+
+
+