diff --git a/AnkiDroid/src/main/AndroidManifest.xml b/AnkiDroid/src/main/AndroidManifest.xml index 650b25f2e0b9..711b8177d98a 100644 --- a/AnkiDroid/src/main/AndroidManifest.xml +++ b/AnkiDroid/src/main/AndroidManifest.xml @@ -450,6 +450,12 @@ + + + + + NotificationService.triggerNotificationFor(this)); diff --git a/AnkiDroid/src/main/java/com/ichi2/anki/receiver/TimeZoneChangeReceiver.kt b/AnkiDroid/src/main/java/com/ichi2/anki/receiver/TimeZoneChangeReceiver.kt new file mode 100644 index 000000000000..7d7164f412e0 --- /dev/null +++ b/AnkiDroid/src/main/java/com/ichi2/anki/receiver/TimeZoneChangeReceiver.kt @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2022 Prateek Singh + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 3 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A + * PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * this program. If not, see . + */ + +package com.ichi2.anki.receiver + +import android.content.BroadcastReceiver +import android.content.Context +import android.content.Intent +import android.content.IntentFilter +import com.ichi2.anki.NotificationDatastore +import com.ichi2.anki.NotificationHelper +import com.ichi2.libanki.utils.TimeManager +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import timber.log.Timber +import java.util.* + +/** + * Broadcast receiver to listen timezone change of user. + * Changes the notification triggering time when user timezone changes. + * */ +class TimeZoneChangeReceiver : BroadcastReceiver() { + + override fun onReceive(context: Context, intent: Intent) { + Timber.d("TimeZoneChangeReceiver Started...") + + CoroutineScope(Dispatchers.Default).launch { + val notificationDatastore = NotificationDatastore.getInstance(context) + + val oldTimezone: String = notificationDatastore.getString(TIMEZONE_KEY, "null") + val newTimezone: String = TimeZone.getDefault().id + val now = TimeManager.time.intTimeMS() + + /** + * Get the current offset according to given TimeZone. + * */ + fun getOffsetFromNow(timezone: String) = TimeZone.getTimeZone(timezone).getOffset(now) + + if (oldTimezone != "null" || getOffsetFromNow(oldTimezone) == getOffsetFromNow(newTimezone)) { + Timber.d("No Timezone changed found...") + return@launch + } + + Timber.d("Timezone changed...") + // Change the timezone to new timezone and recalculate the notification according to new time zone. + notificationDatastore.putStringAsync(TIMEZONE_KEY, newTimezone) + + val oldCurrTimeMS = getZonedCurrTimeMS(oldTimezone) + val newCurrTimeMS = getZonedCurrTimeMS(newTimezone) + val timeDiffMS = oldCurrTimeMS - newCurrTimeMS + + // Calibrate notification time. + NotificationHelper(context).calibrateNotificationTime(newCurrTimeMS, timeDiffMS) + } + } + + companion object { + private const val TIMEZONE_KEY = "TIMEZONE" + + /** + * Registers timezone change receiver on app start. + * */ + fun registerTimeZoneChangeReceiver(context: Context, receiver: BroadcastReceiver) { + Timber.d("Registering Timezone change receiver...") + + val filter = IntentFilter(Intent.ACTION_TIMEZONE_CHANGED) + context.registerReceiver(receiver, filter) + } + + /** + * Get current time according the timezone of user. + * @return epoch time in milliseconds + * */ + fun getZonedCurrTimeMS(zoneId: String): Long { + val currTimeMS = TimeManager.time.intTimeMS() + val offset = TimeZone.getTimeZone(zoneId).getOffset(currTimeMS) + return currTimeMS + offset + } + } +}