Use coroutines in notification manager

pull/1055/head
Alex Baker 4 years ago
parent 0a1a1d870d
commit 9cd9f1ada2

@ -55,7 +55,7 @@ class GeofenceTransitionsIntentService : InjectingJobIntentService() {
} }
geofences geofences
.map { toNotification(place, it, arrival) } .map { toNotification(place, it, arrival) }
.apply(notifier::triggerNotifications) .let { notifier.triggerNotifications(it) }
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Error triggering geofence %s: %s", requestId, e.message) Timber.e(e, "Error triggering geofence %s: %s", requestId, e.message)
} }

@ -170,18 +170,6 @@ public class AndroidUtilities {
return Thread.currentThread() == Looper.getMainLooper().getThread(); return Thread.currentThread() == Looper.getMainLooper().getThread();
} }
/**
* Sleep, ignoring interruption. Before using this method, think carefully about why you are
* ignoring interruptions.
*/
public static void sleepDeep(long l) {
try {
Thread.sleep(l);
} catch (InterruptedException e) {
// ignore
}
}
/** Capitalize the first character */ /** Capitalize the first character */
public static String capitalize(String string) { public static String capitalize(String string) {
return string.substring(0, 1).toUpperCase() + string.substring(1); return string.substring(0, 1).toUpperCase() + string.substring(1);

@ -173,7 +173,9 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener {
} }
}) })
if (!model.isNew) { if (!model.isNew) {
lifecycleScope.launch {
notificationManager.cancel(model.id) notificationManager.cancel(model.id)
}
if (preferences.getBoolean(R.string.p_linkify_task_edit, false)) { if (preferences.getBoolean(R.string.p_linkify_task_edit, false)) {
linkify.linkify(title) linkify.linkify(title)
} }

@ -28,10 +28,6 @@ class TaskDaoBlocking @Inject constructor(private val dao: TaskDao) {
dao.activeTimers() dao.activeTimers()
} }
fun activeNotifications(): List<Task> = runBlocking {
dao.activeNotifications()
}
fun snooze(taskIds: List<Long>, millis: Long) = runBlocking { fun snooze(taskIds: List<Long>, millis: Long) = runBlocking {
dao.snooze(taskIds, millis) dao.snooze(taskIds, millis)
} }

@ -3,12 +3,12 @@ package org.tasks
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Context import android.content.Context
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import com.todoroo.andlib.utility.AndroidUtilities
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.reminders.ReminderService import com.todoroo.astrid.reminders.ReminderService
import com.todoroo.astrid.voice.VoiceOutputAssistant import com.todoroo.astrid.voice.VoiceOutputAssistant
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.delay
import org.tasks.intents.TaskIntents import org.tasks.intents.TaskIntents
import org.tasks.notifications.AudioManager import org.tasks.notifications.AudioManager
import org.tasks.notifications.Notification import org.tasks.notifications.Notification
@ -24,7 +24,7 @@ import kotlin.math.min
class Notifier @Inject constructor( class Notifier @Inject constructor(
@param:ApplicationContext private val context: Context, @param:ApplicationContext private val context: Context,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val notificationManager: NotificationManager, private val notificationManager: NotificationManager,
private val telephonyManager: TelephonyManager, private val telephonyManager: TelephonyManager,
private val audioManager: AudioManager, private val audioManager: AudioManager,
@ -33,7 +33,7 @@ class Notifier @Inject constructor(
private val colorProvider: ColorProvider = ColorProvider(context, preferences) private val colorProvider: ColorProvider = ColorProvider(context, preferences)
fun triggerFilterNotification(filter: Filter) { suspend fun triggerFilterNotification(filter: Filter) {
val tasks = taskDao.fetchFiltered(filter) val tasks = taskDao.fetchFiltered(filter)
val count = tasks.size val count = tasks.size
if (count == 0) { if (count == 0) {
@ -66,12 +66,12 @@ class Notifier @Inject constructor(
notificationManager.notify(filter.listingTitle.hashCode().toLong(), builder, true, false, false) notificationManager.notify(filter.listingTitle.hashCode().toLong(), builder, true, false, false)
} }
fun triggerNotifications(entries: List<Notification>) { suspend fun triggerNotifications(entries: List<Notification>) {
val notifications: MutableList<Notification> = ArrayList() val notifications: MutableList<Notification> = ArrayList()
var ringFiveTimes = false var ringFiveTimes = false
var ringNonstop = false var ringNonstop = false
for (entry in entries.takeLast(NotificationManager.MAX_NOTIFICATIONS)) { for (entry in entries.takeLast(NotificationManager.MAX_NOTIFICATIONS)) {
val task = taskDao.fetchBlocking(entry.taskId) ?: continue val task = taskDao.fetch(entry.taskId) ?: continue
if (entry.type != ReminderService.TYPE_RANDOM) { if (entry.type != ReminderService.TYPE_RANDOM) {
ringFiveTimes = ringFiveTimes or task.isNotifyModeFive ringFiveTimes = ringFiveTimes or task.isNotifyModeFive
ringNonstop = ringNonstop or task.isNotifyModeNonstop ringNonstop = ringNonstop or task.isNotifyModeNonstop
@ -85,7 +85,7 @@ class Notifier @Inject constructor(
return return
} }
Timber.d("Triggering %s", notifications) Timber.d("Triggering $notifications")
notificationManager.notifyTasks(notifications, true, ringNonstop, ringFiveTimes) notificationManager.notifyTasks(notifications, true, ringNonstop, ringFiveTimes)
@ -98,7 +98,7 @@ class Notifier @Inject constructor(
notificationManager.getTaskNotification(it)?.build()?.tickerText?.toString() notificationManager.getTaskNotification(it)?.build()?.tickerText?.toString()
} }
.forEach { .forEach {
AndroidUtilities.sleepDeep(2000) delay(2000)
voiceOutputAssistant.speak(it) voiceOutputAssistant.speak(it)
} }
} }

@ -3,6 +3,7 @@ package org.tasks.notifications
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.runBlocking
import org.tasks.injection.InjectingBroadcastReceiver import org.tasks.injection.InjectingBroadcastReceiver
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
@ -15,6 +16,8 @@ class NotificationClearedReceiver : InjectingBroadcastReceiver() {
super.onReceive(context, intent) super.onReceive(context, intent)
val notificationId = intent.getLongExtra(NotificationManager.EXTRA_NOTIFICATION_ID, -1L) val notificationId = intent.getLongExtra(NotificationManager.EXTRA_NOTIFICATION_ID, -1L)
Timber.d("cleared $notificationId") Timber.d("cleared $notificationId")
runBlocking {
notificationManager.cancel(notificationId) notificationManager.cancel(notificationId)
} }
}
} }

@ -11,18 +11,14 @@ import com.todoroo.andlib.sql.QueryTemplate
import com.todoroo.andlib.utility.AndroidUtilities import com.todoroo.andlib.utility.AndroidUtilities
import com.todoroo.andlib.utility.DateUtilities import com.todoroo.andlib.utility.DateUtilities
import com.todoroo.astrid.api.Filter import com.todoroo.astrid.api.Filter
import com.todoroo.astrid.dao.TaskDaoBlocking import com.todoroo.astrid.dao.TaskDao
import com.todoroo.astrid.data.Task import com.todoroo.astrid.data.Task
import com.todoroo.astrid.reminders.ReminderService import com.todoroo.astrid.reminders.ReminderService
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import io.reactivex.Completable
import io.reactivex.Single
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import org.tasks.LocalBroadcastManager import org.tasks.LocalBroadcastManager
import org.tasks.R import org.tasks.R
import org.tasks.Strings.isNullOrEmpty import org.tasks.Strings.isNullOrEmpty
import org.tasks.data.LocationDaoBlocking import org.tasks.data.LocationDao
import org.tasks.intents.TaskIntents import org.tasks.intents.TaskIntents
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
import org.tasks.receivers.CompleteTaskReceiver import org.tasks.receivers.CompleteTaskReceiver
@ -41,9 +37,9 @@ import kotlin.math.min
class NotificationManager @Inject constructor( class NotificationManager @Inject constructor(
@param:ApplicationContext private val context: Context, @param:ApplicationContext private val context: Context,
private val preferences: Preferences, private val preferences: Preferences,
private val notificationDao: NotificationDaoBlocking, private val notificationDao: NotificationDao,
private val taskDao: TaskDaoBlocking, private val taskDao: TaskDao,
private val locationDao: LocationDaoBlocking, private val locationDao: LocationDao,
private val localBroadcastManager: LocalBroadcastManager) { private val localBroadcastManager: LocalBroadcastManager) {
private val notificationManagerCompat = NotificationManagerCompat.from(context) private val notificationManagerCompat = NotificationManagerCompat.from(context)
private val colorProvider = ColorProvider(context, preferences) private val colorProvider = ColorProvider(context, preferences)
@ -51,35 +47,25 @@ class NotificationManager @Inject constructor(
private val queue = NotificationLimiter(MAX_NOTIFICATIONS) private val queue = NotificationLimiter(MAX_NOTIFICATIONS)
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
fun cancel(id: Long) { suspend fun cancel(id: Long) {
if (id == SUMMARY_NOTIFICATION_ID.toLong()) { if (id == SUMMARY_NOTIFICATION_ID.toLong()) {
Single.fromCallable { notificationDao.getAll() + id } cancel(notificationDao.getAll() + id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { ids: Iterable<Long> -> this.cancel(ids) }
} else { } else {
cancel(listOf(id)) cancel(listOf(id))
} }
} }
@SuppressLint("CheckResult") @SuppressLint("CheckResult")
fun cancel(ids: Iterable<Long>) { suspend fun cancel(ids: Iterable<Long>) {
for (id in ids) { for (id in ids) {
notificationManagerCompat.cancel(id.toInt()) notificationManagerCompat.cancel(id.toInt())
queue.remove(id) queue.remove(id)
} }
Completable.fromAction { notificationDao.deleteAll(ids.toList()) } notificationDao.deleteAll(ids.toList())
.subscribeOn(Schedulers.io()) notifyTasks(emptyList(), alert = false, nonstop = false, fiveTimes = false)
.subscribe {
notifyTasks(
emptyList(),
alert = false,
nonstop = false,
fiveTimes = false)
}
} }
fun restoreNotifications(cancelExisting: Boolean) { suspend fun restoreNotifications(cancelExisting: Boolean) {
val notifications = notificationDao.getAllOrdered() val notifications = notificationDao.getAllOrdered()
if (cancelExisting) { if (cancelExisting) {
for (notification in notifications) { for (notification in notifications) {
@ -109,8 +95,11 @@ class NotificationManager @Inject constructor(
} }
} }
fun notifyTasks( suspend fun notifyTasks(
newNotifications: List<Notification>, alert: Boolean, nonstop: Boolean, fiveTimes: Boolean) { newNotifications: List<Notification>,
alert: Boolean,
nonstop: Boolean,
fiveTimes: Boolean) {
val existingNotifications = notificationDao.getAllOrdered() val existingNotifications = notificationDao.getAllOrdered()
notificationDao.insertAll(newNotifications) notificationDao.insertAll(newNotifications)
val totalCount = existingNotifications.size + newNotifications.size val totalCount = existingNotifications.size + newNotifications.size
@ -151,7 +140,7 @@ class NotificationManager @Inject constructor(
localBroadcastManager.broadcastRefresh() localBroadcastManager.broadcastRefresh()
} }
private fun createNotifications( private suspend fun createNotifications(
notifications: List<Notification>, notifications: List<Notification>,
alert: Boolean, alert: Boolean,
nonstop: Boolean, nonstop: Boolean,
@ -166,7 +155,7 @@ class NotificationManager @Inject constructor(
} else { } else {
builder builder
.setGroup( .setGroup(
if (useGroupKey) GROUP_KEY else if (AndroidUtilities.atLeastNougat()) java.lang.Long.toString(notification.taskId) else null) if (useGroupKey) GROUP_KEY else if (AndroidUtilities.atLeastNougat()) notification.taskId.toString() else null)
.setGroupAlertBehavior( .setGroupAlertBehavior(
if (alert) NotificationCompat.GROUP_ALERT_CHILDREN else NotificationCompat.GROUP_ALERT_SUMMARY) if (alert) NotificationCompat.GROUP_ALERT_CHILDREN else NotificationCompat.GROUP_ALERT_SUMMARY)
notify(notification.taskId, builder, alert, nonstop, fiveTimes) notify(notification.taskId, builder, alert, nonstop, fiveTimes)
@ -175,7 +164,7 @@ class NotificationManager @Inject constructor(
} }
} }
fun notify( suspend fun notify(
notificationId: Long, notificationId: Long,
builder: NotificationCompat.Builder, builder: NotificationCompat.Builder,
alert: Boolean, alert: Boolean,
@ -217,7 +206,7 @@ class NotificationManager @Inject constructor(
} }
} }
private fun updateSummary( private suspend fun updateSummary(
notify: Boolean, nonStop: Boolean, fiveTimes: Boolean, newNotifications: List<Notification>) { notify: Boolean, nonStop: Boolean, fiveTimes: Boolean, newNotifications: List<Notification>) {
val tasks = taskDao.activeNotifications() val tasks = taskDao.activeNotifications()
val taskCount = tasks.size val taskCount = tasks.size
@ -275,11 +264,11 @@ class NotificationManager @Inject constructor(
notify(SUMMARY_NOTIFICATION_ID.toLong(), builder, notify, nonStop, fiveTimes) notify(SUMMARY_NOTIFICATION_ID.toLong(), builder, notify, nonStop, fiveTimes)
} }
fun getTaskNotification(notification: Notification): NotificationCompat.Builder? { suspend fun getTaskNotification(notification: Notification): NotificationCompat.Builder? {
val id = notification.taskId val id = notification.taskId
val type = notification.type val type = notification.type
val `when` = notification.timestamp val `when` = notification.timestamp
val task = taskDao.fetchBlocking(id) val task = taskDao.fetch(id)
if (task == null) { if (task == null) {
Timber.e("Could not find %s", id) Timber.e("Could not find %s", id)
return null return null

Loading…
Cancel
Save