mirror of
https://github.com/Myzel394/Alibi.git
synced 2025-06-19 07:15:25 +02:00
feat: Add boot notification
This commit is contained in:
parent
60fc16f2c4
commit
2e9f1c7ade
@ -9,18 +9,30 @@ import androidx.annotation.RequiresApi
|
|||||||
object NotificationHelper {
|
object NotificationHelper {
|
||||||
const val RECORDER_CHANNEL_ID = "recorder"
|
const val RECORDER_CHANNEL_ID = "recorder"
|
||||||
const val RECORDER_CHANNEL_NOTIFICATION_ID = 1
|
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)
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
fun createChannels(context: Context) {
|
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)
|
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)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -19,7 +19,7 @@ data class AppSettings(
|
|||||||
val showAdvancedSettings: Boolean = false,
|
val showAdvancedSettings: Boolean = false,
|
||||||
val theme: Theme = Theme.SYSTEM,
|
val theme: Theme = Theme.SYSTEM,
|
||||||
val lastRecording: RecordingInformation? = null,
|
val lastRecording: RecordingInformation? = null,
|
||||||
val bootBehavior: BootBehavior? = BootBehavior.START_RECORDING,
|
val bootBehavior: BootBehavior? = BootBehavior.SHOW_NOTIFICATION,
|
||||||
) {
|
) {
|
||||||
fun setShowAdvancedSettings(showAdvancedSettings: Boolean): AppSettings {
|
fun setShowAdvancedSettings(showAdvancedSettings: Boolean): AppSettings {
|
||||||
return copy(showAdvancedSettings = showAdvancedSettings)
|
return copy(showAdvancedSettings = showAdvancedSettings)
|
||||||
@ -56,7 +56,13 @@ data class AppSettings(
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum class BootBehavior {
|
enum class BootBehavior {
|
||||||
|
// Always start recording, no matter if it was interrupted or not
|
||||||
START_RECORDING,
|
START_RECORDING,
|
||||||
|
|
||||||
|
// Only start recording if it was interrupted
|
||||||
|
CONTINUE_RECORDING,
|
||||||
|
|
||||||
|
// Show a notification if interrupted
|
||||||
SHOW_NOTIFICATION,
|
SHOW_NOTIFICATION,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,42 +1,118 @@
|
|||||||
package app.myzel394.alibi.receivers
|
package app.myzel394.alibi.receivers
|
||||||
|
|
||||||
|
import android.app.NotificationManager
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.ComponentName
|
import android.content.ComponentName
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.ServiceConnection
|
import android.content.ServiceConnection
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
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.AudioRecorderService
|
||||||
|
import app.myzel394.alibi.services.RecorderNotificationHelper
|
||||||
import app.myzel394.alibi.services.RecorderService
|
import app.myzel394.alibi.services.RecorderService
|
||||||
import app.myzel394.alibi.ui.enums.Screen
|
import app.myzel394.alibi.ui.enums.Screen
|
||||||
import app.myzel394.alibi.ui.models.AudioRecorderModel
|
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() {
|
class BootReceiver : BroadcastReceiver() {
|
||||||
|
private var job = SupervisorJob()
|
||||||
|
private var scope = CoroutineScope(Dispatchers.IO + job)
|
||||||
|
|
||||||
|
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) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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?) {
|
override fun onReceive(context: Context?, intent: Intent?) {
|
||||||
println("Received new intent: ${intent?.action}")
|
if (intent?.action != Intent.ACTION_BOOT_COMPLETED || context == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (intent?.action == Intent.ACTION_BOOT_COMPLETED) {
|
scope.launch {
|
||||||
println("Starting service")
|
context.dataStore.data.collectLatest { settings ->
|
||||||
|
when (settings.bootBehavior) {
|
||||||
|
AppSettings.BootBehavior.CONTINUE_RECORDING -> {
|
||||||
|
if (AudioRecorderExporter.hasRecordingsAvailable(context)) {
|
||||||
|
startRecording(context, settings)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val connection = object : ServiceConnection {
|
AppSettings.BootBehavior.START_RECORDING -> startRecording(context, settings)
|
||||||
override fun onServiceConnected(className: ComponentName, service: IBinder) {
|
AppSettings.BootBehavior.SHOW_NOTIFICATION -> showNotification(context)
|
||||||
((service as RecorderService.RecorderBinder).getService() as AudioRecorderService).also { recorder ->
|
null -> {
|
||||||
recorder.startRecording()
|
// Nothing to do
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,7 +125,7 @@ class AudioRecorderModel : ViewModel() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ContextCompat.startForegroundService(context, intent)
|
ContextCompat.startForegroundService(context, intent)
|
||||||
context.bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
context.bindService(intent, connection, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun stopRecording(context: Context) {
|
fun stopRecording(context: Context) {
|
||||||
|
@ -111,4 +111,8 @@
|
|||||||
<string name="ui_settings_option_deleteRecordingsImmediately_description">If enabled, Alibi will immediately delete recordings after you have saved the file.</string>
|
<string name="ui_settings_option_deleteRecordingsImmediately_description">If enabled, Alibi will immediately delete recordings after you have saved the file.</string>
|
||||||
<string name="ui_settings_bootBehavior_title">Boot Behavior</string>
|
<string name="ui_settings_bootBehavior_title">Boot Behavior</string>
|
||||||
<string name="ui_settings_bootBehavior_values_SHOW_NOTIFICATION_title">Show a notification</string>
|
<string name="ui_settings_bootBehavior_values_SHOW_NOTIFICATION_title">Show a notification</string>
|
||||||
|
<string name="notificationChannels_boot_name">Boot notification</string>
|
||||||
|
<string name="notificationChannels_boot_description">If enabled, you\'ll be informed that your recording was interrupted</string>
|
||||||
|
<string name="notification_boot_title">Alibi was interrupted</string>
|
||||||
|
<string name="notification_boot_message">Your device restarted and your recording has been interrupted</string>
|
||||||
</resources>
|
</resources>
|
Loading…
x
Reference in New Issue
Block a user