From d9b38cc71d7baa6e1b28b5d625d698f6448d15d5 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Mon, 31 Mar 2025 23:33:36 +0530 Subject: [PATCH 1/5] Reschedule alarms after app updates It should help with cases like https://github.com/FossifyOrg/Clock/issues/61 and with aggressive devices where alarms are cancelled by updates. --- app/src/main/AndroidManifest.xml | 3 ++- .../{BootCompletedReceiver.kt => RescheduleAlarmsReceiver.kt} | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) rename app/src/main/kotlin/org/fossify/clock/receivers/{BootCompletedReceiver.kt => RescheduleAlarmsReceiver.kt} (87%) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 325ea717..d02a88f5 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -178,12 +178,13 @@ + diff --git a/app/src/main/kotlin/org/fossify/clock/receivers/BootCompletedReceiver.kt b/app/src/main/kotlin/org/fossify/clock/receivers/RescheduleAlarmsReceiver.kt similarity index 87% rename from app/src/main/kotlin/org/fossify/clock/receivers/BootCompletedReceiver.kt rename to app/src/main/kotlin/org/fossify/clock/receivers/RescheduleAlarmsReceiver.kt index 98c34114..b12fb2e7 100644 --- a/app/src/main/kotlin/org/fossify/clock/receivers/BootCompletedReceiver.kt +++ b/app/src/main/kotlin/org/fossify/clock/receivers/RescheduleAlarmsReceiver.kt @@ -6,7 +6,7 @@ import android.content.Intent import org.fossify.clock.extensions.alarmController import org.fossify.clock.extensions.goAsync -class BootCompletedReceiver : BroadcastReceiver() { +class RescheduleAlarmsReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { goAsync { From ae59b0c6cc3f8889b4c5cdaa2a22eaaaa4d199ae Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Tue, 1 Apr 2025 00:18:51 +0530 Subject: [PATCH 2/5] Reschedule alarms when time or zone changes --- app/src/main/AndroidManifest.xml | 4 +++- .../org/fossify/clock/receivers/RescheduleAlarmsReceiver.kt | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d02a88f5..ae9ae3db 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -182,9 +182,11 @@ android:exported="true"> + + + - diff --git a/app/src/main/kotlin/org/fossify/clock/receivers/RescheduleAlarmsReceiver.kt b/app/src/main/kotlin/org/fossify/clock/receivers/RescheduleAlarmsReceiver.kt index b12fb2e7..ac207d11 100644 --- a/app/src/main/kotlin/org/fossify/clock/receivers/RescheduleAlarmsReceiver.kt +++ b/app/src/main/kotlin/org/fossify/clock/receivers/RescheduleAlarmsReceiver.kt @@ -1,13 +1,18 @@ package org.fossify.clock.receivers +import android.annotation.SuppressLint import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import org.fossify.clock.extensions.alarmController import org.fossify.clock.extensions.goAsync +/** + * Receiver responsible for rescheduling alarms in background. + */ class RescheduleAlarmsReceiver : BroadcastReceiver() { + @SuppressLint("UnsafeProtectedBroadcastReceiver") override fun onReceive(context: Context, intent: Intent) { goAsync { context.alarmController.rescheduleEnabledAlarms() From ea467df25f666943b82d01998337a4c1f3d5c93e Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Tue, 1 Apr 2025 01:47:05 +0530 Subject: [PATCH 3/5] Add another TODO regarding scheduling logic It still uses the original workaround to manage skipped upcoming alarms --- .../main/kotlin/org/fossify/clock/helpers/AlarmController.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/AlarmController.kt b/app/src/main/kotlin/org/fossify/clock/helpers/AlarmController.kt index 17d6ddc8..c99e77d4 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/AlarmController.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/AlarmController.kt @@ -31,6 +31,8 @@ class AlarmController( */ fun rescheduleEnabledAlarms() { db.getEnabledAlarms().forEach { + // TODO: Instead of naively not scheduling all alarms for today, skipped upcoming + // alarms should be tracked properly. if (!it.isToday() || it.timeInMinutes > getCurrentDayMinutes()) { scheduleNextOccurrence(it, false) } From cb13d401cd79725f0c18b612711b0d4399e4cce3 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Tue, 1 Apr 2025 09:51:13 +0530 Subject: [PATCH 4/5] Minor readability improvement --- .../kotlin/org/fossify/clock/fragments/AlarmFragment.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt index f8d1e763..fc08567f 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/AlarmFragment.kt @@ -196,12 +196,13 @@ class AlarmFragment : Fragment(), ToggleAlarmInterface { } private fun checkAlarmState(alarm: Alarm) { + val activity = activity as? MainActivity ?: return if (alarm.isEnabled) { - context?.alarmController?.scheduleNextOccurrence(alarm, true) + activity.alarmController.scheduleNextOccurrence(alarm = alarm, showToasts = true) } else { - context?.cancelAlarmClock(alarm) + activity.cancelAlarmClock(alarm) } - (activity as? MainActivity)?.updateClockTabAlarm() + activity.updateClockTabAlarm() } fun updateAlarmSound(alarmSound: AlarmSound) { @@ -209,7 +210,7 @@ class AlarmFragment : Fragment(), ToggleAlarmInterface { } @Subscribe(threadMode = ThreadMode.MAIN) - fun onMessageEvent(event: AlarmEvent.Refresh) { + fun onMessageEvent(@Suppress("unused") event: AlarmEvent.Refresh) { setupAlarms() } } From 2c1a890a9619ed257a5719e2ba2826a906b95c19 Mon Sep 17 00:00:00 2001 From: Naveen Singh Date: Tue, 1 Apr 2025 10:21:58 +0530 Subject: [PATCH 5/5] Fix some detekt issues --- .../org/fossify/clock/activities/AlarmActivity.kt | 15 +++++++++++---- .../fossify/clock/activities/SettingsActivity.kt | 5 ----- .../org/fossify/clock/fragments/TimerFragment.kt | 8 +++++--- .../kotlin/org/fossify/clock/helpers/Constants.kt | 1 + .../org/fossify/clock/services/AlarmService.kt | 14 ++++++-------- 5 files changed, 23 insertions(+), 20 deletions(-) diff --git a/app/src/main/kotlin/org/fossify/clock/activities/AlarmActivity.kt b/app/src/main/kotlin/org/fossify/clock/activities/AlarmActivity.kt index 53d4fbe9..4ebb6e2c 100644 --- a/app/src/main/kotlin/org/fossify/clock/activities/AlarmActivity.kt +++ b/app/src/main/kotlin/org/fossify/clock/activities/AlarmActivity.kt @@ -38,6 +38,11 @@ import kotlin.math.max import kotlin.math.min class AlarmActivity : SimpleActivity() { + companion object { + private const val REMINDER_DRAGGABLE_BACKGROUND_ALPHA = 0.2f + private const val REMINDER_GUIDE_SHOW_DURATION = 2000L + private const val DRAG_ACTION_THRESHOLD_PX = 50f + } private val swipeGuideFadeHandler = Handler(Looper.getMainLooper()) private var alarm: Alarm? = null @@ -109,14 +114,16 @@ class AlarmActivity : SimpleActivity() { dragDownX = 0f if (!didVibrate) { binding.reminderDraggable.animate().x(initialDraggableX).withEndAction { - binding.reminderDraggableBackground.animate().alpha(0.2f) + binding.reminderDraggableBackground + .animate() + .alpha(REMINDER_DRAGGABLE_BACKGROUND_ALPHA) } binding.reminderGuide.animate().alpha(1f).start() swipeGuideFadeHandler.removeCallbacksAndMessages(null) swipeGuideFadeHandler.postDelayed({ binding.reminderGuide.animate().alpha(0f).start() - }, 2000L) + }, REMINDER_GUIDE_SHOW_DURATION) } } @@ -126,13 +133,13 @@ class AlarmActivity : SimpleActivity() { b = max(minDragX, event.rawX - dragDownX) ) - if (binding.reminderDraggable.x >= maxDragX - 50f) { + if (binding.reminderDraggable.x >= maxDragX - DRAG_ACTION_THRESHOLD_PX) { if (!didVibrate) { binding.reminderDraggable.performHapticFeedback() didVibrate = true dismissAlarmAndFinish() } - } else if (binding.reminderDraggable.x <= minDragX + 50f) { + } else if (binding.reminderDraggable.x <= minDragX + DRAG_ACTION_THRESHOLD_PX) { if (!didVibrate) { binding.reminderDraggable.performHapticFeedback() didVibrate = true diff --git a/app/src/main/kotlin/org/fossify/clock/activities/SettingsActivity.kt b/app/src/main/kotlin/org/fossify/clock/activities/SettingsActivity.kt index ecf61dd1..ba38473c 100644 --- a/app/src/main/kotlin/org/fossify/clock/activities/SettingsActivity.kt +++ b/app/src/main/kotlin/org/fossify/clock/activities/SettingsActivity.kt @@ -36,7 +36,6 @@ import org.fossify.commons.extensions.getCustomizeColorsString import org.fossify.commons.extensions.getProperPrimaryColor import org.fossify.commons.extensions.isOrWasThankYouInstalled import org.fossify.commons.extensions.launchPurchaseThankYouIntent -import org.fossify.commons.extensions.showErrorToast import org.fossify.commons.extensions.showPickSecondsDialog import org.fossify.commons.extensions.toast import org.fossify.commons.extensions.updateTextColors @@ -352,8 +351,6 @@ class SettingsActivity : SimpleActivity() { id = org.fossify.commons.R.string.system_service_disabled, length = Toast.LENGTH_LONG ) - } catch (e: Exception) { - showErrorToast(e) } } } @@ -363,8 +360,6 @@ class SettingsActivity : SimpleActivity() { importActivityResultLauncher.launch(IMPORT_BACKUP_MIME_TYPES.toTypedArray()) } catch (@Suppress("SwallowedException") _: ActivityNotFoundException) { toast(org.fossify.commons.R.string.system_service_disabled, Toast.LENGTH_LONG) - } catch (e: Exception) { - showErrorToast(e) } } diff --git a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt index 3caaec61..c59d847c 100644 --- a/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt +++ b/app/src/main/kotlin/org/fossify/clock/fragments/TimerFragment.kt @@ -32,6 +32,10 @@ import org.greenrobot.eventbus.Subscribe import org.greenrobot.eventbus.ThreadMode class TimerFragment : Fragment() { + companion object { + private const val INVALID_POSITION = -1 + } + private lateinit var binding: FragmentTimerBinding private lateinit var timerAdapter: TimerAdapter private var timerPositionToScrollTo = INVALID_POSITION @@ -168,7 +172,7 @@ class TimerFragment : Fragment() { } @Subscribe(threadMode = ThreadMode.MAIN) - fun onMessageEvent(event: TimerEvent.Refresh) { + fun onMessageEvent(@Suppress("unused") event: TimerEvent.Refresh) { refreshTimers() } @@ -196,5 +200,3 @@ class TimerFragment : Fragment() { } } } - -private const val INVALID_POSITION = -1 diff --git a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt index 9477e94e..de11c7f4 100644 --- a/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt +++ b/app/src/main/kotlin/org/fossify/clock/helpers/Constants.kt @@ -175,6 +175,7 @@ fun getCurrentDayMinutes(): Int { return calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE) } +@Suppress("MagicNumber") fun getAllTimeZones() = arrayListOf( MyTimeZone(1, "GMT-11:00 Midway", "Pacific/Midway"), MyTimeZone(2, "GMT-10:00 Honolulu", "Pacific/Honolulu"), diff --git a/app/src/main/kotlin/org/fossify/clock/services/AlarmService.kt b/app/src/main/kotlin/org/fossify/clock/services/AlarmService.kt index 66ff48ba..75fd5ee8 100644 --- a/app/src/main/kotlin/org/fossify/clock/services/AlarmService.kt +++ b/app/src/main/kotlin/org/fossify/clock/services/AlarmService.kt @@ -46,6 +46,8 @@ class AlarmService : Service() { private const val DEFAULT_ALARM_VOLUME = 7 private const val INCREASE_VOLUME_DELAY = 300L private const val MIN_ALARM_VOLUME_FOR_INCREASING_ALARMS = 1 + private const val VIBRATION_PATTERN_TIMING = 500L + private const val VOLUME_INCREASE_STEP = 0.1f } private var alarm: Alarm? = null @@ -170,11 +172,9 @@ class AlarmService : Service() { if (alarm.vibrate) { vibrator = getSystemService(VIBRATOR_SERVICE) as Vibrator - val timing = 500L - val repeatIndex = 0 vibrator?.vibrate( VibrationEffect.createWaveform( - longArrayOf(timing, timing), repeatIndex + longArrayOf(VIBRATION_PATTERN_TIMING, VIBRATION_PATTERN_TIMING), 0 ) ) } @@ -182,9 +182,8 @@ class AlarmService : Service() { private fun scheduleVolumeIncrease(lastVolume: Float, maxVolume: Float, delay: Long) { increaseVolumeHandler.postDelayed({ - val volumeFlags = 0 - val newVolume = (lastVolume + 0.1f).coerceAtMost(maxVolume) - audioManager?.setStreamVolume(STREAM_ALARM, newVolume.toInt(), volumeFlags) + val newVolume = (lastVolume + VOLUME_INCREASE_STEP).coerceAtMost(maxVolume) + audioManager?.setStreamVolume(STREAM_ALARM, newVolume.toInt(), 0) if (newVolume < maxVolume) { scheduleVolumeIncrease(newVolume, maxVolume, INCREASE_VOLUME_DELAY) } @@ -193,8 +192,7 @@ class AlarmService : Service() { private fun resetVolumeToInitialValue() { if (config.increaseVolumeGradually) { - val volumeFlags = 0 - audioManager?.setStreamVolume(STREAM_ALARM, initialAlarmVolume, volumeFlags) + audioManager?.setStreamVolume(STREAM_ALARM, initialAlarmVolume, 0) } }