From 3775c58d23cab2070d2652e038eade428ae65d34 Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Fri, 3 Apr 2026 15:17:47 -0400 Subject: [PATCH] Manual review --- .../main/java/io/heckel/ntfy/db/Repository.kt | 36 ++++++++++--------- .../heckel/ntfy/service/SubscriberService.kt | 17 +++++---- .../ntfy/service/SubscriberServiceManager.kt | 6 ++-- .../java/io/heckel/ntfy/ui/MainActivity.kt | 2 +- .../io/heckel/ntfy/ui/SettingsActivity.kt | 13 +++---- app/src/main/java/io/heckel/ntfy/util/Util.kt | 14 ++++---- app/src/main/res/values/strings.xml | 26 +++++++------- 7 files changed, 57 insertions(+), 57 deletions(-) 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