summaryrefslogtreecommitdiffhomepage
path: root/android
diff options
context:
space:
mode:
Diffstat (limited to 'android')
-rw-r--r--android/CHANGELOG.md1
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialogTest.kt14
-rw-r--r--android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt45
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt46
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt16
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/VpnSettingsUiStatePreviewParameterProvider.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreen.kt17
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/state/VpnSettingsUiState.kt3
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt51
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt16
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt7
-rw-r--r--android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt1
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt5
-rw-r--r--android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt10
-rw-r--r--android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/GenericOptions.kt3
-rw-r--r--android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelOptions.kt6
-rw-r--r--android/lib/resource/src/main/res/values-da/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-de/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-es/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-fi/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-fr/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-it/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-ja/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-ko/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-my/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-nb/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-nl/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-pl/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-pt/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-ru/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-sv/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-th/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-tr/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-zh-rCN/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values-zh-rTW/strings.xml1
-rw-r--r--android/lib/resource/src/main/res/values/strings.xml2
-rw-r--r--android/lib/talpid/src/main/kotlin/net/mullvad/talpid/util/UnderlyingConnectivityStatusResolver.kt6
-rw-r--r--android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt6
39 files changed, 205 insertions, 73 deletions
diff --git a/android/CHANGELOG.md b/android/CHANGELOG.md
index 462f9cdb03..2bbb8e5f91 100644
--- a/android/CHANGELOG.md
+++ b/android/CHANGELOG.md
@@ -25,6 +25,7 @@ Line wrap the file at 100 chars. Th
### Added
- Prompt password manager to store new account number on account creation.
- Add the ability to force the ip version used to connect to a relay.
+- Add the ability to disable IPv6 in the tunnel.
### Changed
- Disable Wireguard port setting when a obfuscation is selected since it is not used when an
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialogTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialogTest.kt
index 56bdc562fd..44cc53a256 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialogTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialogTest.kt
@@ -21,9 +21,9 @@ class DnsDialogTest {
DnsDialogViewState(
input = "",
validationError = null,
- isLocal = false,
isAllowLanEnabled = false,
index = null,
+ isIpv6Enabled = true,
)
private fun ComposeContext.initDialog(
@@ -48,7 +48,7 @@ class DnsDialogTest {
fun testDnsDialogLanWarningShownWhenLanTrafficDisabledAndLocalAddressUsed() =
composeExtension.use {
// Arrange
- initDialog(defaultState.copy(isAllowLanEnabled = false, isLocal = true))
+ initDialog(defaultState.copy(isAllowLanEnabled = false, input = localIpAddress))
// Assert
onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertExists()
@@ -58,7 +58,7 @@ class DnsDialogTest {
fun testDnsDialogLanWarningNotShownWhenLanTrafficEnabledAndLocalAddressUsed() =
composeExtension.use {
// Arrange
- initDialog(defaultState.copy(isAllowLanEnabled = true, isLocal = true))
+ initDialog(defaultState.copy(isAllowLanEnabled = true, input = localIpAddress))
// Assert
onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
@@ -68,7 +68,7 @@ class DnsDialogTest {
fun testDnsDialogLanWarningNotShownWhenLanTrafficEnabledAndNonLocalAddressUsed() =
composeExtension.use {
// Arrange
- initDialog(defaultState.copy(isAllowLanEnabled = true, isLocal = false))
+ initDialog(defaultState.copy(isAllowLanEnabled = true, input = publicIpAddress))
// Assert
onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
@@ -78,7 +78,7 @@ class DnsDialogTest {
fun testDnsDialogLanWarningNotShownWhenLanTrafficDisabledAndNonLocalAddressUsed() =
composeExtension.use {
// Arrange
- initDialog(defaultState.copy(isAllowLanEnabled = false, isLocal = false))
+ initDialog(defaultState.copy(isAllowLanEnabled = false, input = publicIpAddress))
// Assert
onNodeWithText(LOCAL_DNS_SERVER_WARNING).assertDoesNotExist()
@@ -105,7 +105,7 @@ class DnsDialogTest {
// Arrange
initDialog(
defaultState.copy(
- input = "192.168.0.1",
+ input = localIpAddress,
validationError = ValidationError.DuplicateAddress,
)
)
@@ -120,5 +120,7 @@ class DnsDialogTest {
"\"Local Network Sharing\" under VPN settings."
private const val invalidIpAddress = "300.300.300.300"
+ private const val localIpAddress = "192.168.0.1"
+ private const val publicIpAddress = "1.1.1.1"
}
}
diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
index 073c81b6f8..75d4f20f6e 100644
--- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
+++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/VpnSettingsScreenTest.kt
@@ -74,6 +74,7 @@ class VpnSettingsScreenTest {
navigateToUdp2TcpSettings: () -> Unit = {},
onToggleAutoStartAndConnectOnBoot: (Boolean) -> Unit = {},
onSelectDeviceIpVersion: (Constraint<IpVersion>) -> Unit = {},
+ onToggleIpv6Toggle: (Boolean) -> Unit = {},
) {
setContentWithTheme {
VpnSettingsScreen(
@@ -106,6 +107,7 @@ class VpnSettingsScreenTest {
navigateToUdp2TcpSettings = navigateToUdp2TcpSettings,
onToggleAutoStartAndConnectOnBoot = onToggleAutoStartAndConnectOnBoot,
onSelectDeviceIpVersion = onSelectDeviceIpVersion,
+ onToggleIpv6Toggle = onToggleIpv6Toggle,
)
}
}
@@ -154,9 +156,9 @@ class VpnSettingsScreenTest {
isCustomDnsEnabled = true,
customDnsItems =
listOf(
- CustomDnsItem(address = DUMMY_DNS_ADDRESS, false),
- CustomDnsItem(address = DUMMY_DNS_ADDRESS_2, false),
- CustomDnsItem(address = DUMMY_DNS_ADDRESS_3, false),
+ CustomDnsItem(address = DUMMY_DNS_ADDRESS, false, false),
+ CustomDnsItem(address = DUMMY_DNS_ADDRESS_2, false, false),
+ CustomDnsItem(address = DUMMY_DNS_ADDRESS_3, false, false),
),
)
)
@@ -176,7 +178,8 @@ class VpnSettingsScreenTest {
state =
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = false,
- customDnsItems = listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, false)),
+ customDnsItems =
+ listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, false, false)),
)
)
onNodeWithTag(LAZY_LIST_VPN_SETTINGS_TEST_TAG)
@@ -196,7 +199,13 @@ class VpnSettingsScreenTest {
isCustomDnsEnabled = true,
isLocalNetworkSharingEnabled = true,
customDnsItems =
- listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true)),
+ listOf(
+ CustomDnsItem(
+ address = DUMMY_DNS_ADDRESS,
+ isLocal = true,
+ isIpv6 = false,
+ )
+ ),
)
)
@@ -213,7 +222,13 @@ class VpnSettingsScreenTest {
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
customDnsItems =
- listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false)),
+ listOf(
+ CustomDnsItem(
+ address = DUMMY_DNS_ADDRESS,
+ isLocal = false,
+ isIpv6 = false,
+ )
+ ),
)
)
@@ -230,7 +245,13 @@ class VpnSettingsScreenTest {
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
customDnsItems =
- listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false)),
+ listOf(
+ CustomDnsItem(
+ address = DUMMY_DNS_ADDRESS,
+ isLocal = false,
+ isIpv6 = false,
+ )
+ ),
)
)
@@ -247,7 +268,13 @@ class VpnSettingsScreenTest {
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
customDnsItems =
- listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true)),
+ listOf(
+ CustomDnsItem(
+ address = DUMMY_DNS_ADDRESS,
+ isLocal = true,
+ isIpv6 = false,
+ )
+ ),
)
)
@@ -417,7 +444,7 @@ class VpnSettingsScreenTest {
state =
VpnSettingsUiState.createDefault(
isCustomDnsEnabled = true,
- customDnsItems = listOf(CustomDnsItem("1.1.1.1", false)),
+ customDnsItems = listOf(CustomDnsItem("1.1.1.1", false, false)),
),
navigateToDns = mockedClickHandler,
)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt
index 8fe5f32b99..cc9ed30d9d 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/cell/DnsCell.kt
@@ -1,6 +1,7 @@
package net.mullvad.mullvadvpn.compose.cell
import androidx.compose.foundation.layout.RowScope
+import androidx.compose.foundation.layout.padding
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Error
import androidx.compose.material.icons.rounded.Error
@@ -9,18 +10,26 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.alpha
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.tooling.preview.Preview
-import androidx.compose.ui.unit.dp
import net.mullvad.mullvadvpn.R
import net.mullvad.mullvadvpn.lib.theme.AppTheme
+import net.mullvad.mullvadvpn.lib.theme.Dimens
+import net.mullvad.mullvadvpn.lib.theme.color.AlphaInvisible
+import net.mullvad.mullvadvpn.lib.theme.color.AlphaVisible
@Preview
@Composable
private fun PreviewDnsCell() {
AppTheme {
- DnsCell(address = "0.0.0.0", isUnreachableLocalDnsWarningVisible = true, onClick = {})
+ DnsCell(
+ address = "0.0.0.0",
+ isUnreachableLocalDnsWarningVisible = true,
+ isUnreachableIpv6DnsWarningVisible = false,
+ onClick = {},
+ )
}
}
@@ -28,22 +37,37 @@ private fun PreviewDnsCell() {
fun DnsCell(
address: String,
isUnreachableLocalDnsWarningVisible: Boolean,
+ isUnreachableIpv6DnsWarningVisible: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
) {
val titleModifier = Modifier
- val startPadding = 54.dp
+ val startPadding = Dimens.cellStartPadding
BaseCell(
headlineContent = { DnsTitle(address = address, modifier = titleModifier) },
- bodyView = {
- if (isUnreachableLocalDnsWarningVisible) {
- Icon(
- imageVector = Icons.Rounded.Error,
- contentDescription = stringResource(id = R.string.confirm_local_dns),
- tint = MaterialTheme.colorScheme.error,
- )
- }
+ iconView = {
+ Icon(
+ modifier =
+ Modifier.padding(end = Dimens.verticalDividerPadding)
+ .alpha(
+ when {
+ isUnreachableLocalDnsWarningVisible ||
+ isUnreachableIpv6DnsWarningVisible -> AlphaVisible
+ else -> AlphaInvisible
+ }
+ ),
+ imageVector = Icons.Rounded.Error,
+ contentDescription =
+ when {
+ isUnreachableLocalDnsWarningVisible ->
+ stringResource(id = R.string.confirm_local_dns)
+ isUnreachableIpv6DnsWarningVisible ->
+ stringResource(id = R.string.confirm_ipv6_dns)
+ else -> null
+ },
+ tint = MaterialTheme.colorScheme.error,
+ )
},
onCellClicked = { onClick.invoke() },
background = MaterialTheme.colorScheme.surfaceContainerLow,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt
index 6f9c8126c0..4fee24a8f9 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/dialog/DnsDialog.kt
@@ -39,7 +39,7 @@ private fun PreviewDnsDialogEdit() {
@Preview
@Composable
private fun PreviewDnsDialogEditAllowLanDisabled() {
- AppTheme { DnsDialog(DnsDialogViewState("192.168.1.1", null, true, false, 0), {}, {}, {}, {}) }
+ AppTheme { DnsDialog(DnsDialogViewState("192.168.1.1", null, false, false, 0), {}, {}, {}, {}) }
}
data class DnsDialogNavArgs(val index: Int? = null, val initialValue: String? = null)
@@ -94,15 +94,15 @@ fun DnsDialog(
placeholderText = stringResource(R.string.custom_dns_hint),
errorText =
when {
- state.validationError is ValidationError.DuplicateAddress -> {
+ state.validationError is ValidationError.DuplicateAddress ->
stringResource(R.string.duplicate_address_warning)
- }
- state.isLocal && !state.isAllowLanEnabled -> {
+ // Ordering is important, as we consider the lan error to have higher
+ // priority than the ipv6 error
+ state.isLocal && !state.isAllowLanEnabled ->
stringResource(id = R.string.confirm_local_dns)
- }
- else -> {
- null
- }
+ state.isIpv6 && !state.isIpv6Enabled ->
+ stringResource(id = R.string.confirm_ipv6_dns)
+ else -> null
},
modifier = Modifier.fillMaxWidth(),
)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/VpnSettingsUiStatePreviewParameterProvider.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/VpnSettingsUiStatePreviewParameterProvider.kt
index 796965d856..55c8802c7f 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/VpnSettingsUiStatePreviewParameterProvider.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/compose/preview/VpnSettingsUiStatePreviewParameterProvider.kt
@@ -21,7 +21,7 @@ class VpnSettingsUiStatePreviewParameterProvider : PreviewParameterProvider<VpnS
mtu = Mtu(MTU),
isLocalNetworkSharingEnabled = true,
isCustomDnsEnabled = true,
- customDnsItems = listOf(CustomDnsItem("0.0.0.0", false)),
+ customDnsItems = listOf(CustomDnsItem("0.0.0.0", false, false)),
contentBlockersOptions =
DefaultDnsOptions(
blockAds = 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 a257341175..0504201d58 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
@@ -142,6 +142,7 @@ private fun PreviewVpnSettings(
navigateToWireguardPortDialog = {},
navigateToServerIpOverrides = {},
onSelectDeviceIpVersion = {},
+ onToggleIpv6Toggle = {},
)
}
}
@@ -271,6 +272,7 @@ fun VpnSettings(
dropUnlessResumed { navigator.navigate(Udp2TcpSettingsDestination) },
onToggleAutoStartAndConnectOnBoot = vm::onToggleAutoStartAndConnectOnBoot,
onSelectDeviceIpVersion = vm::onDeviceIpVersionSelected,
+ onToggleIpv6Toggle = vm::setIpv6Enabled,
)
}
@@ -308,9 +310,9 @@ fun VpnSettingsScreen(
navigateToUdp2TcpSettings: () -> Unit,
onToggleAutoStartAndConnectOnBoot: (Boolean) -> Unit,
onSelectDeviceIpVersion: (ipVersion: Constraint<IpVersion>) -> Unit,
+ onToggleIpv6Toggle: (Boolean) -> Unit,
) {
var expandContentBlockersState by rememberSaveable { mutableStateOf(false) }
- val biggerPadding = 54.dp
val topPadding = 6.dp
ScaffoldWithMediumTopBar(
@@ -467,6 +469,7 @@ fun VpnSettingsScreen(
address = item.address,
isUnreachableLocalDnsWarningVisible =
item.isLocal && !state.isLocalNetworkSharingEnabled,
+ isUnreachableIpv6DnsWarningVisible = item.isIpv6 && !state.isIpv6Enabled,
onClick = { navigateToDns(index, item.address) },
modifier = Modifier.animateItem(),
)
@@ -484,7 +487,7 @@ fun VpnSettingsScreen(
},
bodyView = {},
background = MaterialTheme.colorScheme.surfaceContainerLow,
- startPadding = biggerPadding,
+ startPadding = Dimens.cellStartPaddingLarge,
)
}
}
@@ -682,6 +685,16 @@ fun VpnSettingsScreen(
}
item {
+ HeaderSwitchComposeCell(
+ title = stringResource(R.string.enable_ipv6),
+ isToggled = state.isIpv6Enabled,
+ isEnabled = true,
+ onCellClicked = { newValue -> onToggleIpv6Toggle(newValue) },
+ )
+ Spacer(modifier = Modifier.height(Dimens.cellVerticalSpacing))
+ }
+
+ item {
MtuComposeCell(mtuValue = state.mtu, onEditMtu = { navigateToMtuDialog(state.mtu) })
}
item { MtuSubtitle(modifier = Modifier.testTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) }
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 ec069001cc..3756d547f9 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
@@ -26,6 +26,7 @@ data class VpnSettingsUiState(
val systemVpnSettingsAvailable: Boolean,
val autoStartAndConnectOnBoot: Boolean,
val deviceIpVersion: Constraint<IpVersion>,
+ val isIpv6Enabled: Boolean,
) {
val isCustomWireguardPort =
selectedWireguardPort is Constraint.Only &&
@@ -51,6 +52,7 @@ data class VpnSettingsUiState(
systemVpnSettingsAvailable: Boolean = false,
autoStartAndConnectOnBoot: Boolean = false,
deviceIpVersion: Constraint<IpVersion> = Constraint.Any,
+ isIpv6Enabled: Boolean = true,
) =
VpnSettingsUiState(
mtu,
@@ -68,6 +70,7 @@ data class VpnSettingsUiState(
systemVpnSettingsAvailable,
autoStartAndConnectOnBoot,
deviceIpVersion,
+ isIpv6Enabled,
)
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt
index e6b03ee599..e5453fe57b 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/repository/SettingsRepository.kt
@@ -74,4 +74,6 @@ class SettingsRepository(
suspend fun setDaitaEnabled(enabled: Boolean) = managementService.setDaitaEnabled(enabled)
suspend fun setDaitaDirectOnly(enabled: Boolean) = managementService.setDaitaDirectOnly(enabled)
+
+ suspend fun setIpv6Enabled(enabled: Boolean) = managementService.setIpv6Enabled(enabled)
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt
index ab067e8145..c79682039b 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DnsDialogViewModel.kt
@@ -7,6 +7,7 @@ import arrow.core.Either
import arrow.core.raise.either
import arrow.core.raise.ensure
import com.ramcosta.composedestinations.generated.destinations.DnsDestination
+import java.net.Inet6Address
import java.net.InetAddress
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
@@ -34,13 +35,22 @@ sealed interface DnsDialogSideEffect {
data class DnsDialogViewState(
val input: String,
val validationError: ValidationError?,
- val isLocal: Boolean,
val isAllowLanEnabled: Boolean,
+ val isIpv6Enabled: Boolean,
val index: Int?,
) {
val isNewEntry = index == null
+ val isIpv6: Boolean = input.isIpv6()
+ val isLocal: Boolean = input.isLocalAddress()
fun isValid() = validationError == null
+
+ private fun String.isLocalAddress(): Boolean =
+ isValid() && InetAddress.getByName(this).isLocalAddress()
+
+ private fun String.isIpv6(): Boolean = isValid() && InetAddress.getByName(this) is Inet6Address
+
+ private fun InetAddress.isLocalAddress(): Boolean = isLinkLocalAddress || isSiteLocalAddress
}
sealed class ValidationError {
@@ -67,12 +77,25 @@ class DnsDialogViewModel(
input,
currentIndex,
settings ->
- createViewState(settings.addresses(), currentIndex, settings.allowLan, input)
+ DnsDialogViewState(
+ input = input,
+ validationError =
+ input.validateDnsEntry(currentIndex, settings.addresses()).leftOrNull(),
+ isAllowLanEnabled = settings.allowLan,
+ isIpv6Enabled = settings.tunnelOptions.genericOptions.enableIpv6,
+ index = currentIndex,
+ )
}
.stateIn(
viewModelScope,
SharingStarted.Lazily,
- createViewState(emptyList(), null, false, _ipAddressInput.value),
+ DnsDialogViewState(
+ input = _ipAddressInput.value,
+ validationError = null,
+ isAllowLanEnabled = false,
+ isIpv6Enabled = false,
+ index = null,
+ ),
)
private val _uiSideEffect = Channel<DnsDialogSideEffect>()
@@ -82,20 +105,6 @@ class DnsDialogViewModel(
viewModelScope.launch { settings.emit(repository.settingsUpdates.filterNotNull().first()) }
}
- private fun createViewState(
- customDnsList: List<InetAddress>,
- currentIndex: Int?,
- isAllowLanEnabled: Boolean,
- input: String,
- ): DnsDialogViewState =
- DnsDialogViewState(
- input,
- input.validateDnsEntry(currentIndex, customDnsList).leftOrNull(),
- input.isLocalAddress(),
- isAllowLanEnabled = isAllowLanEnabled,
- currentIndex,
- )
-
private fun String.validateDnsEntry(
index: Int?,
dnsList: List<InetAddress>,
@@ -147,14 +156,6 @@ class DnsDialogViewModel(
return inetAddressValidator.isValid(this)
}
- private fun String.isLocalAddress(): Boolean {
- return isValidIp() && InetAddress.getByName(this).isLocalAddress()
- }
-
- private fun InetAddress.isLocalAddress(): Boolean {
- return isLinkLocalAddress || isSiteLocalAddress
- }
-
private fun InetAddress.isDuplicateDnsEntry(
currentIndex: Int? = null,
dnsList: List<InetAddress>,
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt
index 2273ada5e0..aa00ebdca3 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModel.kt
@@ -3,6 +3,7 @@ package net.mullvad.mullvadvpn.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import co.touchlab.kermit.Logger
+import java.net.Inet6Address
import java.net.InetAddress
import java.net.UnknownHostException
import kotlinx.coroutines.CoroutineDispatcher
@@ -85,6 +86,7 @@ class VpnSettingsViewModel(
systemVpnSettingsAvailable = systemVpnSettingsUseCase(),
autoStartAndConnectOnBoot = autoStartAndConnectOnBoot,
deviceIpVersion = settings?.getDeviceIpVersion() ?: Constraint.Any,
+ ipv6Enabled = settings?.tunnelOptions?.genericOptions?.enableIpv6 == true,
)
}
.stateIn(
@@ -253,6 +255,14 @@ class VpnSettingsViewModel(
}
}
+ fun setIpv6Enabled(enable: Boolean) {
+ viewModelScope.launch(dispatcher) {
+ repository.setIpv6Enabled(enable).onLeft {
+ _uiSideEffect.send(VpnSettingsSideEffect.ShowToast.GenericError)
+ }
+ }
+ }
+
private fun updateDefaultDnsOptionsViaRepository(contentBlockersOption: DefaultDnsOptions) =
viewModelScope.launch(dispatcher) {
repository
@@ -275,7 +285,11 @@ class VpnSettingsViewModel(
private fun List<InetAddress>.asStringAddressList(): List<CustomDnsItem> {
return map {
- CustomDnsItem(address = it.hostAddress ?: EMPTY_STRING, isLocal = it.isLocalAddress())
+ CustomDnsItem(
+ address = it.hostAddress ?: EMPTY_STRING,
+ isLocal = it.isLocalAddress(),
+ isIpv6 = it is Inet6Address,
+ )
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt
index 6e91294257..f4f1a8dbcd 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelState.kt
@@ -26,6 +26,7 @@ data class VpnSettingsViewModelState(
val systemVpnSettingsAvailable: Boolean,
val autoStartAndConnectOnBoot: Boolean,
val deviceIpVersion: Constraint<IpVersion>,
+ val ipv6Enabled: Boolean,
) {
val isCustomWireguardPort =
selectedWireguardPort is Constraint.Only &&
@@ -48,6 +49,7 @@ data class VpnSettingsViewModelState(
systemVpnSettingsAvailable,
autoStartAndConnectOnBoot,
deviceIpVersion,
+ ipv6Enabled,
)
companion object {
@@ -68,16 +70,17 @@ data class VpnSettingsViewModelState(
systemVpnSettingsAvailable = false,
autoStartAndConnectOnBoot = false,
deviceIpVersion = Constraint.Any,
+ ipv6Enabled = false,
)
}
}
-data class CustomDnsItem(val address: String, val isLocal: Boolean) {
+data class CustomDnsItem(val address: String, val isLocal: Boolean, val isIpv6: Boolean) {
companion object {
private const val EMPTY_STRING = ""
fun default(): CustomDnsItem {
- return CustomDnsItem(address = EMPTY_STRING, isLocal = false)
+ return CustomDnsItem(address = EMPTY_STRING, isLocal = false, isIpv6 = false)
}
}
}
diff --git a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt
index 9d7ed39622..c91d6d9a20 100644
--- a/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt
+++ b/android/app/src/test/kotlin/net/mullvad/mullvadvpn/viewmodel/VpnSettingsViewModelTest.kt
@@ -174,6 +174,7 @@ class VpnSettingsViewModelTest {
daitaSettings = DaitaSettings(enabled = false, directOnly = false),
),
dnsOptions = mockk(relaxed = true),
+ genericOptions = mockk(relaxed = true),
)
// Act, Assert
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt
index 44447ee866..4d1baab550 100644
--- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/ManagementService.kt
@@ -802,6 +802,11 @@ class ManagementService(
.mapLeft(SetWireguardConstraintsError::Unknown)
.mapEmpty()
+ suspend fun setIpv6Enabled(enabled: Boolean): Either<SetDaitaSettingsError, Unit> =
+ Either.catch { grpc.setEnableIpv6(BoolValue.of(enabled)) }
+ .mapLeft(SetDaitaSettingsError::Unknown)
+ .mapEmpty()
+
private fun <A> Either<A, Empty>.mapEmpty() = map {}
private inline fun <B, C> Either<Throwable, B>.mapLeftStatus(
diff --git a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
index 6ee772521b..5e2f7fb831 100644
--- a/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
+++ b/android/lib/daemon-grpc/src/main/kotlin/net/mullvad/mullvadvpn/lib/daemon/grpc/mapper/ToDomain.kt
@@ -39,6 +39,7 @@ import net.mullvad.mullvadvpn.lib.model.Endpoint
import net.mullvad.mullvadvpn.lib.model.ErrorState
import net.mullvad.mullvadvpn.lib.model.ErrorStateCause
import net.mullvad.mullvadvpn.lib.model.FeatureIndicator
+import net.mullvad.mullvadvpn.lib.model.GenericOptions
import net.mullvad.mullvadvpn.lib.model.GeoIpLocation
import net.mullvad.mullvadvpn.lib.model.GeoLocationId
import net.mullvad.mullvadvpn.lib.model.IpVersion
@@ -434,7 +435,11 @@ internal fun ManagementInterface.CustomList.toDomain(): CustomList =
)
internal fun ManagementInterface.TunnelOptions.toDomain(): TunnelOptions =
- TunnelOptions(wireguard = wireguard.toDomain(), dnsOptions = dnsOptions.toDomain())
+ TunnelOptions(
+ wireguard = wireguard.toDomain(),
+ dnsOptions = dnsOptions.toDomain(),
+ genericOptions = generic.toDomain(),
+ )
internal fun ManagementInterface.TunnelOptions.WireguardOptions.toDomain(): WireguardTunnelOptions =
WireguardTunnelOptions(
@@ -674,6 +679,9 @@ internal fun ManagementInterface.SocksAuth.toDomain(): SocksAuth =
internal fun ManagementInterface.FeatureIndicators.toDomain(): List<FeatureIndicator> =
activeFeaturesList.map { it.toDomain() }.sorted()
+internal fun ManagementInterface.TunnelOptions.GenericOptions.toDomain(): GenericOptions =
+ GenericOptions(enableIpv6 = enableIpv6)
+
internal fun ManagementInterface.FeatureIndicator.toDomain() =
when (this) {
ManagementInterface.FeatureIndicator.QUANTUM_RESISTANCE ->
diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/GenericOptions.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/GenericOptions.kt
new file mode 100644
index 0000000000..7ae0acc102
--- /dev/null
+++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/GenericOptions.kt
@@ -0,0 +1,3 @@
+package net.mullvad.mullvadvpn.lib.model
+
+data class GenericOptions(val enableIpv6: Boolean)
diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelOptions.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelOptions.kt
index de1d760d30..a93e032975 100644
--- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelOptions.kt
+++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/lib/model/TunnelOptions.kt
@@ -3,6 +3,10 @@ package net.mullvad.mullvadvpn.lib.model
import arrow.optics.optics
@optics
-data class TunnelOptions(val wireguard: WireguardTunnelOptions, val dnsOptions: DnsOptions) {
+data class TunnelOptions(
+ val wireguard: WireguardTunnelOptions,
+ val dnsOptions: DnsOptions,
+ val genericOptions: GenericOptions,
+) {
companion object
}
diff --git a/android/lib/resource/src/main/res/values-da/strings.xml b/android/lib/resource/src/main/res/values-da/strings.xml
index 98567db67c..af65414dbf 100644
--- a/android/lib/resource/src/main/res/values-da/strings.xml
+++ b/android/lib/resource/src/main/res/values-da/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Aktivér alligevel</string>
<string name="enable_custom_dns">Brug brugerdefineret DNS-server</string>
<string name="enable_direct_only">Aktivér %1$s</string>
+ <string name="enable_ipv6">Aktiver IPv6</string>
<string name="enable_method">Aktiver metode</string>
<string name="encrypted_dns_proxy_info_message_part1">Med metoden \"krypteret DNS-proxy\" vil appen kommunikere med vores Mullvad API via en proxy-adresse. Det gør den ved at hente en adresse fra en DNS over HTTPS-server (DoH) og derefter bruge den til at få adgang til en vores API-servere.</string>
<string name="enter_value_placeholder">Indtast MTU</string>
diff --git a/android/lib/resource/src/main/res/values-de/strings.xml b/android/lib/resource/src/main/res/values-de/strings.xml
index dc1824d525..d30ab48b70 100644
--- a/android/lib/resource/src/main/res/values-de/strings.xml
+++ b/android/lib/resource/src/main/res/values-de/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Trotzdem aktivieren</string>
<string name="enable_custom_dns">Benutzerdefinierten DNS-Server verwenden</string>
<string name="enable_direct_only">%1$s aktivieren</string>
+ <string name="enable_ipv6">IPv6 aktivieren</string>
<string name="enable_method">Methode aktivieren</string>
<string name="encrypted_dns_proxy_info_message_part1">Mit der Methode „Verschlüsseltes-DNS-Proxy“ kommuniziert die App mit unserer Mullvad-API über eine Proxy-Adresse. Sie tut dies, indem sie eine Adresse von einem DNS-over-HTTPS-Server (DoH) abruft und dann diese verwendet, um unsere API-Server zu erreichen.</string>
<string name="enter_value_placeholder">MTU eingeben</string>
diff --git a/android/lib/resource/src/main/res/values-es/strings.xml b/android/lib/resource/src/main/res/values-es/strings.xml
index 6598785017..dd08a9f1c1 100644
--- a/android/lib/resource/src/main/res/values-es/strings.xml
+++ b/android/lib/resource/src/main/res/values-es/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Habilitar de todos modos</string>
<string name="enable_custom_dns">Usar servidor DNS personalizado</string>
<string name="enable_direct_only">Habilitar %1$s</string>
+ <string name="enable_ipv6">Habilitar IPv6</string>
<string name="enable_method">Habilitar método</string>
<string name="encrypted_dns_proxy_info_message_part1">Con el método «Proxy DNS cifrado», la aplicación se comunicará con nuestra API de Mullvad a través de una dirección proxy. Para ello, recupera una dirección de un servidor DNS sobre HTTPS (DoH) y luego la utiliza para contactar con nuestros servidores API.</string>
<string name="enter_value_placeholder">Introducir MTU</string>
diff --git a/android/lib/resource/src/main/res/values-fi/strings.xml b/android/lib/resource/src/main/res/values-fi/strings.xml
index 3548e2c2d7..1e40a14515 100644
--- a/android/lib/resource/src/main/res/values-fi/strings.xml
+++ b/android/lib/resource/src/main/res/values-fi/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Ota silti käyttöön</string>
<string name="enable_custom_dns">Käytä mukautettua DNS-palvelinta</string>
<string name="enable_direct_only">Ota %1$s käyttöön</string>
+ <string name="enable_ipv6">Salli IPv6</string>
<string name="enable_method">Ota menetelmä käyttöön</string>
<string name="encrypted_dns_proxy_info_message_part1">Sovellus kommunikoi Mullvad API:n kanssa välityspalvelinosoitteen kautta \"Salattu DNS-välityspalvelin\" -menetelmällä, joka toimii niin, että sovellus hakee osoitteen DNS over HTTPS (DoH) -palvelimelta ja käyttää sitä API-palvelimillemme pääsemiseen.</string>
<string name="enter_value_placeholder">Syötä MTU</string>
diff --git a/android/lib/resource/src/main/res/values-fr/strings.xml b/android/lib/resource/src/main/res/values-fr/strings.xml
index 451680dc93..4134f88935 100644
--- a/android/lib/resource/src/main/res/values-fr/strings.xml
+++ b/android/lib/resource/src/main/res/values-fr/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Activer quand même</string>
<string name="enable_custom_dns">Utiliser un serveur DNS personnalisé</string>
<string name="enable_direct_only">Activer %1$s</string>
+ <string name="enable_ipv6">Activer IPv6</string>
<string name="enable_method">Activer la méthode</string>
<string name="encrypted_dns_proxy_info_message_part1">Avec la méthode « proxy DNS chiffré », l\'application communiquera avec notre API Mullvad par le biais d\'une adresse proxy. Pour ce faire, elle récupère une adresse auprès d\'un serveur DNS over HTTPS (DoH) et l\'utilise pour atteindre nos serveurs API.</string>
<string name="enter_value_placeholder">Saisir le MTU</string>
diff --git a/android/lib/resource/src/main/res/values-it/strings.xml b/android/lib/resource/src/main/res/values-it/strings.xml
index 875610978f..f8ad5bdf21 100644
--- a/android/lib/resource/src/main/res/values-it/strings.xml
+++ b/android/lib/resource/src/main/res/values-it/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Abilita comunque</string>
<string name="enable_custom_dns">Usa un server DNS personalizzato</string>
<string name="enable_direct_only">Abilita %1$s</string>
+ <string name="enable_ipv6">Abilita IPv6</string>
<string name="enable_method">Abilita metodo</string>
<string name="encrypted_dns_proxy_info_message_part1">Con il metodo \"Proxy DNS crittografato\", l\'app comunicherà con la nostra API Mullvad tramite un indirizzo proxy. Lo fa recuperando un indirizzo da un server DNS over HTTPS (DoH) e quindi utilizzandolo per raggiungere i nostri server API.</string>
<string name="enter_value_placeholder">Inserisci MTU</string>
diff --git a/android/lib/resource/src/main/res/values-ja/strings.xml b/android/lib/resource/src/main/res/values-ja/strings.xml
index d00352f8dc..da56178056 100644
--- a/android/lib/resource/src/main/res/values-ja/strings.xml
+++ b/android/lib/resource/src/main/res/values-ja/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">それでも有効にする</string>
<string name="enable_custom_dns">カスタムDNSサーバーを使う</string>
<string name="enable_direct_only">%1$sを有効にする</string>
+ <string name="enable_ipv6">IPv6を有効にする</string>
<string name="enable_method">方法を有効化する</string>
<string name="encrypted_dns_proxy_info_message_part1">[暗号化DNSプロキシ] 方式を使用すると、アプリはプロキシアドレスを通じてMullvad APIと通信します。これはDNS over HTTPS (DoH) サーバーからアドレスを取得し、APIサーバーへのアクセスに利用することで行われます。</string>
<string name="enter_value_placeholder">MTU を入力</string>
diff --git a/android/lib/resource/src/main/res/values-ko/strings.xml b/android/lib/resource/src/main/res/values-ko/strings.xml
index ef986169bb..7c8d40c1b2 100644
--- a/android/lib/resource/src/main/res/values-ko/strings.xml
+++ b/android/lib/resource/src/main/res/values-ko/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">그래도 사용</string>
<string name="enable_custom_dns">사용자 지정 DNS 서버 사용</string>
<string name="enable_direct_only">%1$s 활성화</string>
+ <string name="enable_ipv6">IPv6 사용</string>
<string name="enable_method">방법 활성화</string>
<string name="encrypted_dns_proxy_info_message_part1">앱은 \"암호화된 DNS 프록시\" 방식을 사용하여 프록시 주소를 통해 Mullvad API와 통신합니다. 이는 DoH(DNS over HTTPS) 서버에서 주소를 검색한 다음, 그 주소를 사용해 당사 API 서버에 도달하는 방식으로 이루어집니다.</string>
<string name="enter_value_placeholder">MTU 입력</string>
diff --git a/android/lib/resource/src/main/res/values-my/strings.xml b/android/lib/resource/src/main/res/values-my/strings.xml
index bf1aaf301c..76e1bd397a 100644
--- a/android/lib/resource/src/main/res/values-my/strings.xml
+++ b/android/lib/resource/src/main/res/values-my/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">မည်သို့ပင်ဖြစ်စေ ဖွင့်ရန်</string>
<string name="enable_custom_dns">စိတ်ကြိုက် DNS ဆာဗာကို သုံးရန်</string>
<string name="enable_direct_only">%1$s ကို ဖွင့်ရန်</string>
+ <string name="enable_ipv6">IPv6 ကို ဖွင့်ရန်</string>
<string name="enable_method">နည်းလမ်းကို ဖွင့်ရန်</string>
<string name="encrypted_dns_proxy_info_message_part1">ထိုအက်ပ်သည် “ကုဒ်ဝှက်ထားသော DNS ပရောက်စီ” နည်းလမ်းအားဖြင့် ကျွန်ုပ်တို့၏ Mullvad API ထံသို့ ပရောက်စီလိပ်စာမှတစ်ဆင့် ဆက်သွယ်ပေးမည်ဖြစ်သည်။ HTTPS (DoH) ဆာဗာရှိ DNS မှ လိပ်စာတစ်ခုကို ပြန်လည်ရယူခြင်းအားဖြင့် ထိုသို့လုပ်ဆောင်ပြီးနောက် ကျွန်ုပ်တို့၏ API ဆာဗာများသို့ရောက်ရှိရန် ၎င်းကို အသုံးပြုသည်။</string>
<string name="enter_value_placeholder">MTU ကို ရိုက်ထည့်ရန်</string>
diff --git a/android/lib/resource/src/main/res/values-nb/strings.xml b/android/lib/resource/src/main/res/values-nb/strings.xml
index baf1c6f897..4c73f9de0a 100644
--- a/android/lib/resource/src/main/res/values-nb/strings.xml
+++ b/android/lib/resource/src/main/res/values-nb/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Aktiver uansett</string>
<string name="enable_custom_dns">Bruk egendefinert DNS-server</string>
<string name="enable_direct_only">Aktiver %1$s</string>
+ <string name="enable_ipv6">Aktiver IPv6</string>
<string name="enable_method">Aktiver metoden</string>
<string name="encrypted_dns_proxy_info_message_part1">Med metoden «Kryptert DNS-proxy» vil appen kommunisere med Mullvad API gjennom en proxy-adresse. Dette gjøres ved å hente en adresse fra en DNS over HTTPS-server (DoH) og deretter bruke den til å nå API-serverne våre.</string>
<string name="enter_value_placeholder">Angi MTU</string>
diff --git a/android/lib/resource/src/main/res/values-nl/strings.xml b/android/lib/resource/src/main/res/values-nl/strings.xml
index 6d94e0e54f..4e5e3c7fd0 100644
--- a/android/lib/resource/src/main/res/values-nl/strings.xml
+++ b/android/lib/resource/src/main/res/values-nl/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Toch inschakelen</string>
<string name="enable_custom_dns">Aangepaste DNS-server gebruiken</string>
<string name="enable_direct_only">%1$s inschakelen</string>
+ <string name="enable_ipv6">IPv6 inschakelen</string>
<string name="enable_method">Methode inschakelen</string>
<string name="encrypted_dns_proxy_info_message_part1">Met de methode \"Versleutelde DNS-proxy\" communiceert de app met onze Mullvad-API via een proxyadres. De app doet dit door een adres op te halen van een DoH-server (DNS over HTTPS) en dat te gebruiken om onze API-servers te bereiken.</string>
<string name="enter_value_placeholder">Voer MTU in</string>
diff --git a/android/lib/resource/src/main/res/values-pl/strings.xml b/android/lib/resource/src/main/res/values-pl/strings.xml
index 3dac79a312..b8a50bd47c 100644
--- a/android/lib/resource/src/main/res/values-pl/strings.xml
+++ b/android/lib/resource/src/main/res/values-pl/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Mimo to włącz</string>
<string name="enable_custom_dns">Użyj niestandardowego serwera DNS</string>
<string name="enable_direct_only">Włącz %1$s</string>
+ <string name="enable_ipv6">Włącz IPv6</string>
<string name="enable_method">Włącz metodę</string>
<string name="encrypted_dns_proxy_info_message_part1">Dzięki metodzie „szyfrowany serwer proxy DNS” aplikacja będzie komunikować się z naszym interfejsem API Mullvad za pośrednictwem adresu serwera proxy. Odbywa się to poprzez pobranie adresu z serwera DNS over HTTPS (DoH), a następnie użycie go do połączenia z naszymi serwerami interfejsu API.</string>
<string name="enter_value_placeholder">Wprowadź MTU</string>
diff --git a/android/lib/resource/src/main/res/values-pt/strings.xml b/android/lib/resource/src/main/res/values-pt/strings.xml
index b98f5e84ee..cd074ceef1 100644
--- a/android/lib/resource/src/main/res/values-pt/strings.xml
+++ b/android/lib/resource/src/main/res/values-pt/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Ativar mesmo assim</string>
<string name="enable_custom_dns">Usar servidor DNS personalizado</string>
<string name="enable_direct_only">Ativar %1$s</string>
+ <string name="enable_ipv6">Ativar IPv6</string>
<string name="enable_method">Ativar método</string>
<string name="encrypted_dns_proxy_info_message_part1">Com o método \"Proxy DNS encriptado\", a aplicação irá comunicar com a nossa API Mullvad através de um endereço proxy. Para tal, obtém um endereço de um servidor DNS sobre HTTPS (DoH) e utiliza-o para aceder aos nossos servidores de API.</string>
<string name="enter_value_placeholder">Introduzir MTU</string>
diff --git a/android/lib/resource/src/main/res/values-ru/strings.xml b/android/lib/resource/src/main/res/values-ru/strings.xml
index 59be83838a..a1bd1b0272 100644
--- a/android/lib/resource/src/main/res/values-ru/strings.xml
+++ b/android/lib/resource/src/main/res/values-ru/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Всё равно включить</string>
<string name="enable_custom_dns">Пользовательский DNS-сервер</string>
<string name="enable_direct_only">Включить параметр «%1$s»</string>
+ <string name="enable_ipv6">Включить IPv6</string>
<string name="enable_method">Включить метод</string>
<string name="encrypted_dns_proxy_info_message_part1">При использовании метода «Прокси через зашифрованный DNS» приложение будет взаимодействовать с API Mullvad через прокси-адрес. Полученный от сервера «DNS по HTTPS» (DoH) адрес будет использоваться для доступа к нашим серверам API.</string>
<string name="enter_value_placeholder">Введите MTU</string>
diff --git a/android/lib/resource/src/main/res/values-sv/strings.xml b/android/lib/resource/src/main/res/values-sv/strings.xml
index ec4ec66f52..4b35009e29 100644
--- a/android/lib/resource/src/main/res/values-sv/strings.xml
+++ b/android/lib/resource/src/main/res/values-sv/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Aktivera ändå</string>
<string name="enable_custom_dns">Använd anpassad DNS-server</string>
<string name="enable_direct_only">Aktivera %1$s</string>
+ <string name="enable_ipv6">Aktivera IPv6</string>
<string name="enable_method">Aktivera metod</string>
<string name="encrypted_dns_proxy_info_message_part1">Med metoden \"Krypterad DNS-proxy\" kommunicerar appen med vår Mullvad API via en proxyadress. Den gör det genom att hämta en adress från en DNS over HTTPS-server (DoH) och sedan använda den för att nå våra API-servrar.</string>
<string name="enter_value_placeholder">Ange MTU</string>
diff --git a/android/lib/resource/src/main/res/values-th/strings.xml b/android/lib/resource/src/main/res/values-th/strings.xml
index 4af746a20b..ce3aa780b2 100644
--- a/android/lib/resource/src/main/res/values-th/strings.xml
+++ b/android/lib/resource/src/main/res/values-th/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">เปิดใช้งานต่อไป</string>
<string name="enable_custom_dns">ใช้เซิร์ฟเวอร์ DNS แบบกำหนดเอง</string>
<string name="enable_direct_only">เปิดใช้งาน %1$s</string>
+ <string name="enable_ipv6">เปิดใช้งาน IPv6</string>
<string name="enable_method">เปิดใช้งานวิธีการ</string>
<string name="encrypted_dns_proxy_info_message_part1">การใช้วิธี \"พร็อกซี DNS ที่เข้ารหัส\" จะช่วยให้แอปสื่อสารกับ Mullvad API ของเราผ่านที่อยู่พร็อกซี ซึ่งทำได้โดยดึงที่อยู่จากเซิร์ฟเวอร์ DNS ผ่าน HTTPS (DoH) แล้วจึงใช้ที่อยู่ดังกล่าวเพื่อเข้าถึงเซิร์ฟเวอร์ API ของเรา</string>
<string name="enter_value_placeholder">ป้อน MTU</string>
diff --git a/android/lib/resource/src/main/res/values-tr/strings.xml b/android/lib/resource/src/main/res/values-tr/strings.xml
index b341035535..68826a6a86 100644
--- a/android/lib/resource/src/main/res/values-tr/strings.xml
+++ b/android/lib/resource/src/main/res/values-tr/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">Yine de etkinleştir</string>
<string name="enable_custom_dns">Özel DNS sunucusu kullanın</string>
<string name="enable_direct_only">%1$s ayarını etkinleştir</string>
+ <string name="enable_ipv6">IPv6\'yı etkinleştir</string>
<string name="enable_method">Yöntemi etkinleştir</string>
<string name="encrypted_dns_proxy_info_message_part1">\"Şifreli DNS proxy\'si\" yönteminde, uygulama bir proxy adresi üzerinden Mullvad API ile iletişim kurar. Bunun için bir DNS over HTTPS (DoH) sunucusundan bir adres alır ve bu adresi kullanarak API sunucularımıza bağlanır.</string>
<string name="enter_value_placeholder">MTU\'yu girin</string>
diff --git a/android/lib/resource/src/main/res/values-zh-rCN/strings.xml b/android/lib/resource/src/main/res/values-zh-rCN/strings.xml
index dedfa2cb94..5e18d71e60 100644
--- a/android/lib/resource/src/main/res/values-zh-rCN/strings.xml
+++ b/android/lib/resource/src/main/res/values-zh-rCN/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">仍然启用</string>
<string name="enable_custom_dns">使用自定义 DNS 服务器</string>
<string name="enable_direct_only">启用“%1$s”</string>
+ <string name="enable_ipv6">启用 IPv6</string>
<string name="enable_method">启用方法</string>
<string name="encrypted_dns_proxy_info_message_part1">利用“加密 DNS 代理”方法,应用将通过代理地址与我们的 Mullvad API 进行通信。通信时,应用从 DNS over HTTPS (DoH) 服务器获取地址,然后使用该地址连接我们的 API 服务器。</string>
<string name="enter_value_placeholder">输入 MTU</string>
diff --git a/android/lib/resource/src/main/res/values-zh-rTW/strings.xml b/android/lib/resource/src/main/res/values-zh-rTW/strings.xml
index f602f238fc..08faaefb70 100644
--- a/android/lib/resource/src/main/res/values-zh-rTW/strings.xml
+++ b/android/lib/resource/src/main/res/values-zh-rTW/strings.xml
@@ -154,6 +154,7 @@
<string name="enable_anyway">仍然啟用</string>
<string name="enable_custom_dns">使用自訂 DNS 伺服器</string>
<string name="enable_direct_only">啟用 %1$s</string>
+ <string name="enable_ipv6">啟用 IPv6</string>
<string name="enable_method">啟用方式</string>
<string name="encrypted_dns_proxy_info_message_part1">使用「加密 DNS 代理伺服器」方法時,應用程式會透過代理伺服器位址和我們的 Mullvad API 通訊。應用程式會先從 DNS over HTTPS (DoH) 伺服器取得一個位址,再利用該位址連線至我們的 API 伺服器。</string>
<string name="enter_value_placeholder">輸入 MTU</string>
diff --git a/android/lib/resource/src/main/res/values/strings.xml b/android/lib/resource/src/main/res/values/strings.xml
index 317a2e0932..c770e5aa1d 100644
--- a/android/lib/resource/src/main/res/values/strings.xml
+++ b/android/lib/resource/src/main/res/values/strings.xml
@@ -401,4 +401,6 @@
<string name="changelog_empty">No changelog was added for this version</string>
<string name="wg_port_subtitle">Set %s obfuscation to \"Automatic\" or \"Off\" below to activate this setting.</string>
<string name="device_ip_version_title">Device IP version</string>
+ <string name="confirm_ipv6_dns">The IPv6 DNS server will not work unless you enable \"IPv6\" under VPN settings.</string>
+ <string name="enable_ipv6">Enable IPv6</string>
</resources>
diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/util/UnderlyingConnectivityStatusResolver.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/util/UnderlyingConnectivityStatusResolver.kt
index 8d6428690e..0024f63357 100644
--- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/util/UnderlyingConnectivityStatusResolver.kt
+++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/util/UnderlyingConnectivityStatusResolver.kt
@@ -15,12 +15,12 @@ class UnderlyingConnectivityStatusResolver(
private val protect: (socket: DatagramSocket) -> Boolean
) {
fun currentStatus(): Connectivity.Status =
- Connectivity.Status(ipv4 = hasIPv4(), ipv6 = hasIPv6())
+ Connectivity.Status(ipv4 = hasIpv4(), ipv6 = hasIpv6())
- private fun hasIPv4(): Boolean =
+ private fun hasIpv4(): Boolean =
hasIpVersion(Inet4Address.getByName(PUBLIC_IPV4_ADDRESS), protect)
- private fun hasIPv6(): Boolean =
+ private fun hasIpv6(): Boolean =
hasIpVersion(Inet6Address.getByName(PUBLIC_IPV6_ADDRESS), protect)
// Fake a connection to a public ip address using a UDP socket.
diff --git a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt
index 74f3577f69..77ac2c3e62 100644
--- a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt
+++ b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/dimensions/Dimensions.kt
@@ -17,6 +17,7 @@ data class Dimensions(
val cellHeight: Dp = 56.dp,
val cellHeightTwoRows: Dp = 72.dp,
val cellStartPadding: Dp = 14.dp,
+ val cellStartPaddingLarge: Dp = 50.dp,
val cellTopPadding: Dp = 6.dp,
val cellVerticalSpacing: Dp = 24.dp,
val chipSpace: Dp = 8.dp,
@@ -44,8 +45,8 @@ data class Dimensions(
val mediumPadding: Dp = 16.dp,
val mediumSpacer: Dp = 16.dp,
val miniPadding: Dp = 4.dp,
- val mullvadLogoTextStartPadding: Dp = 6.dp,
val mullvadLogoTextHeight: Dp = 13.dp,
+ val mullvadLogoTextStartPadding: Dp = 6.dp,
val notificationBannerEndPadding: Dp = 8.dp,
val notificationBannerStartPadding: Dp = 16.dp,
val notificationEndIconPadding: Dp = 4.dp,
@@ -58,7 +59,6 @@ data class Dimensions(
val relayCircleSize: Dp = 16.dp,
val screenVerticalMargin: Dp = 24.dp,
val searchFieldHeight: Dp = 42.dp,
- // Search view full screen header container height (material design guidelines)
val searchFieldHeightExpanded: Dp = 72.dp,
val searchFieldHorizontalPadding: Dp = 22.dp,
val searchIconSize: Dp = 24.dp,
@@ -78,9 +78,9 @@ data class Dimensions(
val tinyPadding: Dp = 4.dp,
val titleIconSize: Dp = 48.dp,
val topPadding: Dp = 20.dp,
- val tvDrawerHorizontalPadding: Dp = 12.dp,
val tvDrawerHeaderStartPadding: Dp = 12.dp,
val tvDrawerHeaderWithFocusStartPadding: Dp = 16.dp,
+ val tvDrawerHorizontalPadding: Dp = 12.dp,
val verticalDividerPadding: Dp = 12.dp,
val verticalSpace: Dp = 20.dp,
val verticalSpacer: Dp = 1.dp,