diff --git a/app/src/main/java/io/heckel/ntfy/db/Repository.kt b/app/src/main/java/io/heckel/ntfy/db/Repository.kt
index 6d024ecd..4333180d 100644
--- a/app/src/main/java/io/heckel/ntfy/db/Repository.kt
+++ b/app/src/main/java/io/heckel/ntfy/db/Repository.kt
@@ -447,17 +447,17 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
fun setConnectionAlertSeconds(seconds: Long) {
sharedPrefs.edit {
putLong(SHARED_PREFS_CONNECTION_ALERT_SECONDS, seconds)
- putLong(SHARED_PREFS_CONNECTION_ALERT_SNOOZE_UNTIL, 0L)
+ putLong(SHARED_PREFS_CONNECTION_ALERT_SNOOZE_UNTIL_TIME, 0L)
}
}
- fun getConnectionAlertSnoozeUntil(): Long {
- return sharedPrefs.getLong(SHARED_PREFS_CONNECTION_ALERT_SNOOZE_UNTIL, 0L)
+ fun getConnectionAlertSnoozeUntilTime(): Long {
+ return sharedPrefs.getLong(SHARED_PREFS_CONNECTION_ALERT_SNOOZE_UNTIL_TIME, 0L)
}
- fun setConnectionAlertSnoozeUntil(timeMillis: Long) {
+ fun setConnectionAlertSnoozeUntilTime(timeMillis: Long) {
sharedPrefs.edit {
- putLong(SHARED_PREFS_CONNECTION_ALERT_SNOOZE_UNTIL, timeMillis)
+ putLong(SHARED_PREFS_CONNECTION_ALERT_SNOOZE_UNTIL_TIME, timeMillis)
}
}
@@ -650,13 +650,13 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
const val SHARED_PREFS_INSISTENT_MAX_PRIORITY_ENABLED = "InsistentMaxPriority"
const val SHARED_PREFS_RECORD_LOGS_ENABLED = "RecordLogs"
const val SHARED_PREFS_MESSAGE_BAR_ENABLED = "MessageBarEnabled"
- const val SHARED_PREFS_BATTERY_OPTIMIZATIONS_REMIND_TIME = "BatteryOptimizationsRemindTime"
- const val SHARED_PREFS_WEBSOCKET_REMIND_TIME = "JsonStreamRemindTime" // "Use WebSocket" banner (used to be JSON stream deprecation banner)
- const val SHARED_PREFS_WEBSOCKET_RECONNECT_REMIND_TIME = "WebSocketReconnectRemindTime"
+ const val SHARED_PREFS_BATTERY_OPTIMIZATIONS_REMIND_TIME = "BatteryOptimizationsRemindTime" // Timestamp as millis
+ const val SHARED_PREFS_WEBSOCKET_REMIND_TIME = "JsonStreamRemindTime" // "Use WebSocket" banner (used to be JSON stream deprecation banner), timestamp as millis
+ const val SHARED_PREFS_WEBSOCKET_RECONNECT_REMIND_TIME = "WebSocketReconnectRemindTime" // Timestamp as millis
const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL" // Legacy key required for migration to DefaultBaseURL
const val SHARED_PREFS_DEFAULT_BASE_URL = "DefaultBaseURL"
const val SHARED_PREFS_CONNECTION_ALERT_SECONDS = "ConnectionAlertSeconds"
- const val SHARED_PREFS_CONNECTION_ALERT_SNOOZE_UNTIL = "ConnectionAlertSnoozeUntil"
+ const val SHARED_PREFS_CONNECTION_ALERT_SNOOZE_UNTIL_TIME = "ConnectionAlertSnoozeUntilTime" // Timestamp in millis
const val SHARED_PREFS_LAST_TOPICS = "LastTopics"
private const val LAST_TOPICS_COUNT = 3
@@ -668,12 +668,14 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
const val MUTED_UNTIL_FOREVER = 1L
const val MUTED_UNTIL_TOMORROW = 2L
- private const val ONE_MB = 1024 * 1024L
+ private const val ONE_MB_BYTES = 1024 * 1024L
const val AUTO_DOWNLOAD_NEVER = 0L // Values must match values.xml
const val AUTO_DOWNLOAD_ALWAYS = 1L
- const val AUTO_DOWNLOAD_DEFAULT = ONE_MB
+ const val AUTO_DOWNLOAD_DEFAULT = ONE_MB_BYTES
+
+ private const val ONE_HOUR_SECONDS = 60 * 60L
+ private const val ONE_DAY_SECONDS = 24 * ONE_HOUR_SECONDS
- private const val ONE_DAY_SECONDS = 24 * 60 * 60L
const val AUTO_DELETE_USE_GLOBAL = -1L // Values must match values.xml
const val AUTO_DELETE_NEVER = 0L
const val AUTO_DELETE_ONE_DAY_SECONDS = ONE_DAY_SECONDS
@@ -687,11 +689,11 @@ class Repository(private val sharedPrefs: SharedPreferences, database: Database)
const val INSISTENT_MAX_PRIORITY_ENABLED = 1 // 0 = Disabled (but not needed in code)
const val CONNECTION_ALERT_NEVER = 0L
- const val CONNECTION_ALERT_FIVE_MINUTES = 5 * 60L
- const val CONNECTION_ALERT_FIFTEEN_MINUTES = 15 * 60L
- const val CONNECTION_ALERT_ONE_HOUR = 60 * 60L
- const val CONNECTION_ALERT_THREE_HOURS = 3 * 60 * 60L
- const val CONNECTION_ALERT_TWELVE_HOURS = 12 * 60 * 60L
+ const val CONNECTION_ALERT_FIVE_MINUTES_SECONDS = 5 * 60L
+ const val CONNECTION_ALERT_FIFTEEN_MINUTES_SECONDS = 15 * 60L
+ const val CONNECTION_ALERT_ONE_HOUR_SECONDS = ONE_HOUR_SECONDS
+ const val CONNECTION_ALERT_THREE_HOURS_SECONDS = 3 * ONE_HOUR_SECONDS
+ const val CONNECTION_ALERT_TWELVE_HOURS_SECONDS = 12 * ONE_HOUR_SECONDS
const val CONNECTION_ALERT_DEFAULT = CONNECTION_ALERT_NEVER
const val CONNECTION_PROTOCOL_JSONHTTP = "jsonhttp"
diff --git a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt
index 94a37d76..0377a177 100644
--- a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt
+++ b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt
@@ -11,7 +11,6 @@ import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.pm.ServiceInfo
-import io.heckel.ntfy.util.isNetworkAvailable
import android.os.Build
import android.os.IBinder
import android.os.PowerManager
@@ -29,6 +28,7 @@ import io.heckel.ntfy.ui.Colors
import io.heckel.ntfy.ui.MainActivity
import io.heckel.ntfy.util.HttpUtil
import io.heckel.ntfy.util.Log
+import io.heckel.ntfy.util.isNetworkAvailable
import io.heckel.ntfy.util.shortUrl
import io.heckel.ntfy.util.topicUrl
import kotlinx.coroutines.Dispatchers
@@ -325,7 +325,7 @@ class SubscriberService : Service() {
val now = System.currentTimeMillis()
// Check snooze
- val snoozeUntil = repository.getConnectionAlertSnoozeUntil()
+ val snoozeUntil = repository.getConnectionAlertSnoozeUntilTime()
if (snoozeUntil > now) return
// Check if any connection has been in error for longer than the threshold
@@ -504,10 +504,10 @@ class SubscriberService : Service() {
val notificationManager = context.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
when (intent.action) {
CONNECTION_ALERT_ACTION_DISMISS -> {
- repository.setConnectionAlertSnoozeUntil(System.currentTimeMillis() + CONNECTION_ALERT_DISMISS_SNOOZE_MILLIS)
+ repository.setConnectionAlertSnoozeUntilTime(System.currentTimeMillis() + CONNECTION_ALERT_DISMISS_MILLIS)
}
CONNECTION_ALERT_ACTION_SNOOZE -> {
- repository.setConnectionAlertSnoozeUntil(System.currentTimeMillis() + CONNECTION_ALERT_SNOOZE_DURATION_MILLIS)
+ repository.setConnectionAlertSnoozeUntilTime(System.currentTimeMillis() + CONNECTION_ALERT_SNOOZE_MILLIS)
}
CONNECTION_ALERT_ACTION_NEVER -> {
repository.setConnectionAlertSeconds(Repository.CONNECTION_ALERT_NEVER)
@@ -528,6 +528,9 @@ class SubscriberService : Service() {
const val SERVICE_START_WORKER_VERSION = BuildConfig.VERSION_CODE
const val SERVICE_START_WORKER_WORK_NAME_PERIODIC = "NtfyAutoRestartWorkerPeriodic" // Do not change!
+ private const val ONE_HOUR_SECONDS = 60 * 60L
+ private const val ONE_HOUR_MILLIS = ONE_HOUR_SECONDS * 1000L
+
private const val WAKE_LOCK_TAG = "SubscriberService:lock"
private const val NOTIFICATION_CHANNEL_ID = "ntfy-subscriber"
private const val NOTIFICATION_CONNECTION_ALERT_CHANNEL_ID = "ntfy-connection-alert"
@@ -535,10 +538,10 @@ class SubscriberService : Service() {
private const val NOTIFICATION_SERVICE_ID = 2586
private const val NOTIFICATION_RECEIVED_WAKELOCK_TIMEOUT_MILLIS = 10 * 60 * 1000L /*10 minutes*/
- private const val NOTIFICATION_CONNECTION_ALERT_ID = 2587
+ const val NOTIFICATION_CONNECTION_ALERT_ID = 2587
private const val CONNECTION_ALERT_SNOOZE_HOURS = 8
- private const val CONNECTION_ALERT_SNOOZE_DURATION_MILLIS = CONNECTION_ALERT_SNOOZE_HOURS * 60 * 60 * 1000L
- private const val CONNECTION_ALERT_DISMISS_SNOOZE_MILLIS = 1 * 60 * 60 * 1000L /*1 hour*/
+ private const val CONNECTION_ALERT_SNOOZE_MILLIS = CONNECTION_ALERT_SNOOZE_HOURS * ONE_HOUR_MILLIS
+ private const val CONNECTION_ALERT_DISMISS_MILLIS = ONE_HOUR_MILLIS
private const val CONNECTION_ALERT_ACTION_DISMISS = "io.heckel.ntfy.CONNECTION_ALERT_DISMISS"
private const val CONNECTION_ALERT_ACTION_SNOOZE = "io.heckel.ntfy.CONNECTION_ALERT_SNOOZE"
private const val CONNECTION_ALERT_ACTION_NEVER = "io.heckel.ntfy.CONNECTION_ALERT_NEVER"
diff --git a/app/src/main/java/io/heckel/ntfy/service/SubscriberServiceManager.kt b/app/src/main/java/io/heckel/ntfy/service/SubscriberServiceManager.kt
index a8fe62bc..f577b10c 100644
--- a/app/src/main/java/io/heckel/ntfy/service/SubscriberServiceManager.kt
+++ b/app/src/main/java/io/heckel/ntfy/service/SubscriberServiceManager.kt
@@ -3,11 +3,11 @@ package io.heckel.ntfy.service
import android.app.NotificationManager
import android.content.Context
import android.content.Intent
-import io.heckel.ntfy.util.isNetworkAvailable
import androidx.core.content.ContextCompat
import androidx.work.*
import io.heckel.ntfy.app.Application
import io.heckel.ntfy.util.Log
+import io.heckel.ntfy.util.isNetworkAvailable
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
@@ -65,7 +65,7 @@ class SubscriberServiceManager(private val context: Context) {
if (!hasNetwork) {
app.repository.clearConnectionDetails()
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
- notificationManager.cancel(NOTIFICATION_CONNECTION_ALERT_ID)
+ notificationManager.cancel(SubscriberService.NOTIFICATION_CONNECTION_ALERT_ID)
}
Intent(context, SubscriberService::class.java).also {
context.stopService(it)
@@ -79,8 +79,6 @@ class SubscriberServiceManager(private val context: Context) {
companion object {
const val TAG = "NtfySubscriberMgr"
const val WORK_NAME_ONCE = "ServiceStartWorkerOnce"
- private const val NOTIFICATION_CONNECTION_ALERT_ID = 2587 // Same as SubscriberService
-
fun refresh(context: Context) {
val manager = SubscriberServiceManager(context)
diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt
index 6083ae70..4a1ceb87 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt
@@ -11,7 +11,6 @@ import android.content.Intent
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.Network
-import io.heckel.ntfy.util.isNetworkAvailable
import android.os.Build
import android.os.Bundle
import android.provider.Settings
@@ -67,6 +66,7 @@ import io.heckel.ntfy.util.displayName
import io.heckel.ntfy.util.formatDateShort
import io.heckel.ntfy.util.isDarkThemeOn
import io.heckel.ntfy.util.isIgnoringBatteryOptimizations
+import io.heckel.ntfy.util.isNetworkAvailable
import io.heckel.ntfy.util.maybeSplitTopicUrl
import io.heckel.ntfy.util.randomSubscriptionId
import io.heckel.ntfy.util.shortUrl
diff --git a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
index 3ba01e0d..629aa922 100644
--- a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
+++ b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt
@@ -10,9 +10,7 @@ import android.os.Build
import android.os.Bundle
import android.provider.Settings
import android.provider.Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM
-import android.text.TextUtils
import android.view.View
-import android.widget.Button
import android.widget.Toast
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
@@ -42,7 +40,6 @@ import kotlinx.coroutines.launch
import okhttp3.RequestBody.Companion.toRequestBody
import java.text.SimpleDateFormat
import java.util.*
-import java.util.concurrent.TimeUnit
/**
* Main settings
@@ -344,11 +341,11 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere
when (pref.value.toLongOrNull() ?: repository.getConnectionAlertSeconds()) {
Repository.CONNECTION_ALERT_NEVER -> getString(R.string.settings_advanced_connection_alert_summary_never)
30L -> "Alert after 30 seconds (testing)"
- Repository.CONNECTION_ALERT_FIVE_MINUTES -> getString(R.string.settings_advanced_connection_alert_summary_five_minutes)
- Repository.CONNECTION_ALERT_FIFTEEN_MINUTES -> getString(R.string.settings_advanced_connection_alert_summary_fifteen_minutes)
- Repository.CONNECTION_ALERT_ONE_HOUR -> getString(R.string.settings_advanced_connection_alert_summary_one_hour)
- Repository.CONNECTION_ALERT_THREE_HOURS -> getString(R.string.settings_advanced_connection_alert_summary_three_hours)
- Repository.CONNECTION_ALERT_TWELVE_HOURS -> getString(R.string.settings_advanced_connection_alert_summary_twelve_hours)
+ Repository.CONNECTION_ALERT_FIVE_MINUTES_SECONDS -> getString(R.string.settings_advanced_connection_alert_summary_five_minutes)
+ Repository.CONNECTION_ALERT_FIFTEEN_MINUTES_SECONDS -> getString(R.string.settings_advanced_connection_alert_summary_fifteen_minutes)
+ Repository.CONNECTION_ALERT_ONE_HOUR_SECONDS -> getString(R.string.settings_advanced_connection_alert_summary_one_hour)
+ Repository.CONNECTION_ALERT_THREE_HOURS_SECONDS -> getString(R.string.settings_advanced_connection_alert_summary_three_hours)
+ Repository.CONNECTION_ALERT_TWELVE_HOURS_SECONDS -> getString(R.string.settings_advanced_connection_alert_summary_twelve_hours)
else -> getString(R.string.settings_advanced_connection_alert_summary_never) // Must match default const
}
}
diff --git a/app/src/main/java/io/heckel/ntfy/util/Util.kt b/app/src/main/java/io/heckel/ntfy/util/Util.kt
index 7ef04d84..3c857c8e 100644
--- a/app/src/main/java/io/heckel/ntfy/util/Util.kt
+++ b/app/src/main/java/io/heckel/ntfy/util/Util.kt
@@ -54,13 +54,6 @@ import kotlin.math.abs
import kotlin.math.absoluteValue
import androidx.core.net.toUri
-// We check for any active network, not specifically for internet connectivity,
-// because the ntfy server may be on a LAN without internet access.
-fun isNetworkAvailable(context: Context): Boolean {
- val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
- return connectivityManager.activeNetwork != null
-}
-
fun topicUrl(baseUrl: String, topic: String) = "${baseUrl}/${topic}"
fun topicUrlUp(baseUrl: String, topic: String) = "${baseUrl}/${topic}?up=1" // UnifiedPush
fun topicUrlJson(baseUrl: String, topic: String, since: String) = "${topicUrl(baseUrl, topic)}/json?since=$since"
@@ -554,3 +547,10 @@ fun deriveNotificationId(baseUrl: String, topic: String, sequenceId: String): In
val hash = composite.hashCode()
return if (hash == 0 || hash == Int.MIN_VALUE) 1 else abs(hash)
}
+
+// We check for any active network, not specifically for internet connectivity,
+// because the ntfy server may be on a LAN without internet access.
+fun isNetworkAvailable(context: Context): Boolean {
+ val connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
+ return connectivityManager.activeNetwork != null
+}
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 3e7fb3c2..c0782c20 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -372,19 +372,6 @@
After one week
After one month
After 3 months
- Connection lost alert
- Never alert when connection is lost
- Alert after 5 minutes without connection
- Alert after 15 minutes without connection
- Alert after 1 hour without connection
- Alert after 3 hours without connection
- Alert after 12 hours without connection
- Never
- After 5 minutes
- After 15 minutes
- After 1 hour
- After 3 hours
- After 12 hours
Keep alerting for highest priority
Max priority notifications continuously alert until dismissed
Max priority notifications only alert once
@@ -430,6 +417,19 @@
Restore successful
Restore failed: %1$s
Advanced
+ Alert when disconnected
+ Never notify when the ntfy server cannot be reached
+ Notify if the ntfy server cannot be reached for more than 5 minutes
+ Notify if the ntfy server cannot be reached for more than 15 minutes
+ Notify if the ntfy server cannot be reached for more than 1 hour
+ Notify if the ntfy server cannot be reached for more than 3 hours
+ Notify if the ntfy server cannot be reached for more than 12 hours
+ Never
+ After 5 minutes
+ After 15 minutes
+ After 1 hour
+ After 3 hours
+ After 12 hours
Broadcast messages
Apps can receive incoming notifications as broadcasts
Apps cannot receive notifications as broadcasts