diff --git a/app/src/googleplay/java/org/tasks/location/GeofenceTransitionsIntentService.kt b/app/src/googleplay/java/org/tasks/location/GeofenceTransitionsIntentService.kt index 1596cbf25..83b1ca74b 100644 --- a/app/src/googleplay/java/org/tasks/location/GeofenceTransitionsIntentService.kt +++ b/app/src/googleplay/java/org/tasks/location/GeofenceTransitionsIntentService.kt @@ -55,7 +55,7 @@ class GeofenceTransitionsIntentService : InjectingJobIntentService() { } geofences .map { toNotification(place, it, arrival) } - .apply(notifier::triggerNotifications) + .let { notifier.triggerNotifications(it) } } catch (e: Exception) { Timber.e(e, "Error triggering geofence %s: %s", requestId, e.message) } diff --git a/app/src/main/java/com/todoroo/andlib/utility/AndroidUtilities.java b/app/src/main/java/com/todoroo/andlib/utility/AndroidUtilities.java index 050ca75c3..3c3ddfd1e 100644 --- a/app/src/main/java/com/todoroo/andlib/utility/AndroidUtilities.java +++ b/app/src/main/java/com/todoroo/andlib/utility/AndroidUtilities.java @@ -170,18 +170,6 @@ public class AndroidUtilities { 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 */ public static String capitalize(String string) { return string.substring(0, 1).toUpperCase() + string.substring(1); diff --git a/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt b/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt index 063efe0ab..e2fc623f7 100755 --- a/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt +++ b/app/src/main/java/com/todoroo/astrid/activity/TaskEditFragment.kt @@ -173,7 +173,9 @@ class TaskEditFragment : Fragment(), Toolbar.OnMenuItemClickListener { } }) if (!model.isNew) { - notificationManager.cancel(model.id) + lifecycleScope.launch { + notificationManager.cancel(model.id) + } if (preferences.getBoolean(R.string.p_linkify_task_edit, false)) { linkify.linkify(title) } diff --git a/app/src/main/java/com/todoroo/astrid/dao/TaskDaoBlocking.kt b/app/src/main/java/com/todoroo/astrid/dao/TaskDaoBlocking.kt index f2d9006a1..23a5adc81 100644 --- a/app/src/main/java/com/todoroo/astrid/dao/TaskDaoBlocking.kt +++ b/app/src/main/java/com/todoroo/astrid/dao/TaskDaoBlocking.kt @@ -28,10 +28,6 @@ class TaskDaoBlocking @Inject constructor(private val dao: TaskDao) { dao.activeTimers() } - fun activeNotifications(): List = runBlocking { - dao.activeNotifications() - } - fun snooze(taskIds: List, millis: Long) = runBlocking { dao.snooze(taskIds, millis) } diff --git a/app/src/main/java/org/tasks/Notifier.kt b/app/src/main/java/org/tasks/Notifier.kt index df1ef593b..fe4f923f9 100644 --- a/app/src/main/java/org/tasks/Notifier.kt +++ b/app/src/main/java/org/tasks/Notifier.kt @@ -3,12 +3,12 @@ package org.tasks import android.app.PendingIntent import android.content.Context import androidx.core.app.NotificationCompat -import com.todoroo.andlib.utility.AndroidUtilities 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.voice.VoiceOutputAssistant import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.delay import org.tasks.intents.TaskIntents import org.tasks.notifications.AudioManager import org.tasks.notifications.Notification @@ -24,7 +24,7 @@ import kotlin.math.min class Notifier @Inject constructor( @param:ApplicationContext private val context: Context, - private val taskDao: TaskDaoBlocking, + private val taskDao: TaskDao, private val notificationManager: NotificationManager, private val telephonyManager: TelephonyManager, private val audioManager: AudioManager, @@ -33,7 +33,7 @@ class Notifier @Inject constructor( private val colorProvider: ColorProvider = ColorProvider(context, preferences) - fun triggerFilterNotification(filter: Filter) { + suspend fun triggerFilterNotification(filter: Filter) { val tasks = taskDao.fetchFiltered(filter) val count = tasks.size if (count == 0) { @@ -66,12 +66,12 @@ class Notifier @Inject constructor( notificationManager.notify(filter.listingTitle.hashCode().toLong(), builder, true, false, false) } - fun triggerNotifications(entries: List) { + suspend fun triggerNotifications(entries: List) { val notifications: MutableList = ArrayList() var ringFiveTimes = false var ringNonstop = false 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) { ringFiveTimes = ringFiveTimes or task.isNotifyModeFive ringNonstop = ringNonstop or task.isNotifyModeNonstop @@ -85,7 +85,7 @@ class Notifier @Inject constructor( return } - Timber.d("Triggering %s", notifications) + Timber.d("Triggering $notifications") notificationManager.notifyTasks(notifications, true, ringNonstop, ringFiveTimes) @@ -98,7 +98,7 @@ class Notifier @Inject constructor( notificationManager.getTaskNotification(it)?.build()?.tickerText?.toString() } .forEach { - AndroidUtilities.sleepDeep(2000) + delay(2000) voiceOutputAssistant.speak(it) } } diff --git a/app/src/main/java/org/tasks/notifications/NotificationClearedReceiver.kt b/app/src/main/java/org/tasks/notifications/NotificationClearedReceiver.kt index afa9fdedd..881c342e0 100644 --- a/app/src/main/java/org/tasks/notifications/NotificationClearedReceiver.kt +++ b/app/src/main/java/org/tasks/notifications/NotificationClearedReceiver.kt @@ -3,6 +3,7 @@ package org.tasks.notifications import android.content.Context import android.content.Intent import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.runBlocking import org.tasks.injection.InjectingBroadcastReceiver import timber.log.Timber import javax.inject.Inject @@ -15,6 +16,8 @@ class NotificationClearedReceiver : InjectingBroadcastReceiver() { super.onReceive(context, intent) val notificationId = intent.getLongExtra(NotificationManager.EXTRA_NOTIFICATION_ID, -1L) Timber.d("cleared $notificationId") - notificationManager.cancel(notificationId) + runBlocking { + notificationManager.cancel(notificationId) + } } } \ No newline at end of file diff --git a/app/src/main/java/org/tasks/notifications/NotificationManager.kt b/app/src/main/java/org/tasks/notifications/NotificationManager.kt index 3dc338955..32b798f4a 100644 --- a/app/src/main/java/org/tasks/notifications/NotificationManager.kt +++ b/app/src/main/java/org/tasks/notifications/NotificationManager.kt @@ -11,18 +11,14 @@ import com.todoroo.andlib.sql.QueryTemplate import com.todoroo.andlib.utility.AndroidUtilities import com.todoroo.andlib.utility.DateUtilities 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.reminders.ReminderService 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.R import org.tasks.Strings.isNullOrEmpty -import org.tasks.data.LocationDaoBlocking +import org.tasks.data.LocationDao import org.tasks.intents.TaskIntents import org.tasks.preferences.Preferences import org.tasks.receivers.CompleteTaskReceiver @@ -41,9 +37,9 @@ import kotlin.math.min class NotificationManager @Inject constructor( @param:ApplicationContext private val context: Context, private val preferences: Preferences, - private val notificationDao: NotificationDaoBlocking, - private val taskDao: TaskDaoBlocking, - private val locationDao: LocationDaoBlocking, + private val notificationDao: NotificationDao, + private val taskDao: TaskDao, + private val locationDao: LocationDao, private val localBroadcastManager: LocalBroadcastManager) { private val notificationManagerCompat = NotificationManagerCompat.from(context) private val colorProvider = ColorProvider(context, preferences) @@ -51,35 +47,25 @@ class NotificationManager @Inject constructor( private val queue = NotificationLimiter(MAX_NOTIFICATIONS) @SuppressLint("CheckResult") - fun cancel(id: Long) { + suspend fun cancel(id: Long) { if (id == SUMMARY_NOTIFICATION_ID.toLong()) { - Single.fromCallable { notificationDao.getAll() + id } - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe { ids: Iterable -> this.cancel(ids) } + cancel(notificationDao.getAll() + id) } else { cancel(listOf(id)) } } @SuppressLint("CheckResult") - fun cancel(ids: Iterable) { + suspend fun cancel(ids: Iterable) { for (id in ids) { notificationManagerCompat.cancel(id.toInt()) queue.remove(id) } - Completable.fromAction { notificationDao.deleteAll(ids.toList()) } - .subscribeOn(Schedulers.io()) - .subscribe { - notifyTasks( - emptyList(), - alert = false, - nonstop = false, - fiveTimes = false) - } + notificationDao.deleteAll(ids.toList()) + notifyTasks(emptyList(), alert = false, nonstop = false, fiveTimes = false) } - fun restoreNotifications(cancelExisting: Boolean) { + suspend fun restoreNotifications(cancelExisting: Boolean) { val notifications = notificationDao.getAllOrdered() if (cancelExisting) { for (notification in notifications) { @@ -109,8 +95,11 @@ class NotificationManager @Inject constructor( } } - fun notifyTasks( - newNotifications: List, alert: Boolean, nonstop: Boolean, fiveTimes: Boolean) { + suspend fun notifyTasks( + newNotifications: List, + alert: Boolean, + nonstop: Boolean, + fiveTimes: Boolean) { val existingNotifications = notificationDao.getAllOrdered() notificationDao.insertAll(newNotifications) val totalCount = existingNotifications.size + newNotifications.size @@ -151,7 +140,7 @@ class NotificationManager @Inject constructor( localBroadcastManager.broadcastRefresh() } - private fun createNotifications( + private suspend fun createNotifications( notifications: List, alert: Boolean, nonstop: Boolean, @@ -166,7 +155,7 @@ class NotificationManager @Inject constructor( } else { builder .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( if (alert) NotificationCompat.GROUP_ALERT_CHILDREN else NotificationCompat.GROUP_ALERT_SUMMARY) notify(notification.taskId, builder, alert, nonstop, fiveTimes) @@ -175,7 +164,7 @@ class NotificationManager @Inject constructor( } } - fun notify( + suspend fun notify( notificationId: Long, builder: NotificationCompat.Builder, 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) { val tasks = taskDao.activeNotifications() val taskCount = tasks.size @@ -275,11 +264,11 @@ class NotificationManager @Inject constructor( 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 type = notification.type val `when` = notification.timestamp - val task = taskDao.fetchBlocking(id) + val task = taskDao.fetch(id) if (task == null) { Timber.e("Could not find %s", id) return null