diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 8da078e3..6311e266 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -71,6 +71,10 @@
android:name=".notification.NotificationReplyReceiver"
android:exported="false" />
+
+
= Build.VERSION_CODES.O) {
diff --git a/app/src/main/java/com/m57/hermescontrol/notification/StopKeepConnectedReceiver.kt b/app/src/main/java/com/m57/hermescontrol/notification/StopKeepConnectedReceiver.kt
new file mode 100644
index 00000000..e1d0e787
--- /dev/null
+++ b/app/src/main/java/com/m57/hermescontrol/notification/StopKeepConnectedReceiver.kt
@@ -0,0 +1,26 @@
+package com.m57.hermescontrol.notification
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import com.m57.hermescontrol.data.local.AuthManager
+
+/**
+ * Handles the "Turn off" action on the ongoing background notification:
+ * disables "Stay connected in background" and lets the controller retire the
+ * lease/service.
+ */
+class StopKeepConnectedReceiver : BroadcastReceiver() {
+ companion object {
+ const val ACTION_STOP_KEEP_CONNECTED = "com.m57.hermescontrol.ACTION_STOP_KEEP_CONNECTED"
+ }
+
+ override fun onReceive(
+ context: Context,
+ intent: Intent,
+ ) {
+ if (intent.action != ACTION_STOP_KEEP_CONNECTED) return
+ AuthManager.setKeepConnectedInBackground(false)
+ BackgroundConnectionController.default.onKeepConnectedDisabled()
+ }
+}
diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml
index 4246ab8e..6a328570 100644
--- a/app/src/main/res/values-ar/strings.xml
+++ b/app/src/main/res/values-ar/strings.xml
@@ -129,6 +129,7 @@
Hermes
بانتظار ردود Hermes
متصل في الخلفية
+إيقاف
جارٍ الاتصال…
في انتظار الشبكة
جارٍ إعادة الاتصال
diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml
index 4a3e9465..fabaaf82 100644
--- a/app/src/main/res/values-ko/strings.xml
+++ b/app/src/main/res/values-ko/strings.xml
@@ -126,6 +126,7 @@
헤르메스
헤르메스 응답 대기 중
백그라운드에서 연결됨
+ 끄기
연결 중…
네트워크 대기 중
재연결 중
diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml
index 032fd94e..67868a7b 100644
--- a/app/src/main/res/values-zh/strings.xml
+++ b/app/src/main/res/values-zh/strings.xml
@@ -129,6 +129,7 @@
Hermes
等待 Hermes 回复
在后台保持连接
+ 关闭
正在连接…
等待网络连接
正在重新连接
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 87ac0e5d..00ed6cd8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -152,6 +152,7 @@
Hermes
Waiting for Hermes replies
Connected in background
+ Turn off
Connecting…
Waiting for network
Reconnecting
diff --git a/app/src/test/java/com/m57/hermescontrol/notification/BackgroundConnectionControllerTest.kt b/app/src/test/java/com/m57/hermescontrol/notification/BackgroundConnectionControllerTest.kt
index 2a641154..209cb199 100644
--- a/app/src/test/java/com/m57/hermescontrol/notification/BackgroundConnectionControllerTest.kt
+++ b/app/src/test/java/com/m57/hermescontrol/notification/BackgroundConnectionControllerTest.kt
@@ -407,4 +407,55 @@ class BackgroundConnectionControllerTest {
unmockkObject(NetworkMonitor)
}
}
+
+ @Test
+ fun testOnKeepConnectedDisabled_whenBackgrounded_releasesLeaseAndStopsService() {
+ var leaseReleased = false
+ var serviceStopped = false
+ val snapshot =
+ BackgroundConnectionSnapshot(
+ appInForeground = false,
+ keepConnectedOptIn = false,
+ pendingReply = false,
+ isEligibleForConnection = true,
+ status = ConnectionStatus.CONNECTED,
+ )
+ val controller =
+ BackgroundConnectionController(
+ snapshotProvider = { snapshot },
+ releaseLease = { leaseReleased = true },
+ requestServiceStop = { serviceStopped = true },
+ )
+
+ controller.onKeepConnectedDisabled()
+
+ assertTrue(leaseReleased)
+ assertTrue(serviceStopped)
+ }
+
+ @Test
+ fun testOnKeepConnectedDisabled_whenReplyPending_keepsServiceAndRefreshesNotification() {
+ var serviceStopped = false
+ var refreshed: BackgroundNotificationState? = null
+ val snapshot =
+ BackgroundConnectionSnapshot(
+ appInForeground = false,
+ keepConnectedOptIn = false,
+ pendingReply = true,
+ isEligibleForConnection = true,
+ status = ConnectionStatus.CONNECTED,
+ )
+ val controller =
+ BackgroundConnectionController(
+ snapshotProvider = { snapshot },
+ releaseLease = {},
+ requestServiceStop = { serviceStopped = true },
+ onNotificationStateChanged = { refreshed = it },
+ )
+
+ controller.onKeepConnectedDisabled()
+
+ assertFalse(serviceStopped)
+ assertEquals(BackgroundNotificationState.WaitingForReplies, refreshed)
+ }
}