@@ -12,19 +12,22 @@ import com.tailscale.ipn.R
12
12
import com.tailscale.ipn.UninitializedApp.Companion.notificationManager
13
13
import com.tailscale.ipn.ui.model.Health
14
14
import com.tailscale.ipn.ui.model.Health.UnhealthyState
15
+ import com.tailscale.ipn.ui.model.Ipn
15
16
import com.tailscale.ipn.ui.util.set
16
17
import com.tailscale.ipn.util.TSLog
17
18
import kotlinx.coroutines.CoroutineScope
18
19
import kotlinx.coroutines.FlowPreview
19
20
import kotlinx.coroutines.flow.MutableStateFlow
20
21
import kotlinx.coroutines.flow.StateFlow
22
+ import kotlinx.coroutines.flow.combine
21
23
import kotlinx.coroutines.flow.debounce
22
24
import kotlinx.coroutines.flow.distinctUntilChanged
23
25
import kotlinx.coroutines.launch
24
26
25
27
@OptIn(FlowPreview ::class )
26
28
class HealthNotifier (
27
29
healthStateFlow : StateFlow <Health .State ?>,
30
+ ipnStateFlow : StateFlow <Ipn .State >,
28
31
scope : CoroutineScope ,
29
32
) {
30
33
companion object {
@@ -45,11 +48,22 @@ class HealthNotifier(
45
48
scope.launch {
46
49
healthStateFlow
47
50
.distinctUntilChanged { old, new -> old?.Warnings ?.count() == new?.Warnings ?.count() }
51
+ .combine(ipnStateFlow, ::Pair )
48
52
.debounce(5000 )
49
- .collect { health ->
50
- TSLog .d(TAG , " Health updated: ${health?.Warnings ?.keys?.sorted()} " )
51
- health?.Warnings ?.let {
52
- notifyHealthUpdated(it.values.mapNotNull { it }.toTypedArray())
53
+ .collect { pair ->
54
+ val health = pair.first
55
+ val ipnState = pair.second
56
+ // When the client is Stopped, no warnings should get added, and any warnings added
57
+ // previously should be removed.
58
+ if (ipnState == Ipn .State .Stopped ) {
59
+ TSLog .d(TAG , " Ignoring and dropping all pre-existing health messages in the Stopped state" )
60
+ dropAllWarnings()
61
+ return @collect
62
+ } else {
63
+ TSLog .d(TAG , " Health updated: ${health?.Warnings ?.keys?.sorted()} " )
64
+ health?.Warnings ?.let {
65
+ notifyHealthUpdated(it.values.mapNotNull { it }.toTypedArray())
66
+ }
53
67
}
54
68
}
55
69
}
@@ -65,8 +79,11 @@ class HealthNotifier(
65
79
val removedByNewDependency: MutableSet <UnhealthyState > = mutableSetOf ()
66
80
val isWarmingUp = warnings.any { it.WarnableCode == " warming-up" }
67
81
68
- // / Checks if there is any warning in `warningsBeforeAdd` that needs to be removed because the new warning `w`
69
- // / is listed as a dependency of a warning already in `warningsBeforeAdd`, and removes it.
82
+ /* *
83
+ * dropDependenciesForAddedWarning checks if there is any warning in `warningsBeforeAdd` that
84
+ * needs to be removed because the new warning `w` is listed as a dependency of a warning
85
+ * already in `warningsBeforeAdd`, and removes it.
86
+ */
70
87
fun dropDependenciesForAddedWarning (w : UnhealthyState ) {
71
88
for (warning in warningsBeforeAdd) {
72
89
warning.DependsOn ?.let {
@@ -112,6 +129,14 @@ class HealthNotifier(
112
129
this .updateIcon()
113
130
}
114
131
132
+ /* *
133
+ * Sets the icon displayed to represent the overall health state.
134
+ *
135
+ * - If there are any high severity warnings, or warnings that affect internet connectivity,
136
+ * a warning icon is displayed.
137
+ * - If there are any other kind of warnings, an info icon is displayed.
138
+ * - If there are no warnings at all, no icon is set.
139
+ */
115
140
private fun updateIcon () {
116
141
if (currentWarnings.value.isEmpty()) {
117
142
this .currentIcon.set(null )
@@ -145,6 +170,16 @@ class HealthNotifier(
145
170
notificationManager.notify(code.hashCode(), notification)
146
171
}
147
172
173
+ /* *
174
+ * Removes all warnings currently displayed, including any system notifications, and
175
+ * updates the icon (causing it to be set to null since the set of warnings is empty).
176
+ */
177
+ private fun dropAllWarnings () {
178
+ removeNotifications(this .currentWarnings.value)
179
+ this .currentWarnings.set(emptySet())
180
+ this .updateIcon()
181
+ }
182
+
148
183
private fun removeNotifications (warnings : Set <UnhealthyState >) {
149
184
TSLog .d(TAG , " Removing notifications for $warnings " )
150
185
for (warning in warnings) {
0 commit comments