diff --git a/app/build.gradle b/app/build.gradle
index c34c6dc7..343ea2f9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -17,8 +17,8 @@ android {
minSdkVersion 26
targetSdkVersion 36
- versionCode 60
- versionName "1.24.0"
+ versionCode 61
+ versionName "1.25.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
diff --git a/app/src/main/java/io/heckel/ntfy/app/Application.kt b/app/src/main/java/io/heckel/ntfy/app/Application.kt
index da9219ea..4cce58e3 100644
--- a/app/src/main/java/io/heckel/ntfy/app/Application.kt
+++ b/app/src/main/java/io/heckel/ntfy/app/Application.kt
@@ -10,6 +10,7 @@ import io.heckel.ntfy.util.Log
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.launch
class Application : Application() {
val ioScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
@@ -34,11 +35,28 @@ class Application : Application() {
val connectivityManager = getSystemService(CONNECTIVITY_SERVICE) as ConnectivityManager
connectivityManager.registerDefaultNetworkCallback(object : ConnectivityManager.NetworkCallback() {
override fun onAvailable(network: Network) {
- SubscriberServiceManager.refresh(this@Application)
+ // Force reconnect of all WebSocket/JSON connections so they're rebound to the new
+ // default network. This catches Wi-Fi <-> cellular handoffs and similar transitions
+ // where the underlying socket is bound to a network that's no longer the default.
+ // Without this, broken connections would only be detected via the (potentially
+ // long) ping/pong timeout.
+ Log.i(TAG, "Default network available ($network); forcing reconnect of all connections")
+ ioScope.launch {
+ repository.getSubscriptions()
+ .map { it.baseUrl }
+ .distinct()
+ .forEach { repository.incrementConnectionForceReconnectVersion(it) }
+ SubscriberServiceManager.refresh(this@Application)
+ }
}
override fun onLost(network: Network) {
+ Log.i(TAG, "Default network lost ($network); refreshing subscriber service")
SubscriberServiceManager.refresh(this@Application)
}
})
}
+
+ companion object {
+ private const val TAG = "NtfyApplication"
+ }
}
diff --git a/app/src/main/java/io/heckel/ntfy/util/HttpUtil.kt b/app/src/main/java/io/heckel/ntfy/util/HttpUtil.kt
index c4ac9c7f..a20a64f9 100644
--- a/app/src/main/java/io/heckel/ntfy/util/HttpUtil.kt
+++ b/app/src/main/java/io/heckel/ntfy/util/HttpUtil.kt
@@ -46,12 +46,24 @@ object HttpUtil {
/**
* Client for WebSocket connections.
- * No read timeout, 1 minute ping interval, 10s connect timeout.
+ * No read timeout, 5 minute ping interval, 10s connect timeout.
+ *
+ * Dead connections are normally caught by one of two faster mechanisms:
+ * 1. Device-side network changes (Wi-Fi <-> cellular, network drop/return) are
+ * detected instantly by Application.registerNetworkCallback's onAvailable
+ * handler, which bumps connectionForceReconnectVersion to force a reconnect.
+ * 2. Server-side failures (crash, restart, server's own pong timeout) surface as
+ * TCP FIN/RST and are detected instantly via OkHttp's onClosed/onFailure.
+ *
+ * The 5-minute client ping is only a fallback for the rare case where neither of
+ * the above fires: silent server hangs, NAT eviction, asymmetric routing breaks, etc.
+ * We use a long interval so the modem can fully power down between pings, which is
+ * the dominant battery factor for the foreground service.
*/
suspend fun wsClient(context: Context, baseUrl: String): OkHttpClient {
return emptyClientBuilder(context, baseUrl)
.readTimeout(0, TimeUnit.MILLISECONDS)
- .pingInterval(1, TimeUnit.MINUTES) // Technically not necessary, the server also pings us
+ .pingInterval(5, TimeUnit.MINUTES)
.connectTimeout(10, TimeUnit.SECONDS)
.build()
}
diff --git a/app/src/main/res/values-et/strings.xml b/app/src/main/res/values-et/strings.xml
index c0639a4a..d704095a 100644
--- a/app/src/main/res/values-et/strings.xml
+++ b/app/src/main/res/values-et/strings.xml
@@ -40,7 +40,7 @@
Kuulame saabuvaid teavitusi
loome uuesti ühendust …
Tee korda
- Tellimuste teenus
+ Taustateenus
Küsi hiljem
Katkesta
Tellimuse andmete uuendamine ei õnnestunud: %1$s
@@ -462,8 +462,23 @@
Taasta algväärtused
Sisesta korrektne teenuse võrguaadress, nt https://ntfy.toredomeen.com
Ühendus on katkenud
- Ühendus %1$s teenusega toimib vaid %2$d minuti(t)
- Ühendus %1$d serveriga toimib vaid %2$d minuti(t)
+ Ühendus %1$s teenusega toimib vaid %2$d minuti(t). Palun kontrolli seadme võrguühenduse toimimist.
+ Ühendus %1$d serveriga toimib vaid %2$d minuti(t). Palun kontrolli seadme võrguühenduse toimimist.
Tukasta %1$dt
Ära näita iialgi
+ Ühenduse hoiatused
+ Sa pole võrgus :(
+ Hoiata ühenduse katkemisel
+ Ära iialgi hoiata, kui ntfy server pole leitav
+ Hoiata, kui ntfy server pole leitav enam, kui 5 minuti jooksul
+ Hoiata, kui ntfy server pole leitav enam, kui 15 minuti jooksul
+ Hoiata, kui ntfy server pole leitav enam, kui 1 tunni jooksul
+ Hoiata, kui ntfy server pole leitav enam, kui 3 tunni jooksul
+ Hoiata, kui ntfy server pole leitav enam, kui 12 tunni jooksul
+ Mitte kunagi
+ 5 minuti möödumisel
+ 15 minuti möödumisel
+ 1 tunni möödumisel
+ 3 tunni möödumisel
+ 12 tunni möödumisel
diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml
index f8bc7a9d..ae6eed2a 100644
--- a/app/src/main/res/values-pt-rBR/strings.xml
+++ b/app/src/main/res/values-pt-rBR/strings.xml
@@ -16,7 +16,7 @@
reconectando …
Prioridade alta
Prioridade máxima
- Serviço de Inscrição
+ Inscrição em background
Aguardando recepção de notificações
Inscrito em tópicos de entrega instantânea
Inscrito em um tópico de entrega instantânea
@@ -354,8 +354,8 @@
Certificado adicionado
Certificado removido
Notificação de alerta de conexão
- Não foi possível conectar à %1$s por mais de %2$d minutos
- Não foi possível conectar aos servidores %1$d por mais de %2$d minutos
+ Não foi possível conectar à %1$s por mais de %2$d minutos. Verifique sua conexão de rede.
+ Não foi possível conectar aos servidores %1$d por mais de %2$d minutos. Verifique sua conexão de rede.
Adiar %1$dh
Nunca mostrar
Erro de conexão
@@ -472,4 +472,19 @@
Alerta: Este certificado ainda não é válido.
URL inválida
Não foi possível carregar certificado: %1$s
+ Alertas de conexão
+ Você está offline
+ Alertar quando desconectado
+ Nunca notificar quando o servidor ntfy não puder ser atingido
+ Notificar se o servidor ntfy não puder ser atingido por mais que 5 minutos
+ Notificar se o servidor ntfy não puder ser atingido por mais que 15 minutos
+ Notificar se o servidor ntfy não puder ser atingido por mais que 1 hora
+ Notificar se o servidor ntfy não puder ser atingido por mais que 3 horas
+ Notificar se o servidor ntfy não puder ser atingido por mais que 12 horas
+ Nunca
+ Depois de 5 minutos
+ Depois de 15 minutos
+ Depois de 1 hora
+ Depois de 3 horas
+ Depois de 12 horas
diff --git a/fastlane/metadata/android/en-US/changelog/NEXT.txt b/fastlane/metadata/android/en-US/changelog/61.txt
similarity index 74%
rename from fastlane/metadata/android/en-US/changelog/NEXT.txt
rename to fastlane/metadata/android/en-US/changelog/61.txt
index e09a06af..27e619d6 100644
--- a/fastlane/metadata/android/en-US/changelog/NEXT.txt
+++ b/fastlane/metadata/android/en-US/changelog/61.txt
@@ -1,6 +1,7 @@
Features:
* Add configurable "Alert when connection is lost" setting (#1665, #1662, #1652, #1655, thanks to @tintamarre, @sjozs, @TheRealOne78, and @DAE51D for reporting)
* Suppress connection alerts and stop foreground service when there is no network (ntfy-android#165, thanks to @tintamarre for the contribution)
+* Improve battery life by increasing WebSocket client ping interval from 1 min to 5 min, and reconnect instantly on Wi-Fi/cellular/VPN transitions (ntfy-android#113, thanks to @ftilde for the investigation)
Bug fixes + maintenance:
* Undo automatic phone number linking for numbers in message body (ntfy-android#170, thanks to @acortelyou for the contribution)