summaryrefslogtreecommitdiffhomepage
path: root/android/app/src
diff options
context:
space:
mode:
authorJonatan Rhodin <jonatan.rhodin@mullvad.net>2025-10-02 08:49:41 +0200
committerJonatan Rhodin <jonatan.rhodin@mullvad.net>2025-10-09 11:02:02 +0200
commit8cfcae2c7d7148d55a4812df420a0aa6a9d4d7d4 (patch)
tree3ccef8b1ff7f1619df798289acad0427a23e7cdc /android/app/src
parentcc3d7a2295765fb47949fc73b8bcf7cb76cea552 (diff)
downloadmullvadvpn-8cfcae2c7d7148d55a4812df420a0aa6a9d4d7d4.tar.xz
mullvadvpn-8cfcae2c7d7148d55a4812df420a0aa6a9d4d7d4.zip
Implement LWO on android
Diffstat (limited to 'android/app/src')
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyRelayItems.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt6
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt1
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt15
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingItem.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemExtensions.kt20
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCase.kt9
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilteredRelayListUseCase.kt11
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/FilterCustomListsRelayItemUseCase.kt19
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Filter.kt7
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Settings.kt2
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModelTest.kt2
15 files changed, 92 insertions, 12 deletions
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyRelayItems.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyRelayItems.kt
index 8e46a555c9..c6c69e088b 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyRelayItems.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/data/DummyRelayItems.kt
@@ -23,6 +23,7 @@ private val DUMMY_RELAY_1 =
ownership = Ownership.Rented,
daita = false,
quic = null,
+ lwo = false,
)
private val DUMMY_RELAY_2 =
RelayItem.Location.Relay(
@@ -36,6 +37,7 @@ private val DUMMY_RELAY_2 =
ownership = Ownership.MullvadOwned,
daita = false,
quic = null,
+ lwo = false,
)
private val DUMMY_RELAY_CITY_1 =
RelayItem.Location.City(
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt
index 508d4af359..eafcb58d3d 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/FilterRow.kt
@@ -57,6 +57,7 @@ fun FilterRow(
is FilterChip.Entry -> EntryFilterChip()
is FilterChip.Exit -> ExitFilterChip()
is FilterChip.Quic -> QuicFilterChip()
+ is FilterChip.Lwo -> LwoFilterChip()
}
}
}
@@ -116,6 +117,11 @@ fun QuicFilterChip() {
)
}
+@Composable
+fun LwoFilterChip() {
+ MullvadFilterChip(text = stringResource(id = R.string.lwo), onRemoveClick = {}, enabled = false)
+}
+
private fun Ownership.stringResources(): Int =
when (this) {
Ownership.MullvadOwned -> R.string.owned
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt
index bc0c52db83..8a5f94d730 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/ObfuscationModeCell.kt
@@ -123,6 +123,7 @@ private fun ObfuscationMode.toTitle() =
ObfuscationMode.Udp2Tcp -> stringResource(id = R.string.upd_over_tcp)
ObfuscationMode.Shadowsocks -> stringResource(id = R.string.shadowsocks)
ObfuscationMode.Quic -> stringResource(id = R.string.quic)
+ ObfuscationMode.Lwo -> stringResource(id = R.string.lwo)
}
@Composable
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt
index 98abee9589..6c404a5bc9 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/component/connectioninfo/FeatureIndicatorsPanel.kt
@@ -131,7 +131,8 @@ private fun FeatureIndicator.text(): String {
FeatureIndicator.SPLIT_TUNNELING -> R.string.split_tunneling
FeatureIndicator.SHADOWSOCKS,
FeatureIndicator.UDP_2_TCP,
- FeatureIndicator.QUIC -> R.string.feature_obfuscation
+ FeatureIndicator.QUIC,
+ FeatureIndicator.LWO -> R.string.feature_obfuscation
FeatureIndicator.LAN_SHARING -> R.string.local_network_sharing
FeatureIndicator.DNS_CONTENT_BLOCKERS -> R.string.dns_content_blockers
FeatureIndicator.CUSTOM_DNS -> R.string.feature_custom_dns
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
index 13b6a518cf..c7074b10a6 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreen.kt
@@ -807,5 +807,6 @@ private fun FeatureIndicator.destination() =
FeatureIndicator.DNS_CONTENT_BLOCKERS,
FeatureIndicator.CUSTOM_DNS,
FeatureIndicator.CUSTOM_MTU,
- FeatureIndicator.QUIC -> VpnSettingsDestination(scrollToFeature = this, isModal = true)
+ FeatureIndicator.QUIC,
+ FeatureIndicator.LWO -> VpnSettingsDestination(scrollToFeature = this, isModal = true)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
index a997b39ad4..1cba4093f1 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt
@@ -121,6 +121,7 @@ import net.mullvad.mullvadvpn.lib.ui.tag.LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_
import net.mullvad.mullvadvpn.lib.ui.tag.LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG
import net.mullvad.mullvadvpn.lib.ui.tag.LAZY_LIST_WIREGUARD_OBFUSCATION_TITLE_TEST_TAG
import net.mullvad.mullvadvpn.lib.ui.tag.LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG
+import net.mullvad.mullvadvpn.lib.ui.tag.WIREGUARD_OBFUSCATION_LWO_CELL_TEST_TAG
import net.mullvad.mullvadvpn.lib.ui.tag.WIREGUARD_OBFUSCATION_OFF_CELL_TEST_TAG
import net.mullvad.mullvadvpn.lib.ui.tag.WIREGUARD_OBFUSCATION_QUIC_CELL_TEST_TAG
import net.mullvad.mullvadvpn.lib.ui.tag.WIREGUARD_OBFUSCATION_SHADOWSOCKS_CELL_TEST_TAG
@@ -479,7 +480,8 @@ fun VpnSettingsContent(
when (initialScrollToFeature) {
FeatureIndicator.UDP_2_TCP,
FeatureIndicator.SHADOWSOCKS,
- FeatureIndicator.QUIC -> VpnSettingItem.ObfuscationHeader::class
+ FeatureIndicator.QUIC,
+ FeatureIndicator.LWO -> VpnSettingItem.ObfuscationHeader::class
FeatureIndicator.LAN_SHARING -> VpnSettingItem.LocalNetworkSharingSetting::class
FeatureIndicator.QUANTUM_RESISTANCE -> VpnSettingItem.QuantumResistanceHeader::class
FeatureIndicator.DNS_CONTENT_BLOCKERS -> VpnSettingItem.DnsContentBlockersHeader::class
@@ -867,6 +869,17 @@ fun VpnSettingsContent(
)
}
+ is VpnSettingItem.ObfuscationItem.Lwo ->
+ item(key = it::class.simpleName) {
+ SelectableCell(
+ title = stringResource(id = R.string.lwo),
+ isSelected = it.selected,
+ modifier = Modifier.animateItem(),
+ testTag = WIREGUARD_OBFUSCATION_LWO_CELL_TEST_TAG,
+ onCellClicked = { onSelectObfuscationMode(ObfuscationMode.Lwo) },
+ )
+ }
+
is VpnSettingItem.QuantumItem ->
item(key = it::class.simpleName + it.quantumResistantState) {
SelectableCell(
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingItem.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingItem.kt
index 3ce6637115..fe3ee1a50a 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingItem.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingItem.kt
@@ -106,6 +106,8 @@ sealed interface VpnSettingItem {
data class Quic(override val selected: Boolean) : ObfuscationItem
+ data class Lwo(override val selected: Boolean) : ObfuscationItem
+
data class Off(override val selected: Boolean) : ObfuscationItem
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt
index 08fafc56c0..d860aa3c21 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt
@@ -209,6 +209,8 @@ data class VpnSettingsUiState(val settings: List<VpnSettingItem>, val isModal: B
VpnSettingItem.ObfuscationItem.Quic(obfuscationMode == ObfuscationMode.Quic)
)
add(VpnSettingItem.Divider)
+ add(VpnSettingItem.ObfuscationItem.Lwo(obfuscationMode == ObfuscationMode.Lwo))
+ add(VpnSettingItem.Divider)
add(VpnSettingItem.ObfuscationItem.Off(obfuscationMode == ObfuscationMode.Off))
add(VpnSettingItem.Spacer)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemExtensions.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemExtensions.kt
index c59b0124c3..182044b6fc 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemExtensions.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/relaylist/RelayItemExtensions.kt
@@ -60,17 +60,18 @@ fun RelayItem.CustomList.filter(
providers: Constraint<Providers>,
daita: Boolean,
quic: Boolean,
+ lwo: Boolean,
ipVersion: Constraint<IpVersion>,
): RelayItem.CustomList {
val newLocations =
locations.mapNotNull {
when (it) {
is RelayItem.Location.Country ->
- it.filter(ownership, providers, daita, quic, ipVersion)
+ it.filter(ownership, providers, daita, quic, lwo, ipVersion)
is RelayItem.Location.City ->
- it.filter(ownership, providers, daita, quic, ipVersion)
+ it.filter(ownership, providers, daita, quic, lwo, ipVersion)
is RelayItem.Location.Relay ->
- it.filter(ownership, providers, daita, quic, ipVersion)
+ it.filter(ownership, providers, daita, quic, lwo, ipVersion)
}
}
return copy(locations = newLocations)
@@ -81,9 +82,10 @@ fun RelayItem.Location.Country.filter(
providers: Constraint<Providers>,
daita: Boolean,
quic: Boolean,
+ lwo: Boolean,
ipVersion: Constraint<IpVersion>,
): RelayItem.Location.Country? {
- val cities = cities.mapNotNull { it.filter(ownership, providers, daita, quic, ipVersion) }
+ val cities = cities.mapNotNull { it.filter(ownership, providers, daita, quic, lwo, ipVersion) }
return if (cities.isNotEmpty()) {
this.copy(cities = cities)
} else {
@@ -96,9 +98,10 @@ private fun RelayItem.Location.City.filter(
providers: Constraint<Providers>,
daita: Boolean,
quic: Boolean,
+ lwo: Boolean,
ipVersion: Constraint<IpVersion>,
): RelayItem.Location.City? {
- val relays = relays.mapNotNull { it.filter(ownership, providers, daita, quic, ipVersion) }
+ val relays = relays.mapNotNull { it.filter(ownership, providers, daita, quic, lwo, ipVersion) }
return if (relays.isNotEmpty()) {
this.copy(relays = relays)
} else {
@@ -109,12 +112,16 @@ private fun RelayItem.Location.City.filter(
private fun RelayItem.Location.Relay.requiredFeatures(
requireDaita: Boolean,
requireQuic: Boolean,
+ requireLwo: Boolean,
ipVersion: Constraint<IpVersion>,
): Boolean =
when {
+ // Can not require LWO and require QUIC at the same time
requireDaita && requireQuic -> daita && quic?.supports(ipVersion) == true
+ requireDaita && requireLwo -> daita && lwo
requireDaita -> daita
requireQuic -> quic?.supports(ipVersion) == true
+ requireLwo -> lwo
else -> true
}
@@ -130,10 +137,11 @@ private fun RelayItem.Location.Relay.filter(
providers: Constraint<Providers>,
daita: Boolean,
quic: Boolean,
+ lwo: Boolean,
ipVersion: Constraint<IpVersion>,
): RelayItem.Location.Relay? =
if (
- requiredFeatures(daita, quic, ipVersion) &&
+ requiredFeatures(daita, quic, lwo, ipVersion) &&
hasOwnership(ownership) &&
hasProvider(providers)
)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCase.kt
index 12ec3a296c..c115d86b2a 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCase.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilterChipUseCase.kt
@@ -11,8 +11,10 @@ import net.mullvad.mullvadvpn.lib.model.Settings
import net.mullvad.mullvadvpn.repository.RelayListFilterRepository
import net.mullvad.mullvadvpn.repository.SettingsRepository
import net.mullvad.mullvadvpn.util.isDaitaAndDirectOnly
+import net.mullvad.mullvadvpn.util.isLwoEnabled
import net.mullvad.mullvadvpn.util.isQuicEnabled
import net.mullvad.mullvadvpn.util.shouldFilterByDaita
+import net.mullvad.mullvadvpn.util.shouldFilterByLwo
import net.mullvad.mullvadvpn.util.shouldFilterByQuic
typealias ModelOwnership = Ownership
@@ -84,6 +86,11 @@ class FilterChipUseCase(
) {
add(FilterChip.Quic)
}
+ if (
+ shouldFilterByLwo(settings?.isLwoEnabled() == true, relayListType = relayListType)
+ ) {
+ add(FilterChip.Lwo)
+ }
}
}
}
@@ -100,4 +107,6 @@ sealed interface FilterChip {
data object Exit : FilterChip
data object Quic : FilterChip
+
+ data object Lwo : FilterChip
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilteredRelayListUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilteredRelayListUseCase.kt
index 2681cfa3ad..eb41e3b918 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilteredRelayListUseCase.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/FilteredRelayListUseCase.kt
@@ -14,8 +14,10 @@ import net.mullvad.mullvadvpn.repository.SettingsRepository
import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository
import net.mullvad.mullvadvpn.util.ipVersionConstraint
import net.mullvad.mullvadvpn.util.isDaitaAndDirectOnly
+import net.mullvad.mullvadvpn.util.isLwoEnabled
import net.mullvad.mullvadvpn.util.isQuicEnabled
import net.mullvad.mullvadvpn.util.shouldFilterByDaita
+import net.mullvad.mullvadvpn.util.shouldFilterByLwo
import net.mullvad.mullvadvpn.util.shouldFilterByQuic
class FilteredRelayListUseCase(
@@ -42,7 +44,12 @@ class FilteredRelayListUseCase(
),
shouldFilterByQuic =
shouldFilterByQuic(
- settings?.isQuicEnabled() == true,
+ isQuicEnabled = settings?.isQuicEnabled() == true,
+ relayListType = relayListType,
+ ),
+ shouldFilterByLwo =
+ shouldFilterByLwo(
+ isLwoEnable = settings?.isLwoEnabled() == true,
relayListType = relayListType,
),
constraintIpVersion = settings?.ipVersionConstraint() ?: Constraint.Any,
@@ -54,6 +61,7 @@ class FilteredRelayListUseCase(
providers: Constraint<Providers>,
shouldFilterByDaita: Boolean,
shouldFilterByQuic: Boolean,
+ shouldFilterByLwo: Boolean,
constraintIpVersion: Constraint<IpVersion>,
) = mapNotNull {
it.filter(
@@ -61,6 +69,7 @@ class FilteredRelayListUseCase(
providers,
shouldFilterByDaita,
shouldFilterByQuic,
+ shouldFilterByLwo,
constraintIpVersion,
)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/FilterCustomListsRelayItemUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/FilterCustomListsRelayItemUseCase.kt
index 6604a76805..d351b7633c 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/FilterCustomListsRelayItemUseCase.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/customlists/FilterCustomListsRelayItemUseCase.kt
@@ -14,8 +14,10 @@ import net.mullvad.mullvadvpn.repository.SettingsRepository
import net.mullvad.mullvadvpn.repository.WireguardConstraintsRepository
import net.mullvad.mullvadvpn.util.ipVersionConstraint
import net.mullvad.mullvadvpn.util.isDaitaAndDirectOnly
+import net.mullvad.mullvadvpn.util.isLwoEnabled
import net.mullvad.mullvadvpn.util.isQuicEnabled
import net.mullvad.mullvadvpn.util.shouldFilterByDaita
+import net.mullvad.mullvadvpn.util.shouldFilterByLwo
import net.mullvad.mullvadvpn.util.shouldFilterByQuic
class FilterCustomListsRelayItemUseCase(
@@ -43,7 +45,12 @@ class FilterCustomListsRelayItemUseCase(
),
quic =
shouldFilterByQuic(
- settings?.isQuicEnabled() == true,
+ isQuicEnabled = settings?.isQuicEnabled() == true,
+ relayListType = relayListType,
+ ),
+ lwo =
+ shouldFilterByLwo(
+ isLwoEnable = settings?.isLwoEnabled() == true,
relayListType = relayListType,
),
ipVersion = settings?.ipVersionConstraint() ?: Constraint.Any,
@@ -55,8 +62,16 @@ class FilterCustomListsRelayItemUseCase(
providers: Constraint<Providers>,
daita: Boolean,
quic: Boolean,
+ lwo: Boolean,
ipVersion: Constraint<IpVersion>,
) = mapNotNull {
- it.filter(ownership, providers, daita = daita, quic = quic, ipVersion = ipVersion)
+ it.filter(
+ ownership,
+ providers,
+ daita = daita,
+ quic = quic,
+ lwo = lwo,
+ ipVersion = ipVersion,
+ )
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Filter.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Filter.kt
index 4fa7ba231c..32dabab1c0 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Filter.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Filter.kt
@@ -16,3 +16,10 @@ fun shouldFilterByQuic(isQuicEnabled: Boolean, relayListType: RelayListType) =
is RelayListType.Multihop ->
isQuicEnabled && relayListType.multihopRelayListType == MultihopRelayListType.ENTRY
}
+
+fun shouldFilterByLwo(isLwoEnable: Boolean, relayListType: RelayListType) =
+ when (relayListType) {
+ RelayListType.Single -> isLwoEnable
+ is RelayListType.Multihop ->
+ isLwoEnable && relayListType.multihopRelayListType == MultihopRelayListType.ENTRY
+ }
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Settings.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Settings.kt
index 4da463ab51..45354bad21 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Settings.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/util/Settings.kt
@@ -22,6 +22,8 @@ fun Settings.isDaitaAndDirectOnly() = isDaitaEnabled() && isDaitaDirectOnly()
fun Settings.isQuicEnabled() = obfuscationSettings.selectedObfuscationMode == ObfuscationMode.Quic
+fun Settings.isLwoEnabled() = obfuscationSettings.selectedObfuscationMode == ObfuscationMode.Lwo
+
fun Settings.ipVersionConstraint() = relaySettings.relayConstraints.wireguardConstraints.ipVersion
fun Settings.isDaitaEnabled() = daitaSettings().enabled
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModelTest.kt
index fc6dcf79c0..100c665781 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/CustomListLocationsViewModelTest.kt
@@ -365,6 +365,7 @@ class CustomListLocationsViewModelTest {
ownership = Ownership.MullvadOwned,
daita = false,
quic = null,
+ lwo = false,
)
),
)
@@ -383,6 +384,7 @@ class CustomListLocationsViewModelTest {
ownership = Ownership.MullvadOwned,
daita = false,
quic = null,
+ lwo = false,
)
}
}