From a8a104242a3e15b9cf49c5df9689df407b9e4dd4 Mon Sep 17 00:00:00 2001 From: Cody Henthorne Date: Wed, 8 Dec 2021 17:28:36 -0500 Subject: [PATCH] Fix various issues regarding Notification Profile scheduling. - Timezone conversion when detecting scheduled profile - Not automatically enabling a scheduled profile on creation regardless of when other profiles were enabled/disabled --- .../NotificationProfileSelectionState.kt | 4 +- .../NotificationProfileSelectionViewModel.kt | 31 +++--- .../models/NotificationProfileSelection.kt | 14 +-- ...EditNotificationProfileScheduleFragment.kt | 2 +- ...ditNotificationProfileScheduleViewModel.kt | 18 ++- .../NotificationProfilesRepository.kt | 10 +- .../profiles/NotificationProfiles.kt | 3 +- .../securesms/util/LocalDateTimeExtensions.kt | 12 +- app/src/main/res/values/strings.xml | 2 +- .../NotificationProfileScheduleTest.kt | 105 +++++++++--------- .../profiles/NotificationProfilesTest.kt | 29 ++--- 11 files changed, 126 insertions(+), 104 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/NotificationProfileSelectionState.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/NotificationProfileSelectionState.kt index 2f310efbb..38845229d 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/NotificationProfileSelectionState.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/NotificationProfileSelectionState.kt @@ -1,10 +1,10 @@ package org.thoughtcrime.securesms.components.settings.app.notifications.manual import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile -import java.util.Calendar +import java.time.LocalDateTime data class NotificationProfileSelectionState( val notificationProfiles: List = listOf(), val expandedId: Long = -1L, - val timeSlotB: Calendar + val timeSlotB: LocalDateTime ) diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/NotificationProfileSelectionViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/NotificationProfileSelectionViewModel.kt index 3a81aad22..b6582386a 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/NotificationProfileSelectionViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/NotificationProfileSelectionViewModel.kt @@ -9,8 +9,10 @@ import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.subscribeBy import org.thoughtcrime.securesms.components.settings.app.notifications.profiles.NotificationProfilesRepository import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile +import org.thoughtcrime.securesms.util.isBetween import org.thoughtcrime.securesms.util.livedata.Store -import java.util.Calendar +import org.thoughtcrime.securesms.util.toMillis +import java.time.LocalDateTime import java.util.concurrent.TimeUnit class NotificationProfileSelectionViewModel(private val repository: NotificationProfilesRepository) : ViewModel() { @@ -53,29 +55,24 @@ class NotificationProfileSelectionViewModel(private val repository: Notification .subscribe() } - fun enableUntil(profile: NotificationProfile, calendar: Calendar) { - disposables += repository.manuallyEnableProfileForDuration(profile.id, calendar.timeInMillis) + fun enableUntil(profile: NotificationProfile, enableUntil: LocalDateTime) { + disposables += repository.manuallyEnableProfileForDuration(profile.id, enableUntil.toMillis()) .subscribe() } companion object { - private fun getTimeSlotB(): Calendar { - val now = Calendar.getInstance() - val sixPm = Calendar.getInstance() - val eightAm = Calendar.getInstance() + @Suppress("CascadeIf") + private fun getTimeSlotB(): LocalDateTime { + val now = LocalDateTime.now() + val sixPm = now.withHour(18).withMinute(0).withSecond(0) + val eightAm = now.withHour(8).withMinute(0).withSecond(0) - sixPm.set(Calendar.HOUR_OF_DAY, 18) - sixPm.set(Calendar.MINUTE, 0) - sixPm.set(Calendar.SECOND, 0) - - eightAm.set(Calendar.HOUR_OF_DAY, 8) - eightAm.set(Calendar.MINUTE, 0) - eightAm.set(Calendar.SECOND, 0) - - return if (now.before(sixPm) && (now.after(eightAm) || now == eightAm)) { + return if (now.isBetween(eightAm, sixPm)) { sixPm - } else { + } else if (now.isBefore(eightAm)) { eightAm + } else { + eightAm.plusDays(1) } } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/models/NotificationProfileSelection.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/models/NotificationProfileSelection.kt index f1441b098..a74be7b90 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/models/NotificationProfileSelection.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/manual/models/NotificationProfileSelection.kt @@ -9,12 +9,12 @@ import org.thoughtcrime.securesms.components.emoji.EmojiImageView import org.thoughtcrime.securesms.components.settings.DSLSettingsText import org.thoughtcrime.securesms.components.settings.PreferenceModel import org.thoughtcrime.securesms.notifications.profiles.NotificationProfile -import org.thoughtcrime.securesms.util.DateUtils import org.thoughtcrime.securesms.util.MappingAdapter import org.thoughtcrime.securesms.util.MappingViewHolder +import org.thoughtcrime.securesms.util.formatHours import org.thoughtcrime.securesms.util.visible -import java.util.Calendar -import java.util.Locale +import java.time.LocalDateTime +import java.time.LocalTime /** * Notification Profile selection preference. @@ -34,10 +34,10 @@ object NotificationProfileSelection { override val summary: DSLSettingsText, val notificationProfile: NotificationProfile, val isExpanded: Boolean, - val timeSlotB: Calendar, + val timeSlotB: LocalDateTime, val onRowClick: (NotificationProfile) -> Unit, val onTimeSlotAClick: (NotificationProfile) -> Unit, - val onTimeSlotBClick: (NotificationProfile, Calendar) -> Unit, + val onTimeSlotBClick: (NotificationProfile, LocalDateTime) -> Unit, val onViewSettingsClick: (NotificationProfile) -> Unit, val onToggleClick: (NotificationProfile) -> Unit ) : PreferenceModel() { @@ -87,7 +87,7 @@ object NotificationProfileSelection { expansion.visible = model.isExpanded timeSlotB.text = context.getString( R.string.NotificationProfileSelection__until_s, - DateUtils.getTimeString(context, Locale.getDefault(), model.timeSlotB.timeInMillis) + LocalTime.from(model.timeSlotB).formatHours() ) if (TOGGLE_EXPANSION in payload || UPDATE_TIMESLOT in payload) { @@ -107,7 +107,7 @@ object NotificationProfileSelection { timeSlotB.text = context.getString( R.string.NotificationProfileSelection__until_s, - DateUtils.getTimeString(context, Locale.getDefault(), model.timeSlotB.timeInMillis) + LocalTime.from(model.timeSlotB).formatHours() ) itemView.isSelected = model.isOn diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileScheduleFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileScheduleFragment.kt index d9476e027..147bd9d6f 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileScheduleFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileScheduleFragment.kt @@ -35,7 +35,7 @@ import java.time.format.DateTimeFormatter */ class EditNotificationProfileScheduleFragment : LoggingFragment(R.layout.fragment_edit_notification_profile_schedule) { - private val viewModel: EditNotificationProfileScheduleViewModel by viewModels(factoryProducer = { EditNotificationProfileScheduleViewModel.Factory(profileId) }) + private val viewModel: EditNotificationProfileScheduleViewModel by viewModels(factoryProducer = { EditNotificationProfileScheduleViewModel.Factory(profileId, createMode) }) private val lifecycleDisposable = LifecycleDisposable() private val profileId: Long by lazy { EditNotificationProfileScheduleFragmentArgs.fromBundle(requireArguments()).profileId } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileScheduleViewModel.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileScheduleViewModel.kt index c2109817d..519e35cb9 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileScheduleViewModel.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/EditNotificationProfileScheduleViewModel.kt @@ -17,7 +17,8 @@ import java.time.DayOfWeek * from the database and into the [scheduleSubject] allowing the safe use of !! with [schedule]. */ class EditNotificationProfileScheduleViewModel( - profileId: Long, + private val profileId: Long, + private val createMode: Boolean, private val repository: NotificationProfilesRepository ) : ViewModel() { @@ -72,14 +73,23 @@ class EditNotificationProfileScheduleViewModel( } else if (createMode && !schedule.enabled) { Single.just(SaveScheduleResult.Success) } else { - repository.updateSchedule(schedule).toSingle { SaveScheduleResult.Success } + repository.updateSchedule(schedule) + .toSingleDefault(SaveScheduleResult.Success) + .flatMap { r -> + if (createMode && schedule.enabled && schedule.coversTime(System.currentTimeMillis())) { + repository.manuallyToggleProfile(profileId, schedule) + .toSingleDefault(r) + } else { + Single.just(r) + } + } } return result.observeOn(AndroidSchedulers.mainThread()) } - class Factory(private val profileId: Long) : ViewModelProvider.Factory { + class Factory(private val profileId: Long, private val createMode: Boolean) : ViewModelProvider.Factory { override fun create(modelClass: Class): T { - return modelClass.cast(EditNotificationProfileScheduleViewModel(profileId, NotificationProfilesRepository()))!! + return modelClass.cast(EditNotificationProfileScheduleViewModel(profileId, createMode, NotificationProfilesRepository()))!! } } diff --git a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesRepository.kt b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesRepository.kt index 63f07b5f2..9c92b0722 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesRepository.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/components/settings/app/notifications/profiles/NotificationProfilesRepository.kt @@ -96,19 +96,23 @@ class NotificationProfilesRepository { } fun manuallyToggleProfile(profile: NotificationProfile, now: Long = System.currentTimeMillis()): Completable { + return manuallyToggleProfile(profile.id, profile.schedule, now) + } + + fun manuallyToggleProfile(profileId: Long, schedule: NotificationProfileSchedule, now: Long = System.currentTimeMillis()): Completable { return Completable.fromAction { val profiles = database.getProfiles() val activeProfile = NotificationProfiles.getActiveProfile(profiles, now) - if (profile.id == activeProfile?.id) { + if (profileId == activeProfile?.id) { SignalStore.notificationProfileValues().manuallyEnabledProfile = 0 SignalStore.notificationProfileValues().manuallyEnabledUntil = 0 SignalStore.notificationProfileValues().manuallyDisabledAt = now SignalStore.notificationProfileValues().lastProfilePopup = 0 SignalStore.notificationProfileValues().lastProfilePopupTime = 0 } else { - val inScheduledWindow = profile.schedule.isCurrentlyActive(now) - SignalStore.notificationProfileValues().manuallyEnabledProfile = if (inScheduledWindow) 0 else profile.id + val inScheduledWindow = schedule.isCurrentlyActive(now) + SignalStore.notificationProfileValues().manuallyEnabledProfile = if (inScheduledWindow) 0 else profileId SignalStore.notificationProfileValues().manuallyEnabledUntil = if (inScheduledWindow) 0 else Long.MAX_VALUE SignalStore.notificationProfileValues().manuallyDisabledAt = if (inScheduledWindow) 0 else now } diff --git a/app/src/main/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfiles.kt b/app/src/main/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfiles.kt index e70b9b2b5..407eee2d5 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfiles.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfiles.kt @@ -8,6 +8,7 @@ import org.thoughtcrime.securesms.util.formatHours import org.thoughtcrime.securesms.util.toLocalDateTime import org.thoughtcrime.securesms.util.toLocalTime import org.thoughtcrime.securesms.util.toMillis +import org.thoughtcrime.securesms.util.toOffset import java.time.LocalDateTime import java.time.ZoneId @@ -26,7 +27,7 @@ object NotificationProfiles { val manualProfile: NotificationProfile? = profiles.firstOrNull { it.id == storeValues.manuallyEnabledProfile } val scheduledProfile: NotificationProfile? = profiles.sortedDescending().filter { it.schedule.isCurrentlyActive(now, zoneId) }.firstOrNull { profile -> - profile.schedule.startDateTime(localNow).toMillis() > storeValues.manuallyDisabledAt + profile.schedule.startDateTime(localNow).toMillis(zoneId.toOffset()) > storeValues.manuallyDisabledAt } if (manualProfile == null || scheduledProfile == null) { diff --git a/app/src/main/java/org/thoughtcrime/securesms/util/LocalDateTimeExtensions.kt b/app/src/main/java/org/thoughtcrime/securesms/util/LocalDateTimeExtensions.kt index 0e9ce9a2d..2b8faf319 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/util/LocalDateTimeExtensions.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/util/LocalDateTimeExtensions.kt @@ -3,17 +3,25 @@ package org.thoughtcrime.securesms.util import java.time.Instant import java.time.LocalDateTime import java.time.LocalTime +import java.time.OffsetDateTime import java.time.ZoneId import java.time.ZoneOffset import java.time.format.DateTimeFormatter import java.time.format.FormatStyle import java.util.concurrent.TimeUnit +/** + * Given a [ZoneId] return the time offset as a [ZoneOffset]. + */ +fun ZoneId.toOffset(): ZoneOffset { + return OffsetDateTime.now(this).offset +} + /** * Convert [LocalDateTime] to be same as [System.currentTimeMillis] */ -fun LocalDateTime.toMillis(): Long { - return TimeUnit.SECONDS.toMillis(toEpochSecond(ZoneOffset.UTC)) +fun LocalDateTime.toMillis(zoneOffset: ZoneOffset = ZoneId.systemDefault().toOffset()): Long { + return TimeUnit.SECONDS.toMillis(toEpochSecond(zoneOffset)) } /** diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index a54bec79b..92caf2bce 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -411,7 +411,7 @@ - Notification Profile + Notification profile Turn your notification profile on or off here. diff --git a/app/src/test/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfileScheduleTest.kt b/app/src/test/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfileScheduleTest.kt index 150575be1..d8ab05053 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfileScheduleTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfileScheduleTest.kt @@ -7,6 +7,7 @@ import org.junit.Test import org.thoughtcrime.securesms.util.toMillis import java.time.DayOfWeek import java.time.LocalDateTime +import java.time.ZoneOffset import java.util.TimeZone class NotificationProfileScheduleTest { @@ -37,105 +38,105 @@ class NotificationProfileScheduleTest { fun `when time is within enabled schedule 9am to 5pm then return true`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 900, end = 1700, daysEnabled = setOf(DayOfWeek.SUNDAY)) - assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday9am.plusHours(1).toMillis())) + assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday9am.plusHours(1).toMillis(ZoneOffset.UTC))) } @Test fun `when time is outside enabled schedule 9am to 5pm then return false`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 900, end = 1700, daysEnabled = setOf(DayOfWeek.SUNDAY)) - assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday9am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis())) + assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC))) } @Test fun `when time is inside enabled with day wrapping schedule 10pm to 2am then return true`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 2100, end = 200, daysEnabled = setOf(DayOfWeek.MONDAY)) - assertTrue(schedule.isCurrentlyActive(monday10pm.toMillis())) - assertTrue(schedule.isCurrentlyActive(tuesday1am.toMillis())) + assertTrue(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(tuesday1am.toMillis(ZoneOffset.UTC))) } @Test fun `when time is outside enabled with day wrapping schedule 10pm to 2am then return false`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 2100, end = 200, daysEnabled = setOf(DayOfWeek.MONDAY)) - assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday9am.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis())) + assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis(ZoneOffset.UTC))) } @Test fun `when time is inside enabled schedule 12am to 10am then return false`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 0, end = 1000, daysEnabled = setOf(DayOfWeek.SUNDAY)) - assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis())) + assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC))) } @Test fun `when time is inside enabled schedule 12am to 12am then return false`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 0, end = 2400, daysEnabled = setOf(DayOfWeek.SUNDAY)) - assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday10pm.toMillis())) + assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC))) } @Test fun `when time is outside enabled schedule 12am to 12am then return false`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 0, end = 2400, daysEnabled = setOf(DayOfWeek.SUNDAY)) - assertFalse(schedule.isCurrentlyActive(monday0am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday9am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis())) + assertFalse(schedule.isCurrentlyActive(monday0am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis(ZoneOffset.UTC))) } @Test fun `when enabled schedule 12am to 12am for all days then return true`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = true, start = 0, end = 2400, daysEnabled = DayOfWeek.values().toSet()) - assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis())) - assertTrue(schedule.isCurrentlyActive(sunday10pm.toMillis())) - assertTrue(schedule.isCurrentlyActive(monday0am.toMillis())) - assertTrue(schedule.isCurrentlyActive(monday1am.toMillis())) - assertTrue(schedule.isCurrentlyActive(monday9am.toMillis())) - assertTrue(schedule.isCurrentlyActive(monday10pm.toMillis())) - assertTrue(schedule.isCurrentlyActive(tuesday1am.toMillis())) - assertTrue(schedule.isCurrentlyActive(tuesday9am.toMillis())) - assertTrue(schedule.isCurrentlyActive(tuesday10pm.toMillis())) + assertTrue(schedule.isCurrentlyActive(sunday0am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(monday0am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(tuesday1am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC))) + assertTrue(schedule.isCurrentlyActive(tuesday10pm.toMillis(ZoneOffset.UTC))) } @Test fun `when disabled schedule 12am to 12am for all days then return false`() { val schedule = NotificationProfileSchedule(id = 1L, enabled = false, start = 0, end = 2400, daysEnabled = DayOfWeek.values().toSet()) - assertFalse(schedule.isCurrentlyActive(sunday0am.toMillis())) - assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(sunday9am.toMillis())) - assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday0am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday9am.toMillis())) - assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday1am.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis())) - assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis())) + assertFalse(schedule.isCurrentlyActive(sunday0am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(sunday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(sunday9am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(sunday10pm.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday0am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday9am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(monday10pm.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday1am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday9am.toMillis(ZoneOffset.UTC))) + assertFalse(schedule.isCurrentlyActive(tuesday10pm.toMillis(ZoneOffset.UTC))) } } diff --git a/app/src/test/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfilesTest.kt b/app/src/test/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfilesTest.kt index e9e1e9ba9..5dbb1f31d 100644 --- a/app/src/test/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfilesTest.kt +++ b/app/src/test/java/org/thoughtcrime/securesms/notifications/profiles/NotificationProfilesTest.kt @@ -15,6 +15,7 @@ import org.thoughtcrime.securesms.util.toMillis import java.time.DayOfWeek import java.time.LocalDateTime import java.time.ZoneId +import java.time.ZoneOffset @RunWith(RobolectricTestRunner::class) @Config(manifest = Config.NONE, application = Application::class) @@ -69,30 +70,30 @@ class NotificationProfilesTest { fun `when first is scheduled and second is not manually enabled and now is within schedule return first`() { val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY)) val profiles = listOf(first.copy(schedule = schedule), second) - assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[0])) + assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[0])) } @Test fun `when first is scheduled and second is manually enabled forever within first's schedule then return second`() { signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, second.id) signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE) - signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis()) + signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC)) val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY)) val profiles = listOf(first.copy(schedule = schedule), second) - assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[1])) + assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[1])) } @Test fun `when first is scheduled and second is manually enabled forever before first's schedule start then return first`() { signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, second.id) signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE) - signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis()) + signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC)) val schedule = NotificationProfileSchedule(id = 3L, true, start = 900, daysEnabled = setOf(DayOfWeek.SUNDAY)) val profiles = listOf(first.copy(schedule = schedule), second) - assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday930am.toMillis(), utc), `is`(profiles[0])) + assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday930am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[0])) } @Test @@ -101,41 +102,41 @@ class NotificationProfilesTest { val secondSchedule = NotificationProfileSchedule(id = 4L, true, start = 800, daysEnabled = setOf(DayOfWeek.SUNDAY)) val profiles = listOf(first.copy(schedule = firstSchedule), second.copy(schedule = secondSchedule)) - assertThat("active profile is second", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[1])) + assertThat("active profile is second", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[1])) } @Test fun `when first and second have overlapping schedules and first is created before second and first is manually enabled within overlapping schedule then return first`() { signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id) signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, Long.MAX_VALUE) - signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis()) + signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC)) val firstSchedule = NotificationProfileSchedule(id = 3L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY)) val secondSchedule = NotificationProfileSchedule(id = 4L, true, start = 700, daysEnabled = setOf(DayOfWeek.SUNDAY)) val profiles = listOf(first.copy(schedule = firstSchedule), second.copy(schedule = secondSchedule)) - assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[0])) + assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[0])) } @Test fun `when profile is manually enabled for set time after schedule end and now is after schedule end but before manual then return profile`() { signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id) - signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday930am.toMillis()) - signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis()) + signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday930am.toMillis(ZoneOffset.UTC)) + signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC)) val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, end = 845, daysEnabled = setOf(DayOfWeek.SUNDAY)) val profiles = listOf(first.copy(schedule = schedule)) - assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(), utc), `is`(profiles[0])) + assertThat("active profile is first", NotificationProfiles.getActiveProfile(profiles, sunday9am.toMillis(ZoneOffset.UTC), utc), `is`(profiles[0])) } @Test fun `when profile is manually enabled for set time before schedule end and now is after manual but before schedule end then return null`() { signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_PROFILE, first.id) - signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday9am.toMillis()) - signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis()) + signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_ENABLED_UNTIL, sunday9am.toMillis(ZoneOffset.UTC)) + signalStore.dataSet.putLong(NotificationProfileValues.KEY_MANUALLY_DISABLED_AT, sunday830am.toMillis(ZoneOffset.UTC)) val schedule = NotificationProfileSchedule(id = 3L, true, start = 700, end = 1000, daysEnabled = setOf(DayOfWeek.SUNDAY)) val profiles = listOf(first.copy(schedule = schedule)) - assertThat("active profile is null", NotificationProfiles.getActiveProfile(profiles, sunday930am.toMillis(), utc), nullValue()) + assertThat("active profile is null", NotificationProfiles.getActiveProfile(profiles, sunday930am.toMillis(ZoneOffset.UTC), utc), nullValue()) } }