Skip to content

Commit

Permalink
implemented stopping recording on low battery if set in settings (sti…
Browse files Browse the repository at this point in the history
…ll need to add notification)
  • Loading branch information
Leonidius20 committed Jul 30, 2024
1 parent 59ac9e4 commit 4d9ab7b
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,27 @@ import androidx.core.app.NotificationCompat
import androidx.core.app.ServiceCompat
import androidx.core.content.ContextCompat
import com.yashovardhan99.timeit.Stopwatch
import dagger.hilt.android.AndroidEntryPoint
import io.github.leonidius20.recorder.R
import io.github.leonidius20.recorder.data.settings.Settings
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.launch
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
import java.util.Locale
import javax.inject.Inject

// todo: refactor maybe, place audio-related stuff in separate class to separate from
// service-related stuff
@AndroidEntryPoint
class RecorderService : Service() {

enum class State {
Expand Down Expand Up @@ -70,13 +74,22 @@ class RecorderService : Service() {
/**
* emits max amplitude every 100ms. Used for audio visualization
*/
val amplitudes: SharedFlow<Int>
get() = _amplitudes

val amplitudes = _amplitudes.asSharedFlow()

private lateinit var stopwatch: Stopwatch

private lateinit var lowBatteryBroadcastReceiver: BroadcastReceiverWithCallback
//private lateinit var lowBatteryBroadcastReceiver: BroadcastReceiverWithCallback

@Inject
lateinit var settings: Settings

/**
* the launcher class responsible for starting this service.
* injected by RecorderServiceLauncher itself when starting.
* Needed so that we can notify the UI when the service is stopped
* by a broadcast receiver bc of low battery or storage
*/
var launcher: RecorderServiceLauncher? = null

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {

Expand Down Expand Up @@ -130,15 +143,23 @@ class RecorderService : Service() {
stopSelf()
}

lowBatteryBroadcastReceiver = BroadcastReceiverWithCallback(
callback = {
Log.d("REC SERVICE", "low battery")
if (settings.state.value.stopOnLowBattery) {
val lowBatteryBroadcastReceiver = BroadcastReceiverWithCallback(
callback = {


// todo: make notification with sound about the fact that the recording was auto-stopped


launcher!!.onServiceStopped() // update ui state
stop()
}
).apply {
val intentFilter = IntentFilter(Intent.ACTION_BATTERY_LOW)
ContextCompat.registerReceiver(
this@RecorderService, this,
intentFilter, ContextCompat.RECEIVER_EXPORTED)
}
).apply {
val intentFilter = IntentFilter(Intent.ACTION_BATTERY_LOW)
ContextCompat.registerReceiver(
this@RecorderService, this,
intentFilter, ContextCompat.RECEIVER_EXPORTED)
}

val dateFormat = SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.getDefault())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import androidx.core.content.ContextCompat
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -61,8 +61,7 @@ class RecorderServiceLauncher @Inject constructor(
* displaying it unsubscribes, and then the app goes into foreground again and the
* fragment resubscribes, the visualization reflects the newest samples.
*/
val amplitudes: SharedFlow<Int>
get() = _amplitudes
val amplitudes = _amplitudes.asSharedFlow()


/**
Expand Down Expand Up @@ -107,6 +106,8 @@ class RecorderServiceLauncher @Inject constructor(
) {
binder = service as RecorderService.Binder

binder!!.service.launcher = this

// serviceScope is cancelled when the service is destroyed
service.service.serviceScope.launch {
service.service.state.onEach {
Expand Down Expand Up @@ -137,4 +138,11 @@ class RecorderServiceLauncher @Inject constructor(
binder = null
}

/**
* called by service itself when it is stopped
*/
fun onServiceStopped() {
_state.value = State.IDLE
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package io.github.leonidius20.recorder.data.settings

import android.content.Context
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import androidx.preference.PreferenceManager
import dagger.hilt.android.qualifiers.ApplicationContext
import io.github.leonidius20.recorder.R
import kotlinx.coroutines.flow.MutableStateFlow
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class Settings @Inject constructor(
@ApplicationContext private val context: Context,
): OnSharedPreferenceChangeListener {

data class SettingsState(
val stopOnLowBattery: Boolean,
val stopOnLowStorage: Boolean,
val pauseOnCall: Boolean,
)

private val pref = PreferenceManager.getDefaultSharedPreferences(context)

val state = MutableStateFlow(getCurrentSettingsState())

init {
pref.registerOnSharedPreferenceChangeListener(this)
}

override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
state.value = getCurrentSettingsState()
}

private fun getCurrentSettingsState(): SettingsState {
return SettingsState(
stopOnLowBattery = pref.getBoolean(
context.getString(R.string.stop_on_low_battery_pref_key),
context.resources.getBoolean(R.bool.stop_on_low_battery_default)),
stopOnLowStorage = pref.getBoolean(
context.getString(R.string.stop_on_low_storage_pref_key),
context.resources.getBoolean(R.bool.stop_on_storage_default)),
pauseOnCall = pref.getBoolean(
context.getString(R.string.pause_on_call_pref_key),
context.resources.getBoolean(R.bool.pause_on_call_default)),
)
}


}
6 changes: 6 additions & 0 deletions app/src/main/res/values/default_settings.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<bool name="stop_on_low_battery_default">true</bool>
<bool name="stop_on_storage_default">true</bool>
<bool name="pause_on_call_default">false</bool>
</resources>
11 changes: 11 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,15 @@
<string name="recordings_list_action_share">Share</string>
<string name="recordings_list_choose_new_name">Type new name</string>
<string name="new_name">New name</string>
<string name="prefs_stop_recording_on_low_battery">Stop recording on low battery</string>
<string name="prefs_stop_recording_on_low_storage">Stop recording on low storage</string>
<string name="prefs_pause_recording_on_incoming_call">Pause recording on incoming call</string>
<string name="prefs_recording_control">Recording control</string>
<string name="prefs_about_app_legal_documents"><![CDATA[About app & legal documents]]></string>
<string name="prefs_github_repository">Github Repository</string>
<string name="prefs_github_repo_summary"><![CDATA[Report bugs, suggest improvements & view source code]]></string>

<string name="stop_on_low_battery_pref_key" translatable="false">pause_on_low_battery</string>
<string name="stop_on_low_storage_pref_key" translatable="false">pause_on_storage</string>
<string name="pause_on_call_pref_key" translatable="false">pause_on_call</string>
</resources>
26 changes: 13 additions & 13 deletions app/src/main/res/xml/preferences.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@

<PreferenceCategory
app:key="recording_control_category"
app:title="Recording control">
app:title="@string/prefs_recording_control">

<SwitchPreferenceCompat
app:key="pause_on_low_battery"
app:title="Pause recording on low battery"
app:defaultValue="true"/>
app:key="@string/stop_on_low_battery_pref_key"
app:title="@string/prefs_stop_recording_on_low_battery"
app:defaultValue="@bool/stop_on_low_battery_default"/>

<SwitchPreferenceCompat
app:key="pause_on_storage"
app:title="Pause recording on low storage"
app:defaultValue="true"/>
app:key="@string/stop_on_low_storage_pref_key"
app:title="@string/prefs_stop_recording_on_low_storage"
app:defaultValue="@bool/stop_on_storage_default"/>

<SwitchPreferenceCompat
app:key="pause_on_call"
app:title="Pause recording on incoming call"
app:defaultValue="false"/>
app:key="@string/pause_on_call_pref_key"
app:title="@string/prefs_pause_recording_on_incoming_call"
app:defaultValue="@bool/pause_on_call_default"/>

</PreferenceCategory>

<PreferenceCategory
app:key="about_app"
app:title="About app &amp; legal documents">
app:title="@string/prefs_about_app_legal_documents">

<Preference
app:key="github_repo"
app:title="Github Repository"
app:summary="Report bugs, suggest improvements &amp; view source code">
app:title="@string/prefs_github_repository"
app:summary="@string/prefs_github_repo_summary">

<intent
android:action="android.intent.action.VIEW"
Expand Down

0 comments on commit 4d9ab7b

Please sign in to comment.