From 5e496c6dbd4f3e8a8dfd8ad8c394cb5af469b066 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20G=C3=B6ransson?= Date: Mon, 23 Dec 2024 17:11:37 +0100 Subject: [PATCH] Add support for blocking and disconnecting text in notification --- .../lib/model/NotificationAction.kt | 2 + .../lib/model/NotificationTunnelState.kt | 4 +- .../TunnelStateNotificationAction.kt | 6 +- .../TunnelStateNotificationProvider.kt | 64 ++++++------------- 4 files changed, 26 insertions(+), 50 deletions(-) diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/NotificationAction.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/NotificationAction.kt index 141fe739f5a1..3eb4cf119a5c 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/NotificationAction.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/NotificationAction.kt @@ -11,6 +11,8 @@ sealed interface NotificationAction { data object Disconnect : Tunnel + data object Unblock : Tunnel + data object Cancel : Tunnel data object Dismiss : Tunnel diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/NotificationTunnelState.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/NotificationTunnelState.kt index 3ca573a839ca..4c24c87068d0 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/NotificationTunnelState.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/NotificationTunnelState.kt @@ -7,14 +7,14 @@ sealed interface NotificationTunnelState { data object Connected : NotificationTunnelState - data object Reconnecting : NotificationTunnelState + data object Blocking : NotificationTunnelState data object Disconnecting : NotificationTunnelState sealed interface Error : NotificationTunnelState { data object DeviceOffline : Error - data object Blocking : Error + data object Blocked : Error data object VpnPermissionDenied : Error diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/tunnelstate/TunnelStateNotificationAction.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/tunnelstate/TunnelStateNotificationAction.kt index f836cbcd1b68..4eb2656470e6 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/tunnelstate/TunnelStateNotificationAction.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/tunnelstate/TunnelStateNotificationAction.kt @@ -48,8 +48,8 @@ private fun NotificationTunnelState.contentTitleResourceId(context: Context): St } } NotificationTunnelState.Disconnecting -> context.getString(R.string.disconnecting) - NotificationTunnelState.Reconnecting -> context.getString(R.string.reconnecting) - NotificationTunnelState.Error.Blocking -> context.getString(R.string.blocking_internet) + NotificationTunnelState.Blocking -> context.getString(R.string.blocking) + NotificationTunnelState.Error.Blocked -> context.getString(R.string.blocking_internet) is NotificationTunnelState.Error.Critical -> context.getString(R.string.critical_error) NotificationTunnelState.Error.DeviceOffline -> context.getString(R.string.blocking_internet_device_offline) @@ -93,6 +93,7 @@ fun NotificationAction.Tunnel.titleResource() = is NotificationAction.Tunnel.RequestVpnProfile -> R.string.connect NotificationAction.Tunnel.Disconnect -> R.string.disconnect NotificationAction.Tunnel.Dismiss -> R.string.dismiss + NotificationAction.Tunnel.Unblock -> R.string.unblock } fun NotificationAction.Tunnel.toKey() = @@ -101,6 +102,7 @@ fun NotificationAction.Tunnel.toKey() = is NotificationAction.Tunnel.RequestVpnProfile -> KEY_REQUEST_VPN_PROFILE NotificationAction.Tunnel.Cancel, NotificationAction.Tunnel.Disconnect, + NotificationAction.Tunnel.Unblock, NotificationAction.Tunnel.Dismiss -> KEY_DISCONNECT_ACTION } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/tunnelstate/TunnelStateNotificationProvider.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/tunnelstate/TunnelStateNotificationProvider.kt index cb589096d974..c2127d2a0cc6 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/tunnelstate/TunnelStateNotificationProvider.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/tunnelstate/TunnelStateNotificationProvider.kt @@ -1,14 +1,9 @@ package net.mullvad.mullvadvpn.service.notifications.tunnelstate import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine -import kotlinx.coroutines.flow.distinctUntilChanged -import kotlinx.coroutines.flow.filterIsInstance -import kotlinx.coroutines.flow.map -import kotlinx.coroutines.flow.onStart import kotlinx.coroutines.flow.stateIn import net.mullvad.mullvadvpn.lib.model.ActionAfterDisconnect import net.mullvad.mullvadvpn.lib.model.DeviceState @@ -36,22 +31,16 @@ class TunnelStateNotificationProvider( internal val notificationId = NotificationId(2) override val notifications: StateFlow> = - combine( - connectionProxy.tunnelState, - connectionProxy.tunnelState.actionAfterDisconnect().distinctUntilChanged(), - deviceRepository.deviceState, - ) { tunnelState, actionAfterDisconnect, deviceState -> + combine(connectionProxy.tunnelState, deviceRepository.deviceState) { + tunnelState, + deviceState -> if ( deviceState is DeviceState.LoggedOut && tunnelState is TunnelState.Disconnected ) { return@combine NotificationUpdate.Cancel(notificationId) } val notificationTunnelState = - tunnelState( - tunnelState, - actionAfterDisconnect, - vpnPermissionRepository.invoke().leftOrNull(), - ) + tunnelState(tunnelState, vpnPermissionRepository.invoke().leftOrNull()) return@combine NotificationUpdate.Notify( notificationId, @@ -67,36 +56,19 @@ class TunnelStateNotificationProvider( private fun tunnelState( tunnelState: TunnelState, - actionAfterDisconnect: ActionAfterDisconnect?, prepareError: PrepareError?, - ): NotificationTunnelState = - tunnelState.toNotificationTunnelState(actionAfterDisconnect, prepareError) + ): NotificationTunnelState = tunnelState.toNotificationTunnelState(prepareError) - private fun Flow.actionAfterDisconnect(): Flow = - filterIsInstance() - .map { it.actionAfterDisconnect } - .onStart { emit(null) } - - private fun TunnelState.toNotificationTunnelState( - actionAfterDisconnect: ActionAfterDisconnect?, - prepareError: PrepareError?, - ) = + private fun TunnelState.toNotificationTunnelState(prepareError: PrepareError?) = when (this) { is TunnelState.Disconnected -> NotificationTunnelState.Disconnected(prepareError) - is TunnelState.Connecting -> { - if (actionAfterDisconnect == ActionAfterDisconnect.Reconnect) { - NotificationTunnelState.Reconnecting - } else { - NotificationTunnelState.Connecting + is TunnelState.Connecting -> NotificationTunnelState.Connecting + is TunnelState.Disconnecting -> + when (actionAfterDisconnect) { + ActionAfterDisconnect.Reconnect -> NotificationTunnelState.Connecting + ActionAfterDisconnect.Block -> NotificationTunnelState.Blocking + ActionAfterDisconnect.Nothing -> NotificationTunnelState.Disconnecting } - } - is TunnelState.Disconnecting -> { - if (actionAfterDisconnect == ActionAfterDisconnect.Reconnect) { - NotificationTunnelState.Reconnecting - } else { - NotificationTunnelState.Disconnecting - } - } is TunnelState.Connected -> NotificationTunnelState.Connected is TunnelState.Error -> toNotificationTunnelState() } @@ -106,14 +78,14 @@ class TunnelStateNotificationProvider( return when { cause is ErrorStateCause.IsOffline && errorState.isBlocking -> NotificationTunnelState.Error.DeviceOffline - cause is ErrorStateCause.InvalidDnsServers -> NotificationTunnelState.Error.Blocking + cause is ErrorStateCause.InvalidDnsServers -> NotificationTunnelState.Error.Blocked cause is ErrorStateCause.OtherLegacyAlwaysOnApp -> NotificationTunnelState.Error.LegacyLockdown cause is ErrorStateCause.NotPrepared -> NotificationTunnelState.Error.VpnPermissionDenied cause is ErrorStateCause.OtherAlwaysOnApp -> NotificationTunnelState.Error.AlwaysOnVpn(cause.appName) - errorState.isBlocking -> NotificationTunnelState.Error.Blocking + errorState.isBlocking -> NotificationTunnelState.Error.Blocked else -> NotificationTunnelState.Error.Critical } } @@ -129,14 +101,14 @@ class TunnelStateNotificationProvider( } } NotificationTunnelState.Disconnecting -> NotificationAction.Tunnel.Connect - NotificationTunnelState.Connected, - NotificationTunnelState.Error.Blocking -> NotificationAction.Tunnel.Disconnect + NotificationTunnelState.Connected -> NotificationAction.Tunnel.Disconnect NotificationTunnelState.Connecting -> NotificationAction.Tunnel.Cancel - NotificationTunnelState.Reconnecting -> NotificationAction.Tunnel.Cancel is NotificationTunnelState.Error.Critical, - NotificationTunnelState.Error.DeviceOffline, NotificationTunnelState.Error.VpnPermissionDenied, is NotificationTunnelState.Error.AlwaysOnVpn, NotificationTunnelState.Error.LegacyLockdown -> NotificationAction.Tunnel.Dismiss + NotificationTunnelState.Error.Blocked, + NotificationTunnelState.Blocking, + NotificationTunnelState.Error.DeviceOffline -> NotificationAction.Tunnel.Unblock } }