Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Be more clear with connection state #7401

Merged
merged 5 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ class ConnectScreenTest {
)

// Assert
onNodeWithText("DISCONNECTED").assertExists()
onNodeWithText("DISCONNECTING...").assertExists()
onNodeWithText(mockLocationName).assertExists()
onNodeWithText("Disconnect").assertExists()
}
Expand Down Expand Up @@ -310,7 +310,7 @@ class ConnectScreenTest {
)

// Assert
onNodeWithText("CONNECTED").assertExists()
onNodeWithText("BLOCKING...").assertExists()
onNodeWithText(mockLocationName).assertExists()
onNodeWithText("Disconnect").assertExists()
onNodeWithText("BLOCKING INTERNET").assertExists()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ private fun TunnelState.text() =
is TunnelState.Disconnected -> textResource(id = R.string.disconnected)
is TunnelState.Disconnecting ->
when (actionAfterDisconnect) {
ActionAfterDisconnect.Nothing -> textResource(id = R.string.disconnected)
ActionAfterDisconnect.Block -> textResource(id = R.string.connected)
ActionAfterDisconnect.Nothing -> textResource(id = R.string.disconnecting)
ActionAfterDisconnect.Block -> textResource(id = R.string.blocking)
ActionAfterDisconnect.Reconnect -> textResource(id = R.string.connecting)
}
is TunnelState.Error ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package net.mullvad.mullvadvpn.util
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

inline fun <T1, T2, T3, T4, T5, T6, R> combine(
flow: Flow<T1>,
Expand Down Expand Up @@ -61,3 +62,11 @@ fun <T> Deferred<T>.getOrDefault(default: T) =
} catch (e: IllegalStateException) {
default
}

fun <T> Flow<T>.withPrev(): Flow<Pair<T, T?>> = flow {
var prev: T? = null
collect { curr ->
emit(curr to prev)
prev = curr
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import kotlinx.coroutines.FlowPreview
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filterIsInstance
import kotlinx.coroutines.flow.map
Expand Down Expand Up @@ -36,6 +35,7 @@ import net.mullvad.mullvadvpn.usecase.SelectedLocationTitleUseCase
import net.mullvad.mullvadvpn.util.combine
import net.mullvad.mullvadvpn.util.daysFromNow
import net.mullvad.mullvadvpn.util.isSuccess
import net.mullvad.mullvadvpn.util.withPrev

@Suppress("LongParameterList")
class ConnectViewModel(
Expand All @@ -62,14 +62,14 @@ class ConnectViewModel(
combine(
selectedLocationTitleUseCase(),
inAppNotificationController.notifications,
connectionProxy.tunnelState,
connectionProxy.tunnelState.withPrev(),
lastKnownLocationUseCase.lastKnownDisconnectedLocation,
accountRepository.accountData,
deviceRepository.deviceState.map { it?.displayName() },
) {
selectedRelayItemTitle,
notifications,
tunnelState,
(tunnelState, prevTunnelState),
lastKnownDisconnectedLocation,
accountData,
deviceName ->
Expand All @@ -80,14 +80,22 @@ class ConnectViewModel(
tunnelState.location ?: lastKnownDisconnectedLocation
is TunnelState.Connecting -> tunnelState.location
is TunnelState.Connected -> tunnelState.location
is TunnelState.Disconnecting -> lastKnownDisconnectedLocation
is TunnelState.Disconnecting ->
when (tunnelState.actionAfterDisconnect) {
ActionAfterDisconnect.Nothing -> lastKnownDisconnectedLocation
ActionAfterDisconnect.Block -> lastKnownDisconnectedLocation
// Keep the previous connected location when reconnecting, after
// this state we will reach Connecting with the new relay
// location
ActionAfterDisconnect.Reconnect -> prevTunnelState?.location()
}
is TunnelState.Error -> lastKnownDisconnectedLocation
},
selectedRelayItemTitle = selectedRelayItemTitle,
tunnelState = tunnelState,
showLocation =
when (tunnelState) {
is TunnelState.Disconnected -> true
is TunnelState.Disconnected -> tunnelState.location != null
is TunnelState.Disconnecting -> {
when (tunnelState.actionAfterDisconnect) {
ActionAfterDisconnect.Nothing -> false
Expand All @@ -105,7 +113,6 @@ class ConnectViewModel(
isPlayBuild = isPlayBuild,
)
}
.debounce(UI_STATE_DEBOUNCE_DURATION_MILLIS)
.stateIn(viewModelScope, SharingStarted.WhileSubscribed(), ConnectUiState.INITIAL)

init {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,12 +171,11 @@ class ConnectViewModelTest {
fun `given RelayListUseCase returns new selectedRelayItem uiState should emit new selectedRelayItem`() =
runTest {
val selectedRelayItemTitle = "Item"
selectedRelayItemFlow.value = selectedRelayItemTitle

viewModel.uiState.test {
assertEquals(ConnectUiState.INITIAL, awaitItem())
val result = awaitItem()
assertEquals(selectedRelayItemTitle, result.selectedRelayItemTitle)

selectedRelayItemFlow.value = selectedRelayItemTitle
assertEquals(selectedRelayItemTitle, awaitItem().selectedRelayItemTitle)
}
}

Expand All @@ -196,7 +195,6 @@ class ConnectViewModelTest {

// Act, Assert
viewModel.uiState.test {
assertEquals(ConnectUiState.INITIAL, awaitItem())
tunnelState.emit(TunnelState.Disconnected(null))

// Start of with no location
Expand All @@ -215,12 +213,7 @@ class ConnectViewModelTest {
val locationTestItem = null

// Act, Assert
viewModel.uiState.test {
assertEquals(ConnectUiState.INITIAL, awaitItem())
expectNoEvents()
val result = awaitItem()
assertEquals(locationTestItem, result.location)
}
viewModel.uiState.test { assertEquals(locationTestItem, awaitItem().location) }
}

@Test
Expand Down Expand Up @@ -278,15 +271,12 @@ class ConnectViewModelTest {
val mockErrorState: ErrorState = mockk()
val expectedConnectNotificationState =
InAppNotification.TunnelStateError(mockErrorState)
val tunnelStateError = TunnelState.Error(mockErrorState)
notifications.value = listOf(expectedConnectNotificationState)

// Act, Assert
viewModel.uiState.test {
assertEquals(ConnectUiState.INITIAL, awaitItem())
tunnelState.emit(tunnelStateError)
val result = awaitItem()
assertEquals(expectedConnectNotificationState, result.inAppNotification)
notifications.value = listOf(expectedConnectNotificationState)
assertEquals(expectedConnectNotificationState, awaitItem().inAppNotification)
}
}

Expand Down Expand Up @@ -315,7 +305,6 @@ class ConnectViewModelTest {
viewModel.uiState.test {
awaitItem()
outOfTimeViewFlow.value = true
awaitItem()
}

// Assert
Expand All @@ -328,12 +317,13 @@ class ConnectViewModelTest {
// Arrange
val tunnel = TunnelState.Error(mockk(relaxed = true))
val lastKnownLocation: GeoIpLocation = mockk(relaxed = true)
lastKnownLocationFlow.emit(lastKnownLocation)
tunnelState.emit(tunnel)

// Act, Assert
viewModel.uiState.test {
assertEquals(ConnectUiState.INITIAL, awaitItem())
lastKnownLocationFlow.emit(lastKnownLocation)
tunnelState.emit(tunnel)
awaitItem()
val result = awaitItem()
assertEquals(lastKnownLocation, result.location)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-da/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Det gør den ved at udføre en ekstra nøgleudveksling ved hjælp af en kvantesikker algoritme og blande resultatet med WireGuards almindelige kryptering. Dette ekstra trin bruger cirka 500 kB trafik, hver gang en ny tunnel etableres.</string>
<string name="quantum_resistant_title">Kvante-modstandsdygtig tunnel</string>
<string name="reconnect">Genopret forbindelse</string>
<string name="reconnecting">Genopretter forbindelse...</string>
<string name="redeem">Indløs</string>
<string name="redeem_voucher">Indløs kupon</string>
<string name="remove_button">Fjern</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-de/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Dazu wird ein zusätzlicher Schlüsselaustausch mit einem quantensicheren Algorithmus durchgeführt und das Ergebnis mit der regulären Verschlüsselung von WireGuard vermischt. Dieser zusätzliche Schritt verbraucht jedes Mal, wenn ein neuer Tunnel aufgebaut wird, etwa 500 KiB an Datenverkehr.</string>
<string name="quantum_resistant_title">Quantenresistenter Tunnel</string>
<string name="reconnect">Erneut verbinden</string>
<string name="reconnecting">Wiederherstellen der Verbindung …</string>
<string name="redeem">Einlösen</string>
<string name="redeem_voucher">Gutschein einlösen</string>
<string name="remove_button">Entfernen</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-es/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Lo hace al realizar un intercambio de claves adicional usando un algoritmo cuántico seguro y combinando el resultado en el cifrado normal de WireGuard. Este paso extra utiliza aproximadamente 500 kiB de tráfico cada vez que se establece un nuevo túnel.</string>
<string name="quantum_resistant_title">Túnel con resistencia cuántica</string>
<string name="reconnect">Reconectar</string>
<string name="reconnecting">Volviendo a establecer la conexión...</string>
<string name="redeem">Canjear</string>
<string name="redeem_voucher">Canjear cupón</string>
<string name="remove_button">Quitar</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-fi/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Tunneli torjuu hyökkäykset suorittamalla ylimääräisen avaimenvaihdon käyttämällä ensin kvanttiturvallista algoritmia, jonka tuloksen se sekoittaa WireGuardin tavalliseen salaukseen. Tämä ylimääräinen vaihe käyttää noin 500 kiB liikennettä joka kerta, kun uusi tunneli luodaan.</string>
<string name="quantum_resistant_title">Kvanttihyökkäyksiä kestävä tunneli</string>
<string name="reconnect">Yhdistä uudelleen</string>
<string name="reconnecting">Yhdistetään uudelleen...</string>
<string name="redeem">Lunasta</string>
<string name="redeem_voucher">Lunasta kuponki</string>
<string name="remove_button">Poista</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-fr/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Pour ce faire, il effectue un échange de clés supplémentaire à l\'aide d\'un algorithme à sécurité quantique et mélange le résultat au chiffrement habituel de WireGuard. Cette étape supplémentaire utilise environ 500 kiB de trafic chaque fois qu\'un nouveau tunnel est établi.</string>
<string name="quantum_resistant_title">Tunnel résistant aux attaques quantiques</string>
<string name="reconnect">Reconnexion</string>
<string name="reconnecting">Reconnexion en cours...</string>
<string name="redeem">Échanger</string>
<string name="redeem_voucher">Échanger un bon</string>
<string name="remove_button">Supprimer</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-it/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">L\'operazione viene effettuata eseguendo uno scambio di chiavi aggiuntivo con un algoritmo di sicurezza quantistica e mescolando il risultato nella normale crittografia di WireGuard. Questo passaggio aggiuntivo utilizza circa 500 kiB di traffico ogni volta che viene stabilito un nuovo tunnel.</string>
<string name="quantum_resistant_title">Tunnel resistente agli attacchi quantistici</string>
<string name="reconnect">Riconnetti</string>
<string name="reconnecting">Riconnessione...</string>
<string name="redeem">Riscatta</string>
<string name="redeem_voucher">Riscatta voucher</string>
<string name="remove_button">Rimuovi</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-ja/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">耐量子アルゴリズムで追加の鍵の交換を実行し、結果をWireGuardの通常の暗号化に混合させることで行われます。この追加ステップでは、新しいトンネルが確立されるたびに約500kiBのトラフィックが使用されます。</string>
<string name="quantum_resistant_title">耐量子トンネル</string>
<string name="reconnect">再接続</string>
<string name="reconnecting">再接続中…</string>
<string name="redeem">使用する</string>
<string name="redeem_voucher">バウチャーを使用する</string>
<string name="remove_button">削除</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-ko/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">이를 위해 양자 안전 알고리즘을 사용하여 추가 키 교환을 수행하고 결과를 WireGuard의 일반 암호화에 혼합하는 방법이 이용됩니다. 이 추가 단계는 새 터널이 설정될 때마다 약 500kiB의 트래픽을 사용합니다.</string>
<string name="quantum_resistant_title">양자 저항 터널</string>
<string name="reconnect">다시 연결</string>
<string name="reconnecting">다시 연결 중...</string>
<string name="redeem">사용</string>
<string name="redeem_voucher">바우처 사용</string>
<string name="remove_button">제거</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-my/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Quantum Safe အယ်လဂိုရီသမ်တစ်ခုကို သုံး၍ ထပ်ဆောင်း ကီးဖလှယ်မှုတစ်ခုကို ဆောင်ရွက်ပြီး WireGuard ၏ ပုံမှန် ကုဒ်ပြောင်းဝှက်မှုအတွင်း ရလဒ်ကို ရောနှောခြင်းအားဖြင့် ဤသည်ကို လုပ်ဆောင်ပါသည်။ ဤထပ်ဆောင်းအဆင့်သည် Tunnel အသစ်တစ်ခု တည်ဆောက်တိုင်း ဒေတာ 500 kiB ခန့်ကို သုံးပါသည်။</string>
<string name="quantum_resistant_title">Quantum-resistant Tunnel</string>
<string name="reconnect">ပြန်ချိတ်ဆက်ရန်</string>
<string name="reconnecting">ပြန်ချိတ်ဆက်နေသည်...</string>
<string name="redeem">လဲယူရန်</string>
<string name="redeem_voucher">ဘောက်ချာဖြင့် လဲယူရန်</string>
<string name="remove_button">ဖယ်ရှားရန်</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-nb/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Det gjøres ved at å utføre en ekstra nøkkelutveksling med en kvantesikker algoritme og kombinere resultatet med WireGuard sin vanlige kryptering. Dette ekstratrinnet bruker omtrent 500 kiB trafikk hver gang det opprettes en ny tunnel.</string>
<string name="quantum_resistant_title">Kvantebestandig tunnel</string>
<string name="reconnect">Koble til på nytt</string>
<string name="reconnecting">Kobler til på nytt ...</string>
<string name="redeem">Løs inn</string>
<string name="redeem_voucher">Løs inn kupong</string>
<string name="remove_button">Fjern</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-nl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Het doet dit door een extra sleuteluitwisseling uit te voeren met een kwantumveilig algoritme en het resultaat te mengen met de reguliere versleuteling van WireGuard. Deze extra stap gebruikt ongeveer 500 kiB aan verkeer elke keer dat een nieuwe tunnel wordt opgezet.</string>
<string name="quantum_resistant_title">Kwantumbestendige tunnel</string>
<string name="reconnect">Opnieuw verbinden</string>
<string name="reconnecting">Opnieuw verbinden...</string>
<string name="redeem">Inwisselen</string>
<string name="redeem_voucher">Voucher inwisselen</string>
<string name="remove_button">Verwijderen</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-pl/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Jest to wykonywane poprzez dodatkową wymianę kluczy przy użyciu algorytmu odpornego na ataki z użyciem komputerów kwantowych i zmieszanie wyniku ze zwykłym szyfrowaniem WireGuard. Ten dodatkowy krok zużywa około 500 kB ruchu za każdym razem, gdy ustanawiany jest nowy tunel.</string>
<string name="quantum_resistant_title">Tunel odporny na ataki z użyciem komputerów kwantowych</string>
<string name="reconnect">Połącz ponownie</string>
<string name="reconnecting">Ponowne łączenie...</string>
<string name="redeem">Zrealizuj</string>
<string name="redeem_voucher">Zrealizuj kupon</string>
<string name="remove_button">Usuń</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-pt/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Fá-lo ao realizar uma troca de chaves adicional utilizando um algoritmo de segurança quântica e misturando o resultado na encriptação regular do WireGuard. Este passo adicional utiliza aproximadamente 500 kiB de tráfego sempre que um novo túnel é estabelecido.</string>
<string name="quantum_resistant_title">Túnel com resistência quântica</string>
<string name="reconnect">Religar</string>
<string name="reconnecting">A religar...</string>
<string name="redeem">Reclamar</string>
<string name="redeem_voucher">Reclamar voucher</string>
<string name="remove_button">Remover</string>
Expand Down
1 change: 0 additions & 1 deletion android/lib/resource/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,6 @@
<string name="quantum_resistant_info_second_paragaph">Для этого функция выполняет дополнительный обмен ключами с использованием квантово-устойчивого алгоритма и добавляет результат к обычному шифрованию WireGuard. Эта дополнительная мера использует примерно 500 КиБ трафика при каждом создании нового туннеля.</string>
<string name="quantum_resistant_title">Квантово-устойчивый туннель</string>
<string name="reconnect">Переподключить</string>
<string name="reconnecting">Идет переподключение...</string>
<string name="redeem">Погасить</string>
<string name="redeem_voucher">Погасить ваучер</string>
<string name="remove_button">Удалить</string>
Expand Down
Loading
Loading