diff options
| author | David Göransson <david.goransson@mullvad.net> | 2024-11-18 14:23:05 +0100 |
|---|---|---|
| committer | David Göransson <david.goransson@mullvad.net> | 2024-11-27 09:00:18 +0100 |
| commit | 1bb7fc7ebaa2837ed9f9d28c2bb5a6fd91033988 (patch) | |
| tree | a83565926fb753a2dd9fd24f0e2bd07262e4507e /android/service | |
| parent | 0d155385e1cb7075012bd270de0398d83a438bc5 (diff) | |
| download | mullvadvpn-1bb7fc7ebaa2837ed9f9d28c2bb5a6fd91033988.tar.xz mullvadvpn-1bb7fc7ebaa2837ed9f9d28c2bb5a6fd91033988.zip | |
Handle legacy always-on vpn profiles
Co-authored-by: Jonatan Rhodin <jonatan.rhodin@mullvad.net>
Diffstat (limited to 'android/service')
3 files changed, 51 insertions, 49 deletions
diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/ForegroundNotificationManager.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/ForegroundNotificationManager.kt index 5745377254..cf324e6023 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/ForegroundNotificationManager.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/ForegroundNotificationManager.kt @@ -2,9 +2,9 @@ package net.mullvad.mullvadvpn.service.notifications import android.app.Service import android.content.pm.ServiceInfo -import android.net.VpnService import android.os.Build import co.touchlab.kermit.Logger +import net.mullvad.mullvadvpn.lib.common.util.prepareVpnSafe import net.mullvad.mullvadvpn.lib.model.Notification import net.mullvad.mullvadvpn.lib.model.NotificationChannel import net.mullvad.mullvadvpn.lib.model.NotificationTunnelState @@ -40,7 +40,7 @@ class ForegroundNotificationManager( private fun notifyForeground(tunnelStateNotification: Notification.Tunnel) { val androidNotification = tunnelStateNotification.toNotification(vpnService) - if (VpnService.prepare(vpnService) != null) { + if (vpnService.prepareVpnSafe().isLeft()) { // Got connect/disconnect intent, but we don't have permission to go in foreground. // tunnel state will return permission and we will eventually get stopped by system. Logger.i("Did not start foreground: VPN permission not granted") @@ -65,7 +65,7 @@ class ForegroundNotificationManager( private val defaultNotification = Notification.Tunnel( NotificationChannel.TunnelUpdates.id, - NotificationTunnelState.Disconnected(true), + NotificationTunnelState.Disconnected(null), emptyList(), false, ) 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 c66839ddc5..f836cbcd1b 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 @@ -6,18 +6,19 @@ import android.content.Intent import androidx.core.app.NotificationCompat import net.mullvad.mullvadvpn.lib.common.constant.KEY_CONNECT_ACTION import net.mullvad.mullvadvpn.lib.common.constant.KEY_DISCONNECT_ACTION -import net.mullvad.mullvadvpn.lib.common.constant.KEY_REQUEST_VPN_PERMISSION +import net.mullvad.mullvadvpn.lib.common.constant.KEY_REQUEST_VPN_PROFILE import net.mullvad.mullvadvpn.lib.common.constant.MAIN_ACTIVITY_CLASS import net.mullvad.mullvadvpn.lib.common.util.SdkUtils import net.mullvad.mullvadvpn.lib.model.Notification import net.mullvad.mullvadvpn.lib.model.NotificationAction import net.mullvad.mullvadvpn.lib.model.NotificationTunnelState +import net.mullvad.mullvadvpn.lib.model.PrepareError import net.mullvad.mullvadvpn.service.R internal fun Notification.Tunnel.toNotification(context: Context) = NotificationCompat.Builder(context, channelId.value) .setContentIntent(contentIntent(context)) - .setContentTitle(context.getString(state.contentTitleResourceId())) + .setContentTitle(state.contentTitleResourceId(context)) .setSmallIcon(R.drawable.small_logo_white) .apply { actions.forEach { addAction(it.toCompatAction(context)) } } .setOngoing(ongoing) @@ -35,37 +36,41 @@ private fun Notification.Tunnel.contentIntent(context: Context): PendingIntent { return PendingIntent.getActivity(context, 1, intent, SdkUtils.getSupportedPendingIntentFlags()) } -private fun NotificationTunnelState.contentTitleResourceId(): Int = +private fun NotificationTunnelState.contentTitleResourceId(context: Context): String = when (this) { - NotificationTunnelState.Connected -> R.string.connected - NotificationTunnelState.Connecting -> R.string.connecting + NotificationTunnelState.Connected -> context.getString(R.string.connected) + NotificationTunnelState.Connecting -> context.getString(R.string.connecting) is NotificationTunnelState.Disconnected -> { - if (this.hasVpnPermission) { - R.string.disconnected - } else { - R.string.disconnected_vpn_permission_error + when (prepareError) { + is PrepareError.NotPrepared -> + context.getString(R.string.disconnected_vpn_permission_error) + else -> context.getString(R.string.disconnected) } } - NotificationTunnelState.Disconnecting -> R.string.disconnecting - NotificationTunnelState.Reconnecting -> R.string.reconnecting - NotificationTunnelState.Error.Blocking -> R.string.blocking_internet - is NotificationTunnelState.Error.Critical -> R.string.critical_error - NotificationTunnelState.Error.DeviceOffline -> R.string.blocking_internet_device_offline + NotificationTunnelState.Disconnecting -> context.getString(R.string.disconnecting) + NotificationTunnelState.Reconnecting -> context.getString(R.string.reconnecting) + NotificationTunnelState.Error.Blocking -> 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) NotificationTunnelState.Error.VpnPermissionDenied -> - R.string.vpn_permission_error_notification_title - NotificationTunnelState.Error.AlwaysOnVpn -> R.string.always_on_vpn_error_notification_title + context.getString(R.string.vpn_permission_error_notification_title) + is NotificationTunnelState.Error.AlwaysOnVpn -> + context.getString(R.string.always_on_vpn_error_notification_title, appName) + NotificationTunnelState.Error.LegacyLockdown -> + context.getString(R.string.legacy_always_on_vpn_error_notification_title) } internal fun NotificationAction.Tunnel.toCompatAction(context: Context): NotificationCompat.Action { val pendingIntent = - if (this is NotificationAction.Tunnel.RequestPermission) { + if (this is NotificationAction.Tunnel.RequestVpnProfile) { val intent = Intent().apply { setClassName(context.packageName, MAIN_ACTIVITY_CLASS) addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - setAction(KEY_REQUEST_VPN_PERMISSION) + setAction(KEY_REQUEST_VPN_PROFILE) } PendingIntent.getActivity(context, 1, intent, SdkUtils.getSupportedPendingIntentFlags()) @@ -85,7 +90,7 @@ fun NotificationAction.Tunnel.titleResource() = when (this) { NotificationAction.Tunnel.Cancel -> R.string.cancel NotificationAction.Tunnel.Connect, - NotificationAction.Tunnel.RequestPermission -> R.string.connect + is NotificationAction.Tunnel.RequestVpnProfile -> R.string.connect NotificationAction.Tunnel.Disconnect -> R.string.disconnect NotificationAction.Tunnel.Dismiss -> R.string.dismiss } @@ -93,7 +98,7 @@ fun NotificationAction.Tunnel.titleResource() = fun NotificationAction.Tunnel.toKey() = when (this) { NotificationAction.Tunnel.Connect -> KEY_CONNECT_ACTION - NotificationAction.Tunnel.RequestPermission -> KEY_REQUEST_VPN_PERMISSION + is NotificationAction.Tunnel.RequestVpnProfile -> KEY_REQUEST_VPN_PROFILE NotificationAction.Tunnel.Cancel, NotificationAction.Tunnel.Disconnect, 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 2068f1adff..e9c52bba48 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 @@ -19,15 +19,16 @@ import net.mullvad.mullvadvpn.lib.model.NotificationChannelId import net.mullvad.mullvadvpn.lib.model.NotificationId import net.mullvad.mullvadvpn.lib.model.NotificationTunnelState import net.mullvad.mullvadvpn.lib.model.NotificationUpdate +import net.mullvad.mullvadvpn.lib.model.PrepareError import net.mullvad.mullvadvpn.lib.model.TunnelState import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy import net.mullvad.mullvadvpn.lib.shared.DeviceRepository -import net.mullvad.mullvadvpn.lib.shared.VpnPermissionRepository +import net.mullvad.mullvadvpn.lib.shared.VpnProfileUseCase import net.mullvad.mullvadvpn.service.notifications.NotificationProvider class TunnelStateNotificationProvider( connectionProxy: ConnectionProxy, - vpnPermissionRepository: VpnPermissionRepository, + vpnPermissionRepository: VpnProfileUseCase, deviceRepository: DeviceRepository, channelId: NotificationChannelId, scope: CoroutineScope, @@ -49,8 +50,7 @@ class TunnelStateNotificationProvider( tunnelState( tunnelState, actionAfterDisconnect, - vpnPermissionRepository.hasVpnPermission(), - vpnPermissionRepository.getAlwaysOnVpnAppName(), + vpnPermissionRepository.prepareVpn().leftOrNull(), ) return@combine NotificationUpdate.Notify( @@ -68,14 +68,9 @@ class TunnelStateNotificationProvider( private fun tunnelState( tunnelState: TunnelState, actionAfterDisconnect: ActionAfterDisconnect?, - hasVpnPermission: Boolean, - alwaysOnVpnPermissionName: String?, + prepareError: PrepareError?, ): NotificationTunnelState = - tunnelState.toNotificationTunnelState( - actionAfterDisconnect, - hasVpnPermission, - alwaysOnVpnPermissionName, - ) + tunnelState.toNotificationTunnelState(actionAfterDisconnect, prepareError) private fun Flow<TunnelState>.actionAfterDisconnect(): Flow<ActionAfterDisconnect?> = filterIsInstance<TunnelState.Disconnecting>() @@ -84,11 +79,10 @@ class TunnelStateNotificationProvider( private fun TunnelState.toNotificationTunnelState( actionAfterDisconnect: ActionAfterDisconnect?, - hasVpnPermission: Boolean, - alwaysOnVpnPermissionName: String?, + prepareError: PrepareError?, ) = when (this) { - is TunnelState.Disconnected -> NotificationTunnelState.Disconnected(hasVpnPermission) + is TunnelState.Disconnected -> NotificationTunnelState.Disconnected(prepareError) is TunnelState.Connecting -> { if (actionAfterDisconnect == ActionAfterDisconnect.Reconnect) { NotificationTunnelState.Reconnecting @@ -104,20 +98,21 @@ class TunnelStateNotificationProvider( } } is TunnelState.Connected -> NotificationTunnelState.Connected - is TunnelState.Error -> toNotificationTunnelState(alwaysOnVpnPermissionName) + is TunnelState.Error -> toNotificationTunnelState() } - private fun TunnelState.Error.toNotificationTunnelState( - alwaysOnVpnPermissionName: String? - ): NotificationTunnelState.Error { + private fun TunnelState.Error.toNotificationTunnelState(): NotificationTunnelState.Error { val cause = errorState.cause return when { cause is ErrorStateCause.IsOffline && errorState.isBlocking -> NotificationTunnelState.Error.DeviceOffline cause is ErrorStateCause.InvalidDnsServers -> NotificationTunnelState.Error.Blocking - cause is ErrorStateCause.VpnPermissionDenied -> - alwaysOnVpnPermissionName?.let { NotificationTunnelState.Error.AlwaysOnVpn } - ?: NotificationTunnelState.Error.VpnPermissionDenied + 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 else -> NotificationTunnelState.Error.Critical } @@ -126,10 +121,11 @@ class TunnelStateNotificationProvider( private fun NotificationTunnelState.toAction(): NotificationAction.Tunnel = when (this) { is NotificationTunnelState.Disconnected -> { - if (this.hasVpnPermission) { - NotificationAction.Tunnel.Connect - } else { - NotificationAction.Tunnel.RequestPermission + when (prepareError) { + is PrepareError.OtherAlwaysOnApp, + is PrepareError.OtherLegacyAlwaysOnVpn, + null -> NotificationAction.Tunnel.Connect + is PrepareError.NotPrepared -> NotificationAction.Tunnel.RequestVpnProfile } } NotificationTunnelState.Disconnecting -> NotificationAction.Tunnel.Connect @@ -140,6 +136,7 @@ class TunnelStateNotificationProvider( is NotificationTunnelState.Error.Critical, NotificationTunnelState.Error.DeviceOffline, NotificationTunnelState.Error.VpnPermissionDenied, - NotificationTunnelState.Error.AlwaysOnVpn -> NotificationAction.Tunnel.Dismiss + is NotificationTunnelState.Error.AlwaysOnVpn, + NotificationTunnelState.Error.LegacyLockdown -> NotificationAction.Tunnel.Dismiss } } |
