diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt
index d76c0a1ae3..2b972a6d14 100644
--- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt
+++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/settings/ResourceUsageScreen.kt
@@ -39,6 +39,7 @@ import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
+import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
@@ -51,6 +52,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.vitorpamplona.amethyst.Amethyst
@@ -65,6 +67,7 @@ import com.vitorpamplona.amethyst.service.resourceusage.ResourceUsageReportAssem
import com.vitorpamplona.amethyst.service.resourceusage.ResourceUsageReportAssembler.Companion.formatDurationMs
import com.vitorpamplona.amethyst.service.resourceusage.UsageSummary
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
+import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.navigation.routes.routeToMessage
import com.vitorpamplona.amethyst.ui.navigation.topbars.TopBarWithBackButton
import com.vitorpamplona.amethyst.ui.screen.loggedIn.AccountViewModel
@@ -140,6 +143,7 @@ fun ResourceUsageScreen(
}
SubsystemSection(weekSummary)
ActivitySection(weekSummary)
+ AlwaysOnServiceSection(weekSummary, nav)
MemorySection(memory)
SendReportSection(accountViewModel, nav, loaded, today, memory)
}
@@ -310,10 +314,6 @@ private fun ActivitySection(s: UsageSummary) {
SettingsDivider()
MetricRow(R.string.resource_usage_tor, formatDurationMs(s.torMs))
}
- if (s.alwaysOnMs > 0) {
- SettingsDivider()
- MetricRow(R.string.resource_usage_always_on, formatDurationMs(s.alwaysOnMs))
- }
if (s.callMs > 0) {
SettingsDivider()
MetricRow(R.string.resource_usage_calls, formatDurationMs(s.callMs))
@@ -400,6 +400,55 @@ private fun MemorySection(memory: MemorySnapshot?) {
}
}
+/**
+ * Decision-support card for the always-on notification service — the one
+ * background consumer users can directly turn off. Shows what the service
+ * actually costs in the last 7 days (uptime, the relay connections it holds
+ * while the app is closed, and the measured background battery drain) and
+ * links straight to the setting that controls it.
+ */
+@Composable
+private fun AlwaysOnServiceSection(
+ s: UsageSummary,
+ nav: INav,
+) {
+ if (s.alwaysOnMs <= 0) return
+ val starts = s.alwaysOnStarts.toInt()
+ SettingsSection(R.string.resource_usage_alwayson_section) {
+ Column(
+ modifier = Modifier.padding(16.dp),
+ verticalArrangement = Arrangement.spacedBy(12.dp),
+ ) {
+ Text(
+ text = stringRes(R.string.resource_usage_alwayson_explanation),
+ style = MaterialTheme.typography.bodyMedium,
+ color = MaterialTheme.colorScheme.onSurfaceVariant,
+ )
+ }
+ MetricRow(
+ R.string.resource_usage_alwayson_uptime,
+ "${formatDurationMs(s.alwaysOnMs)} · ${pluralStringResource(R.plurals.resource_usage_alwayson_starts, starts, starts)}",
+ )
+ SettingsDivider()
+ MetricRow(
+ R.string.resource_usage_alwayson_bg_relay,
+ formatConnHours(s.relayConnMsMobileBg + s.relayConnMsWifiBg),
+ )
+ if (s.batteryDrainBg > 0) {
+ SettingsDivider()
+ MetricRow(R.string.resource_usage_alwayson_battery, "${s.batteryDrainBg}%")
+ }
+ Column(modifier = Modifier.padding(horizontal = 8.dp, vertical = 4.dp)) {
+ TextButton(
+ onClick = { nav.nav(Route.NotificationSettings) },
+ modifier = Modifier.align(Alignment.End),
+ ) {
+ Text(stringRes(R.string.resource_usage_alwayson_settings_button))
+ }
+ }
+ }
+}
+
@Composable
private fun SendReportSection(
accountViewModel: AccountViewModel,
diff --git a/amethyst/src/main/res/values/strings.xml b/amethyst/src/main/res/values/strings.xml
index e3e5e34e8e..df93f3236c 100644
--- a/amethyst/src/main/res/values/strings.xml
+++ b/amethyst/src/main/res/values/strings.xml
@@ -3213,11 +3213,20 @@
Remote signatures
Proof-of-work mining
Tor uptime
- Always-on notification service
Time in calls
Time in audio rooms
Location listening
Battery used (in app / background)
+ Background notification service
+ Keeps connections to your relays open while the app is closed, so notifications arrive without Google’s push servers. While enabled, this is usually the largest background battery cost. If battery matters more to you than instant notifications, you can change the delivery method or turn it off.
+ Running time
+
+ - %1$d start
+ - %1$d starts
+
+ Relay connections held while closed
+ Battery drained meanwhile (whole device)
+ Change notification settings
Data by feature (7 days)
Relay sync
Images