Skip to content

Commit

Permalink
Fixes
Browse files Browse the repository at this point in the history
- Fix #118: App List filter not cleared when closing search
- Fix crash when updating NotificationInfo already pushed off list
- Fix crash when tts is unexpectedly null
- Prevent lateinit crash when accessing appContext
  • Loading branch information
pilot51 committed Jan 7, 2024
1 parent 1e4d5c8 commit 734f916
Show file tree
Hide file tree
Showing 6 changed files with 40 additions and 44 deletions.
10 changes: 6 additions & 4 deletions app/src/main/java/com/pilot51/voicenotify/AppDatabase.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,9 +89,11 @@ abstract class AppDatabase : RoomDatabase() {
}

companion object {
val db = Room.databaseBuilder(
VNApplication.appContext,
AppDatabase::class.java, "apps.db"
).build()
val db by lazy {
Room.databaseBuilder(
VNApplication.appContext,
AppDatabase::class.java, "apps.db"
).build()
}
}
}
2 changes: 2 additions & 0 deletions app/src/main/java/com/pilot51/voicenotify/AppListScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ fun AppListActions() {
trailingIcon = {
IconButton(onClick = {
showSearchBar = false
vm.searchQuery = null
vm.filterApps(null)
}) {
Icon(
imageVector = Icons.Filled.Close,
Expand Down
7 changes: 4 additions & 3 deletions app/src/main/java/com/pilot51/voicenotify/AppListViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,24 +15,25 @@
*/
package com.pilot51.voicenotify

import android.app.Application
import android.content.pm.PackageManager
import android.os.Build
import android.widget.Toast
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.compose.runtime.toMutableStateList
import androidx.lifecycle.ViewModel
import androidx.lifecycle.AndroidViewModel
import com.pilot51.voicenotify.AppListViewModel.IgnoreType.*
import com.pilot51.voicenotify.PreferenceHelper.KEY_APP_DEFAULT_ENABLE
import com.pilot51.voicenotify.PreferenceHelper.prefs
import com.pilot51.voicenotify.VNApplication.Companion.appContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.withLock

class AppListViewModel : ViewModel() {
class AppListViewModel(application: Application) : AndroidViewModel(application) {
private val appContext = application.applicationContext
private val apps by Common::apps
val filteredApps = apps.toMutableStateList()
private var isUpdating = false
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/pilot51/voicenotify/NotifyList.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ object NotifyList {
}

fun updateInfo(info: NotificationInfo) {
val index = list.indexOf(info)
val index = list.indexOf(info).takeUnless { it == -1 } ?: return
// Force update to list state by first setting copy
list[index] = info.copy()
// Set back to original to ensure future calls can find it again
Expand Down
57 changes: 24 additions & 33 deletions app/src/main/java/com/pilot51/voicenotify/Service.kt
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ import com.pilot51.voicenotify.PreferenceHelper.KEY_TTS_REPEAT
import com.pilot51.voicenotify.PreferenceHelper.getSelectedAudioStream
import com.pilot51.voicenotify.PreferenceHelper.prefs
import com.pilot51.voicenotify.Utils.isAny
import com.pilot51.voicenotify.VNApplication.Companion.appContext
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableStateFlow
Expand All @@ -88,7 +87,7 @@ class Service : NotificationListenerService() {
private lateinit var telephony: TelephonyManager
private val stateReceiver = DeviceStateReceiver()
private var repeater: RepeatTimer? = null
private val shake = Shake()
private val shake by lazy { Shake(applicationContext) }
private val repeatList = mutableListOf<NotificationInfo>()
private val audioFocusRequest = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
AudioFocusRequest.Builder(AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK)
Expand All @@ -107,17 +106,18 @@ class Service : NotificationListenerService() {
* if the list is empty when we enqueue a message, we trigger shaking and audio focus requesting
* if the list is empty when we finish speaking a message, we untrigger them.
*/
@SuppressLint("UseSparseArrays")
private val ttsQueue = linkedMapOf<Long, NotificationInfo>()
private val statusListener = object : OnStatusChangeListener {
override fun onStatusChanged() {
if (isSuspended.value && tts != null) {
synchronized(ttsQueue) {
for (info in ttsQueue.values) {
info.ignoreReasons.add(IgnoreReason.SUSPENDED)
if (isSuspended.value) {
tts?.run {
synchronized(ttsQueue) {
for (info in ttsQueue.values) {
info.ignoreReasons.add(IgnoreReason.SUSPENDED)
}
}
stop()
}
tts!!.stop()
}
}
}
Expand All @@ -138,7 +138,7 @@ class Service : NotificationListenerService() {
Toast.makeText(applicationContext, errorMsg, Toast.LENGTH_LONG).show()
return@OnInitListener
}
tts!!.setOnUtteranceProgressListener(object : UtteranceProgressListener() {
tts?.setOnUtteranceProgressListener(object : UtteranceProgressListener() {
override fun onStart(utteranceId: String) {}
override fun onStop(utteranceId: String, interrupted: Boolean) {
if (interrupted) {
Expand Down Expand Up @@ -193,7 +193,7 @@ class Service : NotificationListenerService() {
val queueIterator = ttsQueue.iterator()
queueIterator.forEach {
val info = it.value
val isFailed = tts!!.speak(
val isFailed = tts?.speak(
info.ttsMessage, TextToSpeech.QUEUE_ADD, ttsParams, it.key.toString()
) != TextToSpeech.SUCCESS
if (isFailed) {
Expand Down Expand Up @@ -337,7 +337,7 @@ class Service : NotificationListenerService() {
}
//once the message is in our queue, send it to the real one with the necessary parameters
val utteranceId = notificationTime.toString()
val isSpeakFailed = tts!!.speak(
val isSpeakFailed = tts?.speak(
info.ttsMessage, TextToSpeech.QUEUE_ADD, ttsParams, utteranceId
) != TextToSpeech.SUCCESS
if (isSpeakFailed) {
Expand Down Expand Up @@ -477,8 +477,8 @@ class Service : NotificationListenerService() {
}

private fun isScreenOn(): Boolean {
isScreenOn = CheckScreen.isScreenOn()
return isScreenOn
val powerMan = applicationContext.getSystemService(POWER_SERVICE) as PowerManager
return powerMan.isInteractive
}

@get:RequiresApi(Build.VERSION_CODES.M)
Expand Down Expand Up @@ -507,17 +507,6 @@ class Service : NotificationListenerService() {
}
}

private object CheckScreen {
private lateinit var powerMan: PowerManager

fun isScreenOn(): Boolean {
if (!::powerMan.isInitialized) {
powerMan = appContext.getSystemService(POWER_SERVICE) as PowerManager
}
return powerMan.isInteractive
}
}

private inner class DeviceStateReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
Expand All @@ -536,17 +525,19 @@ class Service : NotificationListenerService() {
interruptIfIgnored = false
}
}
if (interruptIfIgnored && tts != null) {
val ignoreReasons = ignore()
if (ignoreReasons.isNotEmpty()) {
Log.i(TAG, "Notifications silenced/ignored for reason(s): "
+ ignoreReasons.joinToString())
synchronized(ttsQueue) {
for (info in ttsQueue.values) {
info.ignoreReasons.addAll(ignoreReasons)
if (interruptIfIgnored) {
tts?.run {
val ignoreReasons = ignore()
if (ignoreReasons.isNotEmpty()) {
Log.i(TAG, "Notifications silenced/ignored for reason(s): "
+ ignoreReasons.joinToString())
synchronized(ttsQueue) {
for (info in ttsQueue.values) {
info.ignoreReasons.addAll(ignoreReasons)
}
}
stop()
}
tts!!.stop()
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/com/pilot51/voicenotify/Shake.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
*/
package com.pilot51.voicenotify

import android.content.Context
import android.content.Context.SENSOR_SERVICE
import android.hardware.Sensor
import android.hardware.SensorEvent
Expand All @@ -23,12 +24,11 @@ import android.hardware.SensorManager
import android.util.Log
import com.pilot51.voicenotify.PreferenceHelper.KEY_SHAKE_THRESHOLD
import com.pilot51.voicenotify.PreferenceHelper.prefs
import com.pilot51.voicenotify.VNApplication.Companion.appContext
import kotlin.math.abs
import kotlin.math.sqrt

class Shake : SensorEventListener {
private val manager = appContext.getSystemService(SENSOR_SERVICE) as SensorManager
class Shake(context: Context) : SensorEventListener {
private val manager = context.getSystemService(SENSOR_SERVICE) as SensorManager
private val sensor = manager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
var onShake: (() -> Unit)? = null
private var threshold = 0.0
Expand Down

0 comments on commit 734f916

Please sign in to comment.