From d89e918996800ac87330cfcb72ce4cd6f64b2840 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Fri, 27 Oct 2023 12:18:15 +0200 Subject: [PATCH 01/11] feat: Add boot behavior to AppSettings --- app/src/main/java/app/myzel394/alibi/db/AppSettings.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt index 505f1a7b3..565a5fdf9 100644 --- a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt +++ b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt @@ -19,6 +19,7 @@ data class AppSettings( val showAdvancedSettings: Boolean = false, val theme: Theme = Theme.SYSTEM, val lastRecording: RecordingInformation? = null, + val bootBehavior: BootBehavior? = BootBehavior.START_RECORDING, ) { fun setShowAdvancedSettings(showAdvancedSettings: Boolean): AppSettings { return copy(showAdvancedSettings = showAdvancedSettings) @@ -44,12 +45,21 @@ data class AppSettings( return copy(lastRecording = lastRecording) } + fun setBootBehavior(bootBehavior: BootBehavior?): AppSettings { + return copy(bootBehavior = bootBehavior) + } + enum class Theme { SYSTEM, LIGHT, DARK, } + enum class BootBehavior { + START_RECORDING, + SHOW_NOTIFICATION, + } + fun exportToString(): String { return Json.encodeToString(serializer(), this) } From 60fc16f2c431290f65b383b3b48da448fb2cf323 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Fri, 27 Oct 2023 16:44:53 +0200 Subject: [PATCH 02/11] current stand --- app/src/main/AndroidManifest.xml | 10 ++ .../myzel394/alibi/receivers/BootReceiver.kt | 43 ++++++++ .../alibi/services/RecorderService.kt | 4 + .../SettingsScreen/atoms/BootBehaviorTile.kt | 101 ++++++++++++++++++ app/src/main/res/values/strings.xml | 2 + 5 files changed, 160 insertions(+) create mode 100644 app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt create mode 100644 app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/BootBehaviorTile.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8f67b7cd0..3df9a3da6 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -13,6 +13,8 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt b/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt new file mode 100644 index 000000000..d4134587e --- /dev/null +++ b/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt @@ -0,0 +1,43 @@ +package app.myzel394.alibi.receivers + +import android.content.BroadcastReceiver +import android.content.ComponentName +import android.content.Context +import android.content.Intent +import android.content.ServiceConnection +import android.os.IBinder +import androidx.core.content.ContextCompat +import app.myzel394.alibi.services.AudioRecorderService +import app.myzel394.alibi.services.RecorderService +import app.myzel394.alibi.ui.enums.Screen +import app.myzel394.alibi.ui.models.AudioRecorderModel + +class BootReceiver : BroadcastReceiver() { + override fun onReceive(context: Context?, intent: Intent?) { + println("Received new intent: ${intent?.action}") + + if (intent?.action == Intent.ACTION_BOOT_COMPLETED) { + println("Starting service") + + val connection = object : ServiceConnection { + override fun onServiceConnected(className: ComponentName, service: IBinder) { + ((service as RecorderService.RecorderBinder).getService() as AudioRecorderService).also { recorder -> + recorder.startRecording() + } + } + + override fun onServiceDisconnected(arg0: ComponentName) { + } + } + + val intent = Intent(context, AudioRecorderService::class.java).apply { + action = "initStart" + } + println("Starting service checking context") + if (context != null) { + println("Starting service with context") + ContextCompat.startForegroundService(context, intent) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt index 02b579794..b67096568 100644 --- a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt @@ -57,6 +57,10 @@ abstract class RecorderService : Service() { } } + "initStart" -> { + startRecording() + } + "changeState" -> { val newState = intent.getStringExtra("newState")?.let { RecorderState.valueOf(it) diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/BootBehaviorTile.kt b/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/BootBehaviorTile.kt new file mode 100644 index 000000000..efa48da9b --- /dev/null +++ b/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/BootBehaviorTile.kt @@ -0,0 +1,101 @@ +package app.myzel394.alibi.ui.components.SettingsScreen.atoms + +import androidx.appcompat.app.AppCompatDelegate +import androidx.compose.foundation.clickable +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.material.icons.Icons +import androidx.compose.material.icons.filled.CheckCircle +import androidx.compose.material.icons.filled.Smartphone +import androidx.compose.material.icons.filled.Translate +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.Icon +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.core.os.LocaleListCompat +import app.myzel394.alibi.R +import app.myzel394.alibi.SUPPORTED_LOCALES +import app.myzel394.alibi.db.AppSettings +import app.myzel394.alibi.ui.components.atoms.SettingsTile +import app.myzel394.alibi.ui.utils.IconResource +import com.maxkeppeker.sheets.core.models.base.ButtonStyle +import com.maxkeppeker.sheets.core.models.base.Header +import com.maxkeppeker.sheets.core.models.base.IconSource +import com.maxkeppeker.sheets.core.models.base.SelectionButton +import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState +import com.maxkeppeler.sheets.list.ListDialog +import com.maxkeppeler.sheets.list.models.ListOption +import com.maxkeppeler.sheets.list.models.ListSelection +import java.util.Locale + +/* +val BOOT_BEHAVIOR_TITLE_MAP = mapOf( + AppSettings.BootBehavior.SHOW_NOTIFICATION to R.string.ui_settings_bootBehavior_values_SHOW_NOTIFICATION_title, + AppSettings.BootBehavior.START_RECORDING to R.string.ui_settings_bootBehavior_values_START_RECORDING_title +) + +@OptIn(ExperimentalMaterial3Api::class) +@Composable +fun BootBehaviorTile() { + val showDialog = rememberUseCaseState() + + ListDialog( + state = showDialog, + header = Header.Default( + title = stringResource(R.string.ui_settings_bootBehavior_title), + icon = IconSource( + painter = IconResource.fromImageVector(Icons.Default.Smartphone) + .asPainterResource(), + contentDescription = null, + ) + ), + selection = ListSelection.Single( + showRadioButtons = true, + options = AppSettings.BootBehavior.entries.map { + ListOption( + titleText = stringResource("ui_settings_bootBehavior_values_${it.name}_title"), + subtitleText = stringResource("ui_settings_bootBehavior_values_${it.name}_subtitle"), + ) + }.toList(), + options = IntRange(0, AppSettings.BootBehavior.entries.size).map { index -> + val locale = locales[index]!! + + ListOption( + titleText = locale.displayName, + subtitleText = locale.getDisplayName(Locale.ENGLISH), + ) + }.toList(), + positiveButton = SelectionButton( + icon = IconSource( + painter = IconResource.fromImageVector(Icons.Default.CheckCircle) + .asPainterResource(), + contentDescription = null, + ), + text = stringResource(android.R.string.ok), + type = ButtonStyle.TEXT, + ) + ) { index, _ -> + AppCompatDelegate.setApplicationLocales( + LocaleListCompat.forLanguageTags( + locales[index]!!.toLanguageTag(), + ), + ) + }, + ) + SettingsTile( + firstModifier = Modifier + .fillMaxHeight() + .clickable { + showDialog.show() + }, + title = stringResource(R.string.ui_settings_bootBehavior_title), + leading = { + Icon( + Icons.Default.Smartphone, + contentDescription = null, + ) + }, + ) +} + + */ \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 76c30ab1b..17065cef5 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -109,4 +109,6 @@ Become a GitHub Sponsor Delete Recordings Immediately If enabled, Alibi will immediately delete recordings after you have saved the file. + Boot Behavior + Show a notification \ No newline at end of file From 2e9f1c7ade4bc33e56bf218c5ad63f93e32c7f4d Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 28 Oct 2023 17:52:32 +0200 Subject: [PATCH 03/11] feat: Add boot notification --- .../app/myzel394/alibi/NotificationHelper.kt | 28 +++-- .../java/app/myzel394/alibi/db/AppSettings.kt | 8 +- .../myzel394/alibi/receivers/BootReceiver.kt | 112 +++++++++++++++--- .../alibi/ui/models/AudioRecorderModel.kt | 2 +- app/src/main/res/values/strings.xml | 4 + 5 files changed, 126 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/app/myzel394/alibi/NotificationHelper.kt b/app/src/main/java/app/myzel394/alibi/NotificationHelper.kt index 679cee744..c34c221f0 100644 --- a/app/src/main/java/app/myzel394/alibi/NotificationHelper.kt +++ b/app/src/main/java/app/myzel394/alibi/NotificationHelper.kt @@ -9,18 +9,30 @@ import androidx.annotation.RequiresApi object NotificationHelper { const val RECORDER_CHANNEL_ID = "recorder" const val RECORDER_CHANNEL_NOTIFICATION_ID = 1 + const val BOOT_CHANNEL_ID = "boot" + const val BOOT_CHANNEL_NOTIFICATION_ID = 2 @RequiresApi(Build.VERSION_CODES.O) fun createChannels(context: Context) { - val channel = NotificationChannel( - RECORDER_CHANNEL_ID, - context.resources.getString(R.string.notificationChannels_recorder_name), - android.app.NotificationManager.IMPORTANCE_LOW, - ) - channel.description = context.resources.getString(R.string.notificationChannels_recorder_description) - val notificationManager = context.getSystemService(NotificationManager::class.java) - notificationManager.createNotificationChannel(channel) + notificationManager.createNotificationChannel( + NotificationChannel( + RECORDER_CHANNEL_ID, + context.getString(R.string.notificationChannels_recorder_name), + NotificationManager.IMPORTANCE_LOW, + ).apply { + description = context.getString(R.string.notificationChannels_recorder_description) + } + ) + notificationManager.createNotificationChannel( + NotificationChannel( + BOOT_CHANNEL_ID, + context.getString(R.string.notificationChannels_boot_name), + NotificationManager.IMPORTANCE_LOW, + ).apply { + description = context.getString(R.string.notificationChannels_boot_description) + } + ) } } \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt index 565a5fdf9..8714157f8 100644 --- a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt +++ b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt @@ -19,7 +19,7 @@ data class AppSettings( val showAdvancedSettings: Boolean = false, val theme: Theme = Theme.SYSTEM, val lastRecording: RecordingInformation? = null, - val bootBehavior: BootBehavior? = BootBehavior.START_RECORDING, + val bootBehavior: BootBehavior? = BootBehavior.SHOW_NOTIFICATION, ) { fun setShowAdvancedSettings(showAdvancedSettings: Boolean): AppSettings { return copy(showAdvancedSettings = showAdvancedSettings) @@ -56,7 +56,13 @@ data class AppSettings( } enum class BootBehavior { + // Always start recording, no matter if it was interrupted or not START_RECORDING, + + // Only start recording if it was interrupted + CONTINUE_RECORDING, + + // Show a notification if interrupted SHOW_NOTIFICATION, } diff --git a/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt b/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt index d4134587e..cb45e933c 100644 --- a/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt +++ b/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt @@ -1,42 +1,118 @@ package app.myzel394.alibi.receivers +import android.app.NotificationManager +import android.app.PendingIntent import android.content.BroadcastReceiver import android.content.ComponentName import android.content.Context import android.content.Intent import android.content.ServiceConnection import android.os.IBinder +import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat +import app.myzel394.alibi.MainActivity +import app.myzel394.alibi.NotificationHelper +import app.myzel394.alibi.R +import app.myzel394.alibi.dataStore +import app.myzel394.alibi.db.AppSettings +import app.myzel394.alibi.helpers.AudioRecorderExporter import app.myzel394.alibi.services.AudioRecorderService +import app.myzel394.alibi.services.RecorderNotificationHelper import app.myzel394.alibi.services.RecorderService import app.myzel394.alibi.ui.enums.Screen import app.myzel394.alibi.ui.models.AudioRecorderModel +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch +import kotlinx.serialization.json.Json class BootReceiver : BroadcastReceiver() { - override fun onReceive(context: Context?, intent: Intent?) { - println("Received new intent: ${intent?.action}") - - if (intent?.action == Intent.ACTION_BOOT_COMPLETED) { - println("Starting service") + private var job = SupervisorJob() + private var scope = CoroutineScope(Dispatchers.IO + job) - val connection = object : ServiceConnection { - override fun onServiceConnected(className: ComponentName, service: IBinder) { - ((service as RecorderService.RecorderBinder).getService() as AudioRecorderService).also { recorder -> - recorder.startRecording() - } + private fun startRecording(context: Context, settings: AppSettings) { + val connection = object : ServiceConnection { + override fun onServiceConnected(className: ComponentName, service: IBinder) { + ((service as RecorderService.RecorderBinder).getService() as AudioRecorderService).also { recorder -> + recorder.startRecording() } + } - override fun onServiceDisconnected(arg0: ComponentName) { - } + override fun onServiceDisconnected(arg0: ComponentName) { } + } - val intent = Intent(context, AudioRecorderService::class.java).apply { - action = "initStart" + val intent = Intent(context, AudioRecorderService::class.java).apply { + action = "init" + if (settings.notificationSettings != null) { + putExtra( + "notificationDetails", + Json.encodeToString( + RecorderNotificationHelper.NotificationDetails.serializer(), + RecorderNotificationHelper.NotificationDetails.fromNotificationSettings( + context, + settings.notificationSettings + ) + ), + ) } - println("Starting service checking context") - if (context != null) { - println("Starting service with context") - ContextCompat.startForegroundService(context, intent) + } + ContextCompat.startForegroundService(context, intent) + context.bindService(intent, connection, 0) + } + + private fun showNotification(context: Context) { + if (!AudioRecorderExporter.hasRecordingsAvailable(context)) { + // Nothing interrupted, so no notification needs to be shown + return + } + + val notification = NotificationCompat.Builder(context, NotificationHelper.BOOT_CHANNEL_ID) + .setPriority(NotificationCompat.PRIORITY_LOW) + .setCategory(NotificationCompat.CATEGORY_REMINDER) + .setSmallIcon(R.drawable.launcher_monochrome_noopacity) + .setContentIntent( + PendingIntent.getActivity( + context, + 0, + Intent(context, MainActivity::class.java), + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + ) + .setOnlyAlertOnce(true) + .setContentTitle(context.getString(R.string.notification_boot_title)) + .setContentText(context.getString(R.string.notification_boot_message)) + .build() + + val notificationManager = + context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager + + notificationManager.notify(NotificationHelper.BOOT_CHANNEL_NOTIFICATION_ID, notification) + } + + override fun onReceive(context: Context?, intent: Intent?) { + if (intent?.action != Intent.ACTION_BOOT_COMPLETED || context == null) { + return + } + + scope.launch { + context.dataStore.data.collectLatest { settings -> + when (settings.bootBehavior) { + AppSettings.BootBehavior.CONTINUE_RECORDING -> { + if (AudioRecorderExporter.hasRecordingsAvailable(context)) { + startRecording(context, settings) + } + } + + AppSettings.BootBehavior.START_RECORDING -> startRecording(context, settings) + AppSettings.BootBehavior.SHOW_NOTIFICATION -> showNotification(context) + null -> { + // Nothing to do + } + } } } } diff --git a/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt b/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt index 7c9724af8..da3f1d721 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/models/AudioRecorderModel.kt @@ -125,7 +125,7 @@ class AudioRecorderModel : ViewModel() { } } ContextCompat.startForegroundService(context, intent) - context.bindService(intent, connection, Context.BIND_AUTO_CREATE) + context.bindService(intent, connection, 0) } fun stopRecording(context: Context) { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 17065cef5..f33ccf0f7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -111,4 +111,8 @@ If enabled, Alibi will immediately delete recordings after you have saved the file. Boot Behavior Show a notification + Boot notification + If enabled, you\'ll be informed that your recording was interrupted + Alibi was interrupted + Your device restarted and your recording has been interrupted \ No newline at end of file From a0bf2d03eb90733a7b30550cf5e31d8b2ee5716f Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 28 Oct 2023 18:20:00 +0200 Subject: [PATCH 04/11] feat: Add automatic recording functionality on boot --- app/src/main/AndroidManifest.xml | 1 + .../main/java/app/myzel394/alibi/db/AppSettings.kt | 2 +- .../java/app/myzel394/alibi/receivers/BootReceiver.kt | 11 ++++++++++- .../alibi/services/IntervalRecorderService.kt | 11 +++++++++++ .../app/myzel394/alibi/services/RecorderService.kt | 6 +++--- 5 files changed, 26 insertions(+), 5 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 3df9a3da6..32cc19fb9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -47,6 +47,7 @@ diff --git a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt index 8714157f8..ffec8cb18 100644 --- a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt +++ b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt @@ -19,7 +19,7 @@ data class AppSettings( val showAdvancedSettings: Boolean = false, val theme: Theme = Theme.SYSTEM, val lastRecording: RecordingInformation? = null, - val bootBehavior: BootBehavior? = BootBehavior.SHOW_NOTIFICATION, + val bootBehavior: BootBehavior? = BootBehavior.START_RECORDING, ) { fun setShowAdvancedSettings(showAdvancedSettings: Boolean): AppSettings { return copy(showAdvancedSettings = showAdvancedSettings) diff --git a/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt b/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt index cb45e933c..c12ef8f5c 100644 --- a/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt +++ b/app/src/main/java/app/myzel394/alibi/receivers/BootReceiver.kt @@ -45,8 +45,15 @@ class BootReceiver : BroadcastReceiver() { } } + println("BootReceiver.startRecording()") val intent = Intent(context, AudioRecorderService::class.java).apply { action = "init" + + putExtra( + "startImmediately", + true, + ) + if (settings.notificationSettings != null) { putExtra( "notificationDetails", @@ -61,7 +68,6 @@ class BootReceiver : BroadcastReceiver() { } } ContextCompat.startForegroundService(context, intent) - context.bindService(intent, connection, 0) } private fun showNotification(context: Context) { @@ -98,8 +104,11 @@ class BootReceiver : BroadcastReceiver() { return } + println("BootReceiver.onReceive()") + scope.launch { context.dataStore.data.collectLatest { settings -> + println("BootBehavior: ${settings.bootBehavior}") when (settings.bootBehavior) { AppSettings.BootBehavior.CONTINUE_RECORDING -> { if (AudioRecorderExporter.hasRecordingsAvailable(context)) { diff --git a/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt index 88d2bca0a..df06b018e 100644 --- a/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt @@ -58,10 +58,21 @@ abstract class IntervalRecorderService : ExtraRecorderInformationService() { } } + private fun fetchCounterValue() { + val files = outputFolder.listFiles()?.filter { + val name = it.nameWithoutExtension + + name.toIntOrNull() != null + }?.toList() ?: emptyList() + + counter = files.size + } + override fun start() { super.start() outputFolder.mkdirs() + fetchCounterValue() scope.launch { dataStore.data.collectLatest { preferenceSettings -> diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt index b67096568..60675d400 100644 --- a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt @@ -55,10 +55,10 @@ abstract class RecorderService : Service() { it ) } - } - "initStart" -> { - startRecording() + if (intent.getBooleanExtra("startImmediately", false)) { + startRecording() + } } "changeState" -> { From bd4af5f26aad5a4bd63ac3c0923b1b5034564272 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 28 Oct 2023 18:40:59 +0200 Subject: [PATCH 05/11] feat: Add BootBehaviorTile to SettingsScreen --- .../SettingsScreen/atoms/BootBehaviorTile.kt | 63 +++++++++++++------ .../alibi/ui/screens/SettingsScreen.kt | 2 + app/src/main/res/values/strings.xml | 7 +++ 3 files changed, 52 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/BootBehaviorTile.kt b/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/BootBehaviorTile.kt index efa48da9b..9982f5bb4 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/BootBehaviorTile.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/SettingsScreen/atoms/BootBehaviorTile.kt @@ -9,12 +9,16 @@ import androidx.compose.material.icons.filled.Smartphone import androidx.compose.material.icons.filled.Translate import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon +import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Modifier +import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.res.stringResource import androidx.core.os.LocaleListCompat import app.myzel394.alibi.R import app.myzel394.alibi.SUPPORTED_LOCALES +import app.myzel394.alibi.dataStore import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.ui.components.atoms.SettingsTile import app.myzel394.alibi.ui.utils.IconResource @@ -26,23 +30,43 @@ import com.maxkeppeker.sheets.core.models.base.rememberUseCaseState import com.maxkeppeler.sheets.list.ListDialog import com.maxkeppeler.sheets.list.models.ListOption import com.maxkeppeler.sheets.list.models.ListSelection +import kotlinx.coroutines.launch import java.util.Locale -/* val BOOT_BEHAVIOR_TITLE_MAP = mapOf( AppSettings.BootBehavior.SHOW_NOTIFICATION to R.string.ui_settings_bootBehavior_values_SHOW_NOTIFICATION_title, - AppSettings.BootBehavior.START_RECORDING to R.string.ui_settings_bootBehavior_values_START_RECORDING_title + AppSettings.BootBehavior.START_RECORDING to R.string.ui_settings_bootBehavior_values_START_RECORDING_title, + AppSettings.BootBehavior.CONTINUE_RECORDING to R.string.ui_settings_bootBehavior_values_CONTINUE_RECORDING_title, +) +val BOOT_BEHAVIOR_DESCRIPTION_MAP = mapOf( + AppSettings.BootBehavior.SHOW_NOTIFICATION to R.string.ui_settings_bootBehavior_values_SHOW_NOTIFICATION_description, + AppSettings.BootBehavior.START_RECORDING to R.string.ui_settings_bootBehavior_values_START_RECORDING_description, + AppSettings.BootBehavior.CONTINUE_RECORDING to R.string.ui_settings_bootBehavior_values_CONTINUE_RECORDING_description, ) @OptIn(ExperimentalMaterial3Api::class) @Composable -fun BootBehaviorTile() { +fun BootBehaviorTile( + settings: AppSettings, +) { + val scope = rememberCoroutineScope() val showDialog = rememberUseCaseState() + val dataStore = LocalContext.current.dataStore + + fun updateValue(behavior: AppSettings.BootBehavior?) { + scope.launch { + dataStore.updateData { + it.setBootBehavior( + behavior + ) + } + } + } ListDialog( state = showDialog, header = Header.Default( - title = stringResource(R.string.ui_settings_bootBehavior_title), + title = stringResource(R.string.ui_settings_bootBehavior_help), icon = IconSource( painter = IconResource.fromImageVector(Icons.Default.Smartphone) .asPainterResource(), @@ -53,18 +77,19 @@ fun BootBehaviorTile() { showRadioButtons = true, options = AppSettings.BootBehavior.entries.map { ListOption( - titleText = stringResource("ui_settings_bootBehavior_values_${it.name}_title"), - subtitleText = stringResource("ui_settings_bootBehavior_values_${it.name}_subtitle"), + titleText = stringResource( + BOOT_BEHAVIOR_TITLE_MAP[it]!! + ), + subtitleText = stringResource( + BOOT_BEHAVIOR_DESCRIPTION_MAP[it]!! + ), + selected = settings.bootBehavior == it, ) - }.toList(), - options = IntRange(0, AppSettings.BootBehavior.entries.size).map { index -> - val locale = locales[index]!! - + }.toList() + listOf( ListOption( - titleText = locale.displayName, - subtitleText = locale.getDisplayName(Locale.ENGLISH), + titleText = stringResource(R.string.ui_settings_bootBehavior_values_nothing_title), ) - }.toList(), + ), positiveButton = SelectionButton( icon = IconSource( painter = IconResource.fromImageVector(Icons.Default.CheckCircle) @@ -75,11 +100,8 @@ fun BootBehaviorTile() { type = ButtonStyle.TEXT, ) ) { index, _ -> - AppCompatDelegate.setApplicationLocales( - LocaleListCompat.forLanguageTags( - locales[index]!!.toLanguageTag(), - ), - ) + val behavior = AppSettings.BootBehavior.values().getOrNull(index) + updateValue(behavior) }, ) SettingsTile( @@ -89,6 +111,9 @@ fun BootBehaviorTile() { showDialog.show() }, title = stringResource(R.string.ui_settings_bootBehavior_title), + description = stringResource( + BOOT_BEHAVIOR_TITLE_MAP[settings.bootBehavior] ?: R.string.ui_settings_bootBehavior_help + ), leading = { Icon( Icons.Default.Smartphone, @@ -97,5 +122,3 @@ fun BootBehaviorTile() { }, ) } - - */ \ No newline at end of file diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/SettingsScreen.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/SettingsScreen.kt index 0a1b4f96d..f28bafa2a 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/screens/SettingsScreen.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/SettingsScreen.kt @@ -41,6 +41,7 @@ import app.myzel394.alibi.db.AppSettings import app.myzel394.alibi.ui.SUPPORTS_DARK_MODE_NATIVELY import app.myzel394.alibi.ui.components.SettingsScreen.atoms.AboutTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.BitrateTile +import app.myzel394.alibi.ui.components.SettingsScreen.atoms.BootBehaviorTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.CustomNotificationTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.DeleteRecordingsImmediatelyTile import app.myzel394.alibi.ui.components.SettingsScreen.atoms.EncoderTile @@ -149,6 +150,7 @@ fun SettingsScreen( InAppLanguagePicker() DeleteRecordingsImmediatelyTile(settings = settings) CustomNotificationTile(navController = navController, settings = settings) + BootBehaviorTile(settings = settings) AboutTile(navController = navController) AnimatedVisibility(visible = settings.showAdvancedSettings) { Column( diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f33ccf0f7..c1db6e521 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -115,4 +115,11 @@ If enabled, you\'ll be informed that your recording was interrupted Alibi was interrupted Your device restarted and your recording has been interrupted + Always start recording + Continue recording + Show a notification if recording has been interrupted + Continue recording, if interrupted, otherwise start a new recording + If recording has been interrupted, continue it + Do nothing + What should Alibi do when your phone boots up? \ No newline at end of file From eeaeb52fb0c0e7087c05d6961c1d05e63783ea0c Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sat, 28 Oct 2023 18:41:29 +0200 Subject: [PATCH 06/11] feat: Set default boot behavior to CONTINUE_RECORDING --- app/src/main/java/app/myzel394/alibi/db/AppSettings.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt index ffec8cb18..328f73841 100644 --- a/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt +++ b/app/src/main/java/app/myzel394/alibi/db/AppSettings.kt @@ -19,7 +19,7 @@ data class AppSettings( val showAdvancedSettings: Boolean = false, val theme: Theme = Theme.SYSTEM, val lastRecording: RecordingInformation? = null, - val bootBehavior: BootBehavior? = BootBehavior.START_RECORDING, + val bootBehavior: BootBehavior? = BootBehavior.CONTINUE_RECORDING, ) { fun setShowAdvancedSettings(showAdvancedSettings: Boolean): AppSettings { return copy(showAdvancedSettings = showAdvancedSettings) From 536271109bb17b9ee26e18580ede8342a1006389 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sun, 29 Oct 2023 11:17:44 +0100 Subject: [PATCH 07/11] feat: Fetch duration on recording start --- .../alibi/services/IntervalRecorderService.kt | 25 +++++++++++++++++++ .../alibi/services/RecorderService.kt | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt index df06b018e..56183f9b6 100644 --- a/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/IntervalRecorderService.kt @@ -1,5 +1,6 @@ package app.myzel394.alibi.services +import android.media.MediaMetadataRetriever import android.media.MediaRecorder import app.myzel394.alibi.dataStore import app.myzel394.alibi.db.AudioRecorderSettings @@ -68,11 +69,35 @@ abstract class IntervalRecorderService : ExtraRecorderInformationService() { counter = files.size } + private fun fetchRecordingTime() { + var oldAmount = 0L + + for (file in outputFolder.listFiles() ?: emptyArray()) { + if (file.nameWithoutExtension.toIntOrNull() == null) { + continue + } + + // It's better to at least get an approximate value, than to crash + runCatching { + val amount = MediaMetadataRetriever().run { + setDataSource(file.absolutePath) + extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toIntOrNull() + ?: 0 + } + + oldAmount += amount + } + } + + recordingTime = oldAmount + } + override fun start() { super.start() outputFolder.mkdirs() fetchCounterValue() + fetchRecordingTime() scope.launch { dataStore.data.collectLatest { preferenceSettings -> diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt index 60675d400..b5fa25bbe 100644 --- a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt @@ -34,7 +34,7 @@ abstract class RecorderService : Service() { var onStateChange: ((RecorderState) -> Unit)? = null var recordingTime = 0L - private set + protected set private lateinit var recordingTimeTimer: ScheduledExecutorService var onRecordingTimeChange: ((Long) -> Unit)? = null var notificationDetails: RecorderNotificationHelper.NotificationDetails? = null From 968c3cc32cade2af2504c8e2f86095e775d93d2e Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sun, 29 Oct 2023 11:40:08 +0100 Subject: [PATCH 08/11] fix: Recorder start fixes --- .../ui/components/AudioRecorder/molecules/StartRecording.kt | 4 ++++ .../java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt | 1 + 2 files changed, 5 insertions(+) diff --git a/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/molecules/StartRecording.kt b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/molecules/StartRecording.kt index 72f2f42e5..4111fca7d 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/molecules/StartRecording.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/components/AudioRecorder/molecules/StartRecording.kt @@ -82,6 +82,10 @@ fun StartRecording( ) } + runCatching { + audioRecorder.stopRecording(context) + } + AudioRecorderExporter.clearAllRecordings(context) audioRecorder.startRecording(context) diff --git a/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt b/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt index ce3cff6d5..687a29fdc 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/screens/AudioRecorderScreen.kt @@ -94,6 +94,7 @@ fun AudioRecorderScreen( delay(100) try { + audioRecorder.stopRecording(context) val file = AudioRecorderExporter( audioRecorder.recorderService?.getRecordingInformation() ?: settings.lastRecording From 3df34b4ad01424ca13ea3cc9fc1c4482f8fe0244 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sun, 29 Oct 2023 12:22:08 +0100 Subject: [PATCH 09/11] chore: Update dependencies --- app/build.gradle | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d3c9db3f1..4a15fd50e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -6,7 +6,7 @@ plugins { android { namespace 'app.myzel394.alibi' - compileSdk 34 + compileSdk 33 def keystoreProperties = new Properties() def keystorePropertiesFile = rootProject.file('key.properties') @@ -34,7 +34,7 @@ android { multiDexEnabled true applicationId "app.myzel394.alibi" minSdk 24 - targetSdk 34 + targetSdk 33 versionCode 7 versionName "0.3.0" @@ -94,13 +94,13 @@ dependencies { implementation 'androidx.core:core-ktx:1.12.0' implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0') implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2' - implementation 'androidx.activity:activity-compose:1.7.2' + implementation 'androidx.activity:activity-compose:1.8.0' implementation platform('androidx.compose:compose-bom:2022.10.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.compose.material:material-icons-extended:1.5.1" + implementation "androidx.compose.material:material-icons-extended:1.5.4" implementation 'androidx.appcompat:appcompat:1.6.1' testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.5' @@ -110,7 +110,7 @@ dependencies { debugImplementation 'androidx.compose.ui:ui-tooling' debugImplementation 'androidx.compose.ui:ui-test-manifest' - implementation "androidx.navigation:navigation-compose:2.7.2" + implementation "androidx.navigation:navigation-compose:2.7.4" implementation 'com.google.dagger:hilt-android:2.46.1' annotationProcessor 'com.google.dagger:hilt-compiler:2.46.1' From 2c5665fa49cc83cce7cbf29027c2387e5878bc83 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sun, 29 Oct 2023 13:09:41 +0100 Subject: [PATCH 10/11] fix: Decreasing version because of https://issuetracker.google.com/issues/299506164 --- app/build.gradle | 13 ++++++-- .../alibi/services/RecorderService.kt | 26 ++++++++++------ .../java/app/myzel394/alibi/ui/Navigation.kt | 31 ------------------- .../alibi/ui/utils/available-microphones.kt | 3 ++ 4 files changed, 29 insertions(+), 44 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4a15fd50e..b5d105696 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,6 +42,13 @@ android { vectorDrawables { useSupportLibrary true } + + configurations.all { + resolutionStrategy { + force("androidx.emoji2:emoji2-views-helper:1.3.0") + force("androidx.emoji2:emoji2:1.3.0") + } + } } signingConfigs { @@ -91,10 +98,10 @@ android { } dependencies { - implementation 'androidx.core:core-ktx:1.12.0' + implementation 'androidx.core:core-ktx:1.10.0' implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0') implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2' - implementation 'androidx.activity:activity-compose:1.8.0' + implementation 'androidx.activity:activity-compose:1.0.0' implementation platform('androidx.compose:compose-bom:2022.10.00') implementation 'androidx.compose.ui:ui' implementation 'androidx.compose.ui:ui-graphics' @@ -110,7 +117,7 @@ dependencies { debugImplementation 'androidx.compose.ui:ui-tooling' debugImplementation 'androidx.compose.ui:ui-test-manifest' - implementation "androidx.navigation:navigation-compose:2.7.4" + implementation "androidx.navigation:navigation-compose:2.5.0" implementation 'com.google.dagger:hilt-android:2.46.1' annotationProcessor 'com.google.dagger:hilt-compiler:2.46.1' diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt index b5fa25bbe..b3cd09a49 100644 --- a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt @@ -146,16 +146,22 @@ abstract class RecorderService : Service() { fun startRecording() { recordingStart = LocalDateTime.now() - ServiceCompat.startForeground( - this, - NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, - getNotificationHelper().buildStartingNotification(), - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE - } else { - 0 - }, - ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + startForeground( + NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, + getNotificationHelper().buildStartingNotification(), + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE + } else { + 0 + }, + ) + } else { + startForeground( + NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, + getNotificationHelper().buildStartingNotification(), + ) + } // Start changeState(RecorderState.RECORDING) 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 985e79d56..f55e4acf2 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt @@ -60,15 +60,6 @@ fun Navigation( } composable( Screen.AudioRecorder.route, - enterTransition = { - when (initialState.destination.route) { - Screen.Welcome.route -> null - else -> scaleIn(initialScale = SCALE_IN) + fadeIn() - } - }, - exitTransition = { - scaleOut(targetScale = SCALE_IN) + fadeOut(tween(durationMillis = 150)) - } ) { AudioRecorderScreen( navController = navController, @@ -77,12 +68,6 @@ fun Navigation( } composable( Screen.Settings.route, - enterTransition = { - scaleIn(initialScale = 1 / SCALE_IN) + fadeIn() - }, - exitTransition = { - scaleOut(targetScale = 1 / SCALE_IN) + fadeOut(tween(durationMillis = 150)) - } ) { SettingsScreen( navController = navController, @@ -91,16 +76,6 @@ fun Navigation( } composable( Screen.CustomRecordingNotifications.route, - enterTransition = { - slideInHorizontally( - initialOffsetX = { it -> it / 2 } - ) + fadeIn() - }, - exitTransition = { - slideOutHorizontally( - targetOffsetX = { it -> it / 2 } - ) + fadeOut(tween(150)) - } ) { CustomRecordingNotificationsScreen( navController = navController, @@ -108,12 +83,6 @@ fun Navigation( } composable( Screen.About.route, - enterTransition = { - scaleIn() - }, - exitTransition = { - scaleOut() + fadeOut(tween(150)) - } ) { AboutScreen( navController = navController, diff --git a/app/src/main/java/app/myzel394/alibi/ui/utils/available-microphones.kt b/app/src/main/java/app/myzel394/alibi/ui/utils/available-microphones.kt index c36c91bf5..2a435ddd7 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/utils/available-microphones.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/utils/available-microphones.kt @@ -16,10 +16,13 @@ val ALLOWED_MICROPHONE_TYPES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES, AudioDeviceInfo.TYPE_IP, AudioDeviceInfo.TYPE_DOCK, + /* + Currently unavailable due to targetSDK 33 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { AudioDeviceInfo.TYPE_DOCK_ANALOG } else { }, + */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { AudioDeviceInfo.TYPE_BLE_HEADSET } else { From c340bab9a8d5433228b282c4450a78f8a4812d43 Mon Sep 17 00:00:00 2001 From: Myzel394 <50424412+Myzel394@users.noreply.github.com> Date: Sun, 29 Oct 2023 13:09:41 +0100 Subject: [PATCH 11/11] fix: Decreasing version because of bug --- app/build.gradle | 13 ++++++-- .../alibi/services/RecorderService.kt | 26 ++++++++++------ .../java/app/myzel394/alibi/ui/Navigation.kt | 31 ------------------- .../alibi/ui/utils/available-microphones.kt | 3 ++ 4 files changed, 29 insertions(+), 44 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 4a15fd50e..b5d105696 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -42,6 +42,13 @@ android { vectorDrawables { useSupportLibrary true } + + configurations.all { + resolutionStrategy { + force("androidx.emoji2:emoji2-views-helper:1.3.0") + force("androidx.emoji2:emoji2:1.3.0") + } + } } signingConfigs { @@ -91,10 +98,10 @@ android { } dependencies { - implementation 'androidx.core:core-ktx:1.12.0' + implementation 'androidx.core:core-ktx:1.10.0' implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0') implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.2' - implementation 'androidx.activity:activity-compose:1.8.0' + implementation 'androidx.activity:activity-compose:1.0.0' implementation platform('androidx.compose:compose-bom:2022.10.00') implementation 'androidx.compose.ui:ui' implementation 'androidx.compose.ui:ui-graphics' @@ -110,7 +117,7 @@ dependencies { debugImplementation 'androidx.compose.ui:ui-tooling' debugImplementation 'androidx.compose.ui:ui-test-manifest' - implementation "androidx.navigation:navigation-compose:2.7.4" + implementation "androidx.navigation:navigation-compose:2.5.0" implementation 'com.google.dagger:hilt-android:2.46.1' annotationProcessor 'com.google.dagger:hilt-compiler:2.46.1' diff --git a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt index b5fa25bbe..b3cd09a49 100644 --- a/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt +++ b/app/src/main/java/app/myzel394/alibi/services/RecorderService.kt @@ -146,16 +146,22 @@ abstract class RecorderService : Service() { fun startRecording() { recordingStart = LocalDateTime.now() - ServiceCompat.startForeground( - this, - NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, - getNotificationHelper().buildStartingNotification(), - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE - } else { - 0 - }, - ) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + startForeground( + NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, + getNotificationHelper().buildStartingNotification(), + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE + } else { + 0 + }, + ) + } else { + startForeground( + NotificationHelper.RECORDER_CHANNEL_NOTIFICATION_ID, + getNotificationHelper().buildStartingNotification(), + ) + } // Start changeState(RecorderState.RECORDING) 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 985e79d56..f55e4acf2 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/Navigation.kt @@ -60,15 +60,6 @@ fun Navigation( } composable( Screen.AudioRecorder.route, - enterTransition = { - when (initialState.destination.route) { - Screen.Welcome.route -> null - else -> scaleIn(initialScale = SCALE_IN) + fadeIn() - } - }, - exitTransition = { - scaleOut(targetScale = SCALE_IN) + fadeOut(tween(durationMillis = 150)) - } ) { AudioRecorderScreen( navController = navController, @@ -77,12 +68,6 @@ fun Navigation( } composable( Screen.Settings.route, - enterTransition = { - scaleIn(initialScale = 1 / SCALE_IN) + fadeIn() - }, - exitTransition = { - scaleOut(targetScale = 1 / SCALE_IN) + fadeOut(tween(durationMillis = 150)) - } ) { SettingsScreen( navController = navController, @@ -91,16 +76,6 @@ fun Navigation( } composable( Screen.CustomRecordingNotifications.route, - enterTransition = { - slideInHorizontally( - initialOffsetX = { it -> it / 2 } - ) + fadeIn() - }, - exitTransition = { - slideOutHorizontally( - targetOffsetX = { it -> it / 2 } - ) + fadeOut(tween(150)) - } ) { CustomRecordingNotificationsScreen( navController = navController, @@ -108,12 +83,6 @@ fun Navigation( } composable( Screen.About.route, - enterTransition = { - scaleIn() - }, - exitTransition = { - scaleOut() + fadeOut(tween(150)) - } ) { AboutScreen( navController = navController, diff --git a/app/src/main/java/app/myzel394/alibi/ui/utils/available-microphones.kt b/app/src/main/java/app/myzel394/alibi/ui/utils/available-microphones.kt index c36c91bf5..2a435ddd7 100644 --- a/app/src/main/java/app/myzel394/alibi/ui/utils/available-microphones.kt +++ b/app/src/main/java/app/myzel394/alibi/ui/utils/available-microphones.kt @@ -16,10 +16,13 @@ val ALLOWED_MICROPHONE_TYPES = AudioDeviceInfo.TYPE_WIRED_HEADPHONES, AudioDeviceInfo.TYPE_IP, AudioDeviceInfo.TYPE_DOCK, + /* + Currently unavailable due to targetSDK 33 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { AudioDeviceInfo.TYPE_DOCK_ANALOG } else { }, + */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { AudioDeviceInfo.TYPE_BLE_HEADSET } else {