diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/activities/MainActivity.kt b/app/src/main/kotlin/com/simplemobiletools/clock/activities/MainActivity.kt index 871c8ae1..d6b11dcd 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/activities/MainActivity.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/activities/MainActivity.kt @@ -10,18 +10,18 @@ import android.os.Bundle import android.view.WindowManager import android.widget.ImageView import android.widget.TextView +import androidx.lifecycle.lifecycleScope import com.simplemobiletools.clock.BuildConfig import com.simplemobiletools.clock.R import com.simplemobiletools.clock.adapters.ViewPagerAdapter -import com.simplemobiletools.clock.extensions.config -import com.simplemobiletools.clock.extensions.getNextAlarm -import com.simplemobiletools.clock.extensions.rescheduleEnabledAlarms -import com.simplemobiletools.clock.extensions.updateWidgets +import com.simplemobiletools.clock.extensions.* import com.simplemobiletools.clock.helpers.* import com.simplemobiletools.commons.extensions.* import com.simplemobiletools.commons.helpers.* import com.simplemobiletools.commons.models.FAQItem import kotlinx.android.synthetic.main.activity_main.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch import me.grantland.widget.AutofitHelper class MainActivity : SimpleActivity() { @@ -44,8 +44,8 @@ class MainActivity : SimpleActivity() { setupTabs() updateWidgets() - if (getNextAlarm().isEmpty()) { - ensureBackgroundThread { + lifecycleScope.launch(Dispatchers.IO) { + if (getEnabledAlarms().isEmpty()) { rescheduleEnabledAlarms() } } diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Context.kt b/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Context.kt index 4dc63988..0d1025d4 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Context.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/extensions/Context.kt @@ -270,25 +270,8 @@ fun Context.formatTo12HourFormat(showSeconds: Boolean, hours: Int, minutes: Int, return "${formatTime(showSeconds, false, newHours, minutes, seconds)} $appendable" } -fun Context.getNextAlarm(): String { - val milliseconds = (getSystemService(Context.ALARM_SERVICE) as AlarmManager).nextAlarmClock?.triggerTime ?: return "" - val calendar = Calendar.getInstance() - val isDaylightSavingActive = TimeZone.getDefault().inDaylightTime(Date()) - var offset = calendar.timeZone.rawOffset - if (isDaylightSavingActive) { - offset += TimeZone.getDefault().dstSavings - } - - calendar.timeInMillis = milliseconds - val dayOfWeekIndex = (calendar.get(Calendar.DAY_OF_WEEK) + 5) % 7 - val dayOfWeek = resources.getStringArray(R.array.week_days_short)[dayOfWeekIndex] - val formatted = getFormattedTime(((milliseconds + offset) / 1000L).toInt(), false, false) - return "$dayOfWeek $formatted" -} - suspend fun Context.getClosestEnabledAlarmString(): String = withContext(Dispatchers.IO) { - val enabledAlarms = dbHelper.getEnabledAlarms() - val nextAlarmList = enabledAlarms + val nextAlarmList = getEnabledAlarms() .mapNotNull { getTimeUntilNextAlarm(it.timeInMinutes, it.days) } if (nextAlarmList.isEmpty()) { @@ -320,6 +303,10 @@ suspend fun Context.getClosestEnabledAlarmString(): String = withContext(Dispatc return@withContext "$dayOfWeek $formattedTime" } +suspend fun Context.getEnabledAlarms(): List = withContext(Dispatchers.IO) { + return@withContext dbHelper.getEnabledAlarms() +} + fun Context.rescheduleEnabledAlarms() { dbHelper.getEnabledAlarms().forEach { if (it.days != TODAY_BIT || it.timeInMinutes > getCurrentDayMinutes()) { diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/fragments/AlarmFragment.kt b/app/src/main/kotlin/com/simplemobiletools/clock/fragments/AlarmFragment.kt index 2b9f3473..6bf85826 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/fragments/AlarmFragment.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/fragments/AlarmFragment.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.lifecycle.lifecycleScope import com.simplemobiletools.clock.R import com.simplemobiletools.clock.activities.MainActivity import com.simplemobiletools.clock.activities.SimpleActivity @@ -20,9 +21,10 @@ import com.simplemobiletools.commons.extensions.getProperTextColor import com.simplemobiletools.commons.extensions.toast import com.simplemobiletools.commons.extensions.updateTextColors import com.simplemobiletools.commons.helpers.SORT_BY_DATE_CREATED -import com.simplemobiletools.commons.helpers.ensureBackgroundThread import com.simplemobiletools.commons.models.AlarmSound import kotlinx.android.synthetic.main.fragment_alarm.view.* +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch class AlarmFragment : Fragment(), ToggleAlarmInterface { private var alarms = ArrayList() @@ -89,12 +91,11 @@ class AlarmFragment : Fragment(), ToggleAlarmInterface { it.timeInMinutes }) } - - if (context?.getNextAlarm()?.isEmpty() == true) { - alarms.forEach { - if (it.days == TODAY_BIT && it.isEnabled && it.timeInMinutes <= getCurrentDayMinutes()) { - it.isEnabled = false - ensureBackgroundThread { + lifecycleScope.launch(Dispatchers.IO) { + if (context?.getEnabledAlarms()?.isEmpty() == true) { + alarms.forEach { + if (it.days == TODAY_BIT && it.isEnabled && it.timeInMinutes <= getCurrentDayMinutes()) { + it.isEnabled = false context?.dbHelper?.updateAlarmEnabledState(it.id, false) } } diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Constants.kt b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Constants.kt index 904ebe0d..073a8770 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Constants.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/Constants.kt @@ -1,7 +1,13 @@ package com.simplemobiletools.clock.helpers +import android.content.BroadcastReceiver import com.simplemobiletools.clock.models.MyTimeZone +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch import java.util.* +import kotlin.coroutines.CoroutineContext import kotlin.math.pow // shared preferences @@ -237,3 +243,16 @@ fun getTimeDifferenceInMinutes(currentTimeInMinutes: Int, alarmTimeInMinutes: In } } +fun BroadcastReceiver.goAsync( + context: CoroutineContext = (Dispatchers.Main.immediate + SupervisorJob()), + block: suspend CoroutineScope.() -> Unit +) { + val pendingResult = goAsync() + CoroutineScope(SupervisorJob()).launch(context) { + try { + block() + } finally { + pendingResult.finish() + } + } +} diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/MyDigitalTimeWidgetProvider.kt b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/MyDigitalTimeWidgetProvider.kt index c9c23817..5f96184b 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/helpers/MyDigitalTimeWidgetProvider.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/helpers/MyDigitalTimeWidgetProvider.kt @@ -12,11 +12,16 @@ import android.widget.RemoteViews import com.simplemobiletools.clock.R import com.simplemobiletools.clock.activities.SplashActivity import com.simplemobiletools.clock.extensions.config -import com.simplemobiletools.clock.extensions.getNextAlarm +import com.simplemobiletools.clock.extensions.getClosestEnabledAlarmString import com.simplemobiletools.commons.extensions.applyColorFilter import com.simplemobiletools.commons.extensions.getLaunchIntent import com.simplemobiletools.commons.extensions.setText import com.simplemobiletools.commons.extensions.setVisibleIf +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.cancel +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class MyDigitalTimeWidgetProvider : AppWidgetProvider() { override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) { @@ -37,10 +42,18 @@ class MyDigitalTimeWidgetProvider : AppWidgetProvider() { } private fun updateTexts(context: Context, views: RemoteViews) { - val nextAlarm = context.getNextAlarm() - views.apply { - setText(R.id.widget_next_alarm, nextAlarm) - setVisibleIf(R.id.widget_alarm_holder, nextAlarm.isNotEmpty()) + CoroutineScope(Dispatchers.IO).launch { + try { + val nextAlarm = context.getClosestEnabledAlarmString() + withContext(Dispatchers.Main.immediate) { + views.apply { + setText(R.id.widget_next_alarm, nextAlarm) + setVisibleIf(R.id.widget_alarm_holder, nextAlarm.isNotEmpty()) + } + } + } finally { + cancel() + } } } diff --git a/app/src/main/kotlin/com/simplemobiletools/clock/receivers/EarlyAlarmDismissalReceiver.kt b/app/src/main/kotlin/com/simplemobiletools/clock/receivers/EarlyAlarmDismissalReceiver.kt index b5fd5348..4cfa6e05 100644 --- a/app/src/main/kotlin/com/simplemobiletools/clock/receivers/EarlyAlarmDismissalReceiver.kt +++ b/app/src/main/kotlin/com/simplemobiletools/clock/receivers/EarlyAlarmDismissalReceiver.kt @@ -6,29 +6,29 @@ import android.app.NotificationManager import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.text.format.DateFormat import androidx.core.app.NotificationCompat import com.simplemobiletools.clock.R +import com.simplemobiletools.clock.extensions.getClosestEnabledAlarmString import com.simplemobiletools.clock.extensions.getDismissAlarmPendingIntent -import com.simplemobiletools.clock.extensions.getNextAlarm import com.simplemobiletools.clock.extensions.getOpenAlarmTabIntent -import com.simplemobiletools.clock.helpers.* +import com.simplemobiletools.clock.helpers.ALARM_ID +import com.simplemobiletools.clock.helpers.EARLY_ALARM_DISMISSAL_CHANNEL_ID +import com.simplemobiletools.clock.helpers.EARLY_ALARM_NOTIF_ID +import com.simplemobiletools.clock.helpers.goAsync import com.simplemobiletools.commons.helpers.isOreoPlus -import java.text.SimpleDateFormat -import java.util.* class EarlyAlarmDismissalReceiver : BroadcastReceiver() { - override fun onReceive(context: Context, intent: Intent) { + override fun onReceive(context: Context, intent: Intent) = goAsync { val alarmId = intent.getIntExtra(ALARM_ID, -1) if (alarmId == -1) { - return + return@goAsync } triggerEarlyDismissalNotification(context, alarmId) } - private fun triggerEarlyDismissalNotification(context: Context, alarmId: Int) { + private suspend fun triggerEarlyDismissalNotification(context: Context, alarmId: Int) { val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager if (isOreoPlus()) { NotificationChannel(EARLY_ALARM_DISMISSAL_CHANNEL_ID, context.getString(R.string.early_alarm_dismissal), NotificationManager.IMPORTANCE_DEFAULT).apply { @@ -42,7 +42,7 @@ class EarlyAlarmDismissalReceiver : BroadcastReceiver() { val contentIntent = context.getOpenAlarmTabIntent() val notification = NotificationCompat.Builder(context) .setContentTitle(context.getString(R.string.upcoming_alarm)) - .setContentText(context.getNextAlarm()) + .setContentText(context.getClosestEnabledAlarmString()) .setSmallIcon(R.drawable.ic_alarm_vector) .setPriority(Notification.PRIORITY_LOW) .addAction(0, context.getString(R.string.dismiss), dismissIntent)