diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt index ca1649c8ab9a..8108c400fc53 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/AccountScreenTest.kt @@ -29,7 +29,8 @@ import org.junit.Test @OptIn(ExperimentalMaterial3Api::class) class AccountScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { @@ -42,8 +43,7 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState( + uiState = AccountUiState( deviceName = DUMMY_DEVICE_NAME, accountNumber = DUMMY_ACCOUNT_NUMBER, accountExpiry = null, @@ -67,8 +67,7 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState( + uiState = AccountUiState( deviceName = DUMMY_DEVICE_NAME, accountNumber = DUMMY_ACCOUNT_NUMBER, accountExpiry = null, @@ -93,8 +92,7 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState( + uiState = AccountUiState( deviceName = DUMMY_DEVICE_NAME, accountNumber = DUMMY_ACCOUNT_NUMBER, accountExpiry = null, @@ -119,8 +117,7 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState( + uiState = AccountUiState( deviceName = DUMMY_DEVICE_NAME, accountNumber = DUMMY_ACCOUNT_NUMBER, accountExpiry = null, @@ -144,12 +141,9 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default() - .copy( - paymentDialogData = - PurchaseResult.Completed.Success.toPaymentDialogData(), - ), + uiState = AccountUiState.default().copy( + paymentDialogData = PurchaseResult.Completed.Success.toPaymentDialogData(), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) @@ -165,12 +159,10 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default() - .copy( - paymentDialogData = - PurchaseResult.Error.VerificationError(null).toPaymentDialogData(), - ), + uiState = AccountUiState.default().copy( + paymentDialogData = PurchaseResult.Error.VerificationError(null) + .toPaymentDialogData(), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) @@ -186,13 +178,12 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default() - .copy( - paymentDialogData = - PurchaseResult.Error.FetchProductsError(ProductId(""), null) - .toPaymentDialogData(), - ), + uiState = AccountUiState.default().copy( + paymentDialogData = PurchaseResult.Error.FetchProductsError( + ProductId(""), + null, + ).toPaymentDialogData(), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) @@ -208,8 +199,8 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default().copy(billingPaymentState = PaymentState.Error.Billing), + uiState = AccountUiState.default() + .copy(billingPaymentState = PaymentState.Error.Billing), uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) @@ -228,12 +219,13 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = AccountUiState.default().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) @@ -252,12 +244,13 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = AccountUiState.default().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) @@ -276,12 +269,13 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = AccountUiState.default().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) @@ -291,11 +285,9 @@ class AccountScreenTest { composeTestRule.onNodeWithTag(PLAY_PAYMENT_INFO_ICON_TEST_TAG).performClick() // Assert - composeTestRule - .onNodeWithText( - "We are currently verifying your purchase, this might take some time. Your time will be added if the verification is successful.", - ) - .assertExists() + composeTestRule.onNodeWithText( + "We are currently verifying your purchase, this might take some time. Your time will be added if the verification is successful.", + ).assertExists() } @Test @@ -307,12 +299,13 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = AccountUiState.default().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) @@ -333,12 +326,13 @@ class AccountScreenTest { composeTestRule.setContentWithTheme { AccountScreen( showSitePayment = true, - uiState = - AccountUiState.default() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = AccountUiState.default().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), onPurchaseBillingProductClick = clickHandler, uiSideEffect = MutableSharedFlow().asSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ChangelogDialogTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ChangelogDialogTest.kt index 8db049a3672b..32fcab25f493 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ChangelogDialogTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ChangelogDialogTest.kt @@ -19,9 +19,11 @@ import org.junit.Rule import org.junit.Test class ChangelogDialogTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() - @MockK lateinit var mockedViewModel: ChangelogViewModel + @MockK + lateinit var mockedViewModel: ChangelogViewModel @Before fun setup() { @@ -31,8 +33,11 @@ class ChangelogDialogTest { @Test fun testShowChangeLogWhenNeeded() { // Arrange - every { mockedViewModel.uiState } returns - MutableStateFlow(ChangelogDialogUiState.Show(listOf(CHANGELOG_ITEM))) + every { mockedViewModel.uiState } returns MutableStateFlow( + ChangelogDialogUiState.Show( + listOf(CHANGELOG_ITEM), + ), + ) every { mockedViewModel.dismissChangelogDialog() } just Runs composeTestRule.setContentWithTheme { diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt index eed4404891e2..66e9d4010716 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/ConnectScreenTest.kt @@ -39,7 +39,8 @@ import org.junit.Rule import org.junit.Test class ConnectScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { @@ -74,8 +75,7 @@ class ConnectScreenTest { // Arrange composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connecting(null, null), @@ -109,13 +109,11 @@ class ConnectScreenTest { every { mockTunnelEndpoint.quantumResistant } returns true composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connecting(endpoint = mockTunnelEndpoint, null), - tunnelRealState = - TunnelState.Connecting(endpoint = mockTunnelEndpoint, null), + tunnelRealState = TunnelState.Connecting(endpoint = mockTunnelEndpoint, null), inAddress = null, outAddress = "", showLocation = false, @@ -144,8 +142,7 @@ class ConnectScreenTest { val mockTunnelEndpoint: TunnelEndpoint = mockk(relaxed = true) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connected(mockTunnelEndpoint, null), @@ -177,8 +174,7 @@ class ConnectScreenTest { every { mockTunnelEndpoint.quantumResistant } returns true composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connected(mockTunnelEndpoint, null), @@ -211,8 +207,7 @@ class ConnectScreenTest { every { mockRelayLocation.locationName } returns mockLocationName composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = mockRelayLocation, tunnelUiState = TunnelState.Disconnecting(ActionAfterDisconnect.Nothing), @@ -245,8 +240,7 @@ class ConnectScreenTest { every { mockRelayLocation.locationName } returns mockLocationName composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = mockRelayLocation, tunnelUiState = TunnelState.Disconnected, @@ -279,22 +273,28 @@ class ConnectScreenTest { every { mockRelayLocation.locationName } returns mockLocationName composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = mockRelayLocation, - tunnelUiState = - TunnelState.Error(ErrorState(ErrorStateCause.StartTunnelError, true)), - tunnelRealState = - TunnelState.Error(ErrorState(ErrorStateCause.StartTunnelError, true)), + tunnelUiState = TunnelState.Error( + ErrorState( + ErrorStateCause.StartTunnelError, + true, + ), + ), + tunnelRealState = TunnelState.Error( + ErrorState( + ErrorStateCause.StartTunnelError, + true, + ), + ), inAddress = null, outAddress = "", showLocation = true, isTunnelInfoExpanded = false, deviceName = "", daysLeftUntilExpiry = null, - inAppNotification = - InAppNotification.TunnelStateError( + inAppNotification = InAppNotification.TunnelStateError( ErrorState(ErrorStateCause.StartTunnelError, true), ), ), @@ -319,22 +319,28 @@ class ConnectScreenTest { every { mockRelayLocation.locationName } returns mockLocationName composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = mockRelayLocation, - tunnelUiState = - TunnelState.Error(ErrorState(ErrorStateCause.StartTunnelError, false)), - tunnelRealState = - TunnelState.Error(ErrorState(ErrorStateCause.StartTunnelError, false)), + tunnelUiState = TunnelState.Error( + ErrorState( + ErrorStateCause.StartTunnelError, + false, + ), + ), + tunnelRealState = TunnelState.Error( + ErrorState( + ErrorStateCause.StartTunnelError, + false, + ), + ), inAddress = null, outAddress = "", showLocation = true, isTunnelInfoExpanded = false, deviceName = "", daysLeftUntilExpiry = null, - inAppNotification = - InAppNotification.TunnelStateError( + inAppNotification = InAppNotification.TunnelStateError( ErrorState(ErrorStateCause.StartTunnelError, false), ), ), @@ -347,8 +353,10 @@ class ConnectScreenTest { onNodeWithText("FAILED TO SECURE CONNECTION").assertExists() onNodeWithText(mockLocationName).assertExists() onNodeWithText("Dismiss").assertExists() - onNodeWithText(text = "Critical error (your attention is required)", ignoreCase = true) - .assertExists() + onNodeWithText( + text = "Critical error (your attention is required)", + ignoreCase = true, + ).assertExists() } } @@ -357,13 +365,11 @@ class ConnectScreenTest { // Arrange composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Disconnecting(ActionAfterDisconnect.Reconnect), - tunnelRealState = - TunnelState.Disconnecting(ActionAfterDisconnect.Reconnect), + tunnelRealState = TunnelState.Disconnecting(ActionAfterDisconnect.Reconnect), inAddress = null, outAddress = "", showLocation = false, @@ -394,8 +400,7 @@ class ConnectScreenTest { every { mockRelayLocation.locationName } returns mockLocationName composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = mockRelayLocation, tunnelUiState = TunnelState.Disconnecting(ActionAfterDisconnect.Block), @@ -430,8 +435,7 @@ class ConnectScreenTest { val mockedClickHandler: () -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = mockRelayLocation, tunnelUiState = TunnelState.Disconnected, @@ -463,8 +467,7 @@ class ConnectScreenTest { val mockedClickHandler: () -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connected(mockTunnelEndpoint, null), @@ -496,8 +499,7 @@ class ConnectScreenTest { val mockedClickHandler: () -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connected(mockTunnelEndpoint, null), @@ -528,8 +530,7 @@ class ConnectScreenTest { val mockedClickHandler: () -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Disconnected, @@ -560,8 +561,7 @@ class ConnectScreenTest { val mockedClickHandler: () -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connecting(null, null), @@ -593,8 +593,7 @@ class ConnectScreenTest { val dummyLocation = GeoIpLocation(null, null, "dummy country", null, "dummy hostname") composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = dummyLocation, relayLocation = null, tunnelUiState = TunnelState.Connecting(null, null), @@ -633,8 +632,7 @@ class ConnectScreenTest { every { mockLocation.hostname } returns mockHostName composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = mockLocation, relayLocation = null, tunnelUiState = TunnelState.Connected(mockTunnelEndpoint, null), @@ -663,17 +661,15 @@ class ConnectScreenTest { @Test fun testOutdatedVersionNotification() { // Arrange - val versionInfo = - VersionInfo( - currentVersion = "1.0", - upgradeVersion = "1.1", - isOutdated = true, - isSupported = true, - ) + val versionInfo = VersionInfo( + currentVersion = "1.0", + upgradeVersion = "1.1", + isOutdated = true, + isSupported = true, + ) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connecting(null, null), @@ -700,17 +696,15 @@ class ConnectScreenTest { @Test fun testUnsupportedVersionNotification() { // Arrange - val versionInfo = - VersionInfo( - currentVersion = "1.0", - upgradeVersion = "1.1", - isOutdated = true, - isSupported = false, - ) + val versionInfo = VersionInfo( + currentVersion = "1.0", + upgradeVersion = "1.1", + isOutdated = true, + isSupported = false, + ) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connecting(null, null), @@ -732,8 +726,7 @@ class ConnectScreenTest { onNodeWithText("UNSUPPORTED VERSION").assertExists() onNodeWithText( "Your privacy might be at risk with this unsupported app version. Please update now.", - ) - .assertExists() + ).assertExists() } } @@ -743,8 +736,7 @@ class ConnectScreenTest { val expiryDate = DateTime(2020, 11, 11, 10, 10) composeTestRule.setContentWithTheme { ConnectScreen( - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connecting(null, null), @@ -772,18 +764,16 @@ class ConnectScreenTest { fun testOnUpdateVersionClick() { // Arrange val mockedClickHandler: () -> Unit = mockk(relaxed = true) - val versionInfo = - VersionInfo( - currentVersion = "1.0", - upgradeVersion = "1.1", - isOutdated = true, - isSupported = false, - ) + val versionInfo = VersionInfo( + currentVersion = "1.0", + upgradeVersion = "1.1", + isOutdated = true, + isSupported = false, + ) composeTestRule.setContentWithTheme { ConnectScreen( onUpdateVersionClick = mockedClickHandler, - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connecting(null, null), @@ -815,8 +805,7 @@ class ConnectScreenTest { composeTestRule.setContentWithTheme { ConnectScreen( onManageAccountClick = mockedClickHandler, - uiState = - ConnectUiState( + uiState = ConnectUiState( location = null, relayLocation = null, tunnelUiState = TunnelState.Connecting(null, null), @@ -846,8 +835,7 @@ class ConnectScreenTest { composeTestRule.setContentWithTheme { ConnectScreen( uiState = ConnectUiState.INITIAL, - uiSideEffect = - MutableStateFlow( + uiSideEffect = MutableStateFlow( ConnectViewModel.UiSideEffect.OpenAccountManagementPageInBrowser("222"), ), ) diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreenTest.kt index 56e24b9a08b8..2373dc028543 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/DeviceRevokedScreenTest.kt @@ -13,7 +13,8 @@ import org.junit.Rule import org.junit.Test class DeviceRevokedScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt index 8cf4efcc1989..080adf07568e 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/OutOfTimeScreenTest.kt @@ -29,7 +29,8 @@ import org.junit.Rule import org.junit.Test class OutOfTimeScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { @@ -58,8 +59,7 @@ class OutOfTimeScreenTest { onNodeWithText( "Either buy credit on our website or redeem a voucher.", substring = true, - ) - .assertDoesNotExist() + ).assertDoesNotExist() onNodeWithText("Buy credit").assertDoesNotExist() } } @@ -71,8 +71,7 @@ class OutOfTimeScreenTest { OutOfTimeScreen( showSitePayment = true, uiState = OutOfTimeUiState(deviceName = ""), - uiSideEffect = - MutableStateFlow(OutOfTimeViewModel.UiSideEffect.OpenAccountView("222")), + uiSideEffect = MutableStateFlow(OutOfTimeViewModel.UiSideEffect.OpenAccountView("222")), onSitePaymentClick = {}, onRedeemVoucherClick = {}, onSettingsClick = {}, @@ -165,8 +164,7 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState( + uiState = OutOfTimeUiState( tunnelState = TunnelState.Connecting(null, null), deviceName = "", ), @@ -193,8 +191,7 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState( + uiState = OutOfTimeUiState( paymentDialogData = PurchaseResult.Completed.Success.toPaymentDialogData(), ), uiSideEffect = MutableStateFlow(OutOfTimeViewModel.UiSideEffect.OpenConnectScreen), @@ -217,10 +214,9 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState( - paymentDialogData = - PurchaseResult.Error.VerificationError(null).toPaymentDialogData(), + uiState = OutOfTimeUiState( + paymentDialogData = PurchaseResult.Error.VerificationError(null) + .toPaymentDialogData(), ), uiSideEffect = MutableStateFlow(OutOfTimeViewModel.UiSideEffect.OpenConnectScreen), onSitePaymentClick = {}, @@ -242,13 +238,12 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState() - .copy( - paymentDialogData = - PurchaseResult.Error.FetchProductsError(ProductId(""), null) - .toPaymentDialogData(), - ), + uiState = OutOfTimeUiState().copy( + paymentDialogData = PurchaseResult.Error.FetchProductsError( + ProductId(""), + null, + ).toPaymentDialogData(), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), ) } @@ -287,10 +282,8 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = OutOfTimeUiState( + billingPaymentState = PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), ), uiSideEffect = MutableStateFlow(OutOfTimeViewModel.UiSideEffect.OpenConnectScreen), onSitePaymentClick = {}, @@ -315,12 +308,13 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = OutOfTimeUiState().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), ) } @@ -338,12 +332,13 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = OutOfTimeUiState().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), ) } @@ -352,11 +347,9 @@ class OutOfTimeScreenTest { composeTestRule.onNodeWithTag(PLAY_PAYMENT_INFO_ICON_TEST_TAG).performClick() // Assert - composeTestRule - .onNodeWithText( - "We are currently verifying your purchase, this might take some time. Your time will be added if the verification is successful.", - ) - .assertExists() + composeTestRule.onNodeWithText( + "We are currently verifying your purchase, this might take some time. Your time will be added if the verification is successful.", + ).assertExists() } @Test @@ -368,12 +361,13 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = OutOfTimeUiState().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), ) } @@ -393,10 +387,8 @@ class OutOfTimeScreenTest { composeTestRule.setContentWithTheme { OutOfTimeScreen( showSitePayment = true, - uiState = - OutOfTimeUiState( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = OutOfTimeUiState( + billingPaymentState = PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), ), uiSideEffect = MutableStateFlow(OutOfTimeViewModel.UiSideEffect.OpenConnectScreen), onSitePaymentClick = {}, diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt index 2b29a43d6e8f..033824ef7375 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/RedeemVoucherDialogTest.kt @@ -18,7 +18,8 @@ import org.junit.Rule import org.junit.Test class RedeemVoucherDialogTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { @@ -51,8 +52,7 @@ class RedeemVoucherDialogTest { val mockedClickHandler: (Boolean) -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { RedeemVoucherDialogScreen( - uiState = - VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Success(0)), + uiState = VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Success(0)), onVoucherInputChange = {}, onRedeem = {}, onDismiss = mockedClickHandler, @@ -91,8 +91,7 @@ class RedeemVoucherDialogTest { // Arrange composeTestRule.setContentWithTheme { RedeemVoucherDialogScreen( - uiState = - VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Verifying), + uiState = VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Verifying), onVoucherInputChange = {}, onRedeem = {}, onDismiss = {}, @@ -108,8 +107,7 @@ class RedeemVoucherDialogTest { // Arrange composeTestRule.setContentWithTheme { RedeemVoucherDialogScreen( - uiState = - VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Success(0)), + uiState = VoucherDialogUiState(voucherViewModelState = VoucherDialogState.Success(0)), onVoucherInputChange = {}, onRedeem = {}, onDismiss = {}, @@ -125,8 +123,7 @@ class RedeemVoucherDialogTest { // Arrange composeTestRule.setContentWithTheme { RedeemVoucherDialogScreen( - uiState = - VoucherDialogUiState( + uiState = VoucherDialogUiState( voucherViewModelState = VoucherDialogState.Error(ERROR_MESSAGE), ), onVoucherInputChange = {}, diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt index 07c93be41368..8d2cf436e6a2 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SelectLocationScreenTest.kt @@ -26,7 +26,8 @@ import org.junit.Rule import org.junit.Test class SelectLocationScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { @@ -53,8 +54,7 @@ class SelectLocationScreenTest { // Arrange composeTestRule.setContentWithTheme { SelectLocationScreen( - uiState = - SelectLocationUiState.ShowData( + uiState = SelectLocationUiState.ShowData( countries = DUMMY_RELAY_COUNTRIES, selectedRelay = null, ), @@ -76,22 +76,20 @@ class SelectLocationScreenTest { @Test fun testShowRelayListStateSelected() { - val updatedDummyList = - DUMMY_RELAY_COUNTRIES.let { - val cities = it[0].cities.toMutableList() - val city = cities.removeAt(0) - cities.add(0, city.copy(expanded = true)) - - val mutableRelayList = it.toMutableList() - mutableRelayList[0] = it[0].copy(expanded = true, cities = cities.toList()) - mutableRelayList - } + val updatedDummyList = DUMMY_RELAY_COUNTRIES.let { + val cities = it[0].cities.toMutableList() + val city = cities.removeAt(0) + cities.add(0, city.copy(expanded = true)) + + val mutableRelayList = it.toMutableList() + mutableRelayList[0] = it[0].copy(expanded = true, cities = cities.toList()) + mutableRelayList + } // Arrange composeTestRule.setContentWithTheme { SelectLocationScreen( - uiState = - SelectLocationUiState.ShowData( + uiState = SelectLocationUiState.ShowData( countries = updatedDummyList, selectedRelay = updatedDummyList[0].cities[0].relays[0], ), @@ -117,8 +115,10 @@ class SelectLocationScreenTest { val mockedSearchTermInput: (String) -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { SelectLocationScreen( - uiState = - SelectLocationUiState.ShowData(countries = emptyList(), selectedRelay = null), + uiState = SelectLocationUiState.ShowData( + countries = emptyList(), + selectedRelay = null, + ), uiCloseAction = MutableSharedFlow(), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), onSearchTermInput = mockedSearchTermInput, @@ -155,22 +155,20 @@ class SelectLocationScreenTest { } companion object { - private val DUMMY_RELAY_1 = - net.mullvad.mullvadvpn.model.Relay( - hostname = "Relay host 1", - active = true, - endpointData = RelayEndpointData.Wireguard(WireguardRelayEndpointData), - owned = true, - provider = "PROVIDER", - ) - private val DUMMY_RELAY_2 = - net.mullvad.mullvadvpn.model.Relay( - hostname = "Relay host 2", - active = true, - endpointData = RelayEndpointData.Wireguard(WireguardRelayEndpointData), - owned = true, - provider = "PROVIDER", - ) + private val DUMMY_RELAY_1 = net.mullvad.mullvadvpn.model.Relay( + hostname = "Relay host 1", + active = true, + endpointData = RelayEndpointData.Wireguard(WireguardRelayEndpointData), + owned = true, + provider = "PROVIDER", + ) + private val DUMMY_RELAY_2 = net.mullvad.mullvadvpn.model.Relay( + hostname = "Relay host 2", + active = true, + endpointData = RelayEndpointData.Wireguard(WireguardRelayEndpointData), + owned = true, + provider = "PROVIDER", + ) private val DUMMY_RELAY_CITY_1 = RelayListCity("Relay City 1", "RCi1", arrayListOf(DUMMY_RELAY_1)) private val DUMMY_RELAY_CITY_2 = @@ -184,11 +182,9 @@ class SelectLocationScreenTest { private val DUMMY_WIREGUARD_ENDPOINT_DATA = WireguardEndpointData(DUMMY_WIREGUARD_PORT_RANGES) - private val DUMMY_RELAY_COUNTRIES = - RelayList( - arrayListOf(DUMMY_RELAY_COUNTRY_1, DUMMY_RELAY_COUNTRY_2), - DUMMY_WIREGUARD_ENDPOINT_DATA, - ) - .toRelayCountries(ownership = Constraint.Any(), providers = Constraint.Any()) + private val DUMMY_RELAY_COUNTRIES = RelayList( + arrayListOf(DUMMY_RELAY_COUNTRY_1, DUMMY_RELAY_COUNTRY_2), + DUMMY_WIREGUARD_ENDPOINT_DATA, + ).toRelayCountries(ownership = Constraint.Any(), providers = Constraint.Any()) } } diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt index 47dfd5505369..ba6b135abf9d 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SettingsScreenTest.kt @@ -13,7 +13,8 @@ import org.junit.Rule import org.junit.Test class SettingsScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { @@ -26,8 +27,11 @@ class SettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { SettingsScreen( - uiState = - SettingsUiState(appVersion = "", isLoggedIn = true, isUpdateAvailable = true), + uiState = SettingsUiState( + appVersion = "", + isLoggedIn = true, + isUpdateAvailable = true, + ), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) } @@ -45,8 +49,11 @@ class SettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { SettingsScreen( - uiState = - SettingsUiState(appVersion = "", isLoggedIn = false, isUpdateAvailable = true), + uiState = SettingsUiState( + appVersion = "", + isLoggedIn = false, + isUpdateAvailable = true, + ), enterTransitionEndAction = MutableSharedFlow().asSharedFlow(), ) } diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt index e46c9839d1a2..d58802c58be2 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/SplitTunnelingScreenTest.kt @@ -22,7 +22,8 @@ import org.koin.core.context.unloadKoinModules import org.koin.dsl.module class SplitTunnelingScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() private val mockBitmap: Bitmap = Bitmap.createBitmap(10, 10, Bitmap.Config.ARGB_8888) private val testModule = module { @@ -71,8 +72,7 @@ class SplitTunnelingScreenTest { AppData(packageName = INCLUDED_APP_PACKAGE_NAME, iconRes = 0, name = INCLUDED_APP_NAME) composeTestRule.setContentWithTheme { SplitTunnelingScreen( - uiState = - SplitTunnelingUiState.ShowAppList( + uiState = SplitTunnelingUiState.ShowAppList( excludedApps = listOf(excludedApp), includedApps = listOf(includedApp), showSystemApps = false, @@ -99,8 +99,7 @@ class SplitTunnelingScreenTest { AppData(packageName = INCLUDED_APP_PACKAGE_NAME, iconRes = 0, name = INCLUDED_APP_NAME) composeTestRule.setContentWithTheme { SplitTunnelingScreen( - uiState = - SplitTunnelingUiState.ShowAppList( + uiState = SplitTunnelingUiState.ShowAppList( excludedApps = emptyList(), includedApps = listOf(includedApp), showSystemApps = false, @@ -130,8 +129,7 @@ class SplitTunnelingScreenTest { val mockedClickHandler: (String) -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { SplitTunnelingScreen( - uiState = - SplitTunnelingUiState.ShowAppList( + uiState = SplitTunnelingUiState.ShowAppList( excludedApps = listOf(excludedApp), includedApps = listOf(includedApp), showSystemApps = false, @@ -157,8 +155,7 @@ class SplitTunnelingScreenTest { val mockedClickHandler: (String) -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { SplitTunnelingScreen( - uiState = - SplitTunnelingUiState.ShowAppList( + uiState = SplitTunnelingUiState.ShowAppList( excludedApps = listOf(excludedApp), includedApps = listOf(includedApp), showSystemApps = false, @@ -184,8 +181,7 @@ class SplitTunnelingScreenTest { val mockedClickHandler: (Boolean) -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { SplitTunnelingScreen( - uiState = - SplitTunnelingUiState.ShowAppList( + uiState = SplitTunnelingUiState.ShowAppList( excludedApps = listOf(excludedApp), includedApps = listOf(includedApp), showSystemApps = false, 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 54662520f8bd..e44fbcf08ac2 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 @@ -38,7 +38,8 @@ import org.junit.Rule import org.junit.Test class VpnSettingsScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { @@ -57,8 +58,7 @@ class VpnSettingsScreenTest { composeTestRule.apply { onNodeWithText("Auto-connect").assertExists() } - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) // Assert @@ -78,8 +78,7 @@ class VpnSettingsScreenTest { ) } - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) // Assert @@ -98,8 +97,7 @@ class VpnSettingsScreenTest { ) } - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) // Act @@ -114,8 +112,7 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( dialog = VpnSettingsDialog.Mtu(mtuEditValue = EMPTY_STRING), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), @@ -131,8 +128,7 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( dialog = VpnSettingsDialog.Mtu(mtuEditValue = VALID_DUMMY_MTU_VALUE), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), @@ -148,8 +144,7 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( dialog = VpnSettingsDialog.Mtu(mtuEditValue = EMPTY_STRING), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), @@ -169,8 +164,7 @@ class VpnSettingsScreenTest { val mockedSubmitHandler: (Int) -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( dialog = VpnSettingsDialog.Mtu(mtuEditValue = VALID_DUMMY_MTU_VALUE), ), onSaveMtuClick = mockedSubmitHandler, @@ -190,8 +184,7 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( dialog = VpnSettingsDialog.Mtu(mtuEditValue = INVALID_DUMMY_MTU_VALUE), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), @@ -208,8 +201,7 @@ class VpnSettingsScreenTest { val mockedClickHandler: () -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( dialog = VpnSettingsDialog.Mtu(mtuEditValue = EMPTY_STRING), ), onRestoreMtuClick = mockedClickHandler, @@ -230,8 +222,7 @@ class VpnSettingsScreenTest { val mockedClickHandler: () -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( dialog = VpnSettingsDialog.Mtu(mtuEditValue = EMPTY_STRING), ), onCancelMtuDialogClick = mockedClickHandler, @@ -251,12 +242,10 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( isCustomDnsEnabled = true, isAllowLanEnabled = false, - customDnsItems = - listOf( + customDnsItems = listOf( CustomDnsItem(address = DUMMY_DNS_ADDRESS, false), CustomDnsItem(address = DUMMY_DNS_ADDRESS_2, false), CustomDnsItem(address = DUMMY_DNS_ADDRESS_3, false), @@ -280,16 +269,14 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( isCustomDnsEnabled = false, customDnsItems = listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, false)), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), ) } - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_LAST_ITEM_TEST_TAG)) // Assert composeTestRule.onNodeWithText(DUMMY_DNS_ADDRESS).assertDoesNotExist() @@ -301,12 +288,15 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( isCustomDnsEnabled = true, isAllowLanEnabled = true, - customDnsItems = - listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true)), + customDnsItems = listOf( + CustomDnsItem( + address = DUMMY_DNS_ADDRESS, + isLocal = true, + ), + ), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), ) @@ -321,12 +311,15 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( isCustomDnsEnabled = true, isAllowLanEnabled = false, - customDnsItems = - listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false)), + customDnsItems = listOf( + CustomDnsItem( + address = DUMMY_DNS_ADDRESS, + isLocal = false, + ), + ), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), ) @@ -341,12 +334,15 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( isCustomDnsEnabled = true, isAllowLanEnabled = true, - customDnsItems = - listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = false)), + customDnsItems = listOf( + CustomDnsItem( + address = DUMMY_DNS_ADDRESS, + isLocal = false, + ), + ), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), ) @@ -361,12 +357,15 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( isCustomDnsEnabled = true, isAllowLanEnabled = false, - customDnsItems = - listOf(CustomDnsItem(address = DUMMY_DNS_ADDRESS, isLocal = true)), + customDnsItems = listOf( + CustomDnsItem( + address = DUMMY_DNS_ADDRESS, + isLocal = true, + ), + ), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), ) @@ -402,12 +401,9 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.Dns( - stagedDns = - StagedDns.NewDns( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.Dns( + stagedDns = StagedDns.NewDns( item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false), ), ), @@ -425,12 +421,9 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.Dns( - stagedDns = - StagedDns.EditDns( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.Dns( + stagedDns = StagedDns.EditDns( item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false), index = 0, ), @@ -449,12 +442,9 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.Dns( - stagedDns = - StagedDns.NewDns( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.Dns( + stagedDns = StagedDns.NewDns( item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = true), validationResult = StagedDns.ValidationResult.Success, ), @@ -474,12 +464,9 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.Dns( - stagedDns = - StagedDns.NewDns( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.Dns( + stagedDns = StagedDns.NewDns( item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = true), validationResult = StagedDns.ValidationResult.Success, ), @@ -499,12 +486,9 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.Dns( - stagedDns = - StagedDns.NewDns( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.Dns( + stagedDns = StagedDns.NewDns( item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false), validationResult = StagedDns.ValidationResult.Success, ), @@ -524,12 +508,9 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.Dns( - stagedDns = - StagedDns.NewDns( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.Dns( + stagedDns = StagedDns.NewDns( item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false), validationResult = StagedDns.ValidationResult.Success, ), @@ -549,12 +530,9 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.Dns( - stagedDns = - StagedDns.NewDns( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.Dns( + stagedDns = StagedDns.NewDns( item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false), validationResult = StagedDns.ValidationResult.InvalidAddress, ), @@ -573,15 +551,11 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.Dns( - stagedDns = - StagedDns.NewDns( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.Dns( + stagedDns = StagedDns.NewDns( item = CustomDnsItem(DUMMY_DNS_ADDRESS, isLocal = false), - validationResult = - StagedDns.ValidationResult.DuplicateAddress, + validationResult = StagedDns.ValidationResult.DuplicateAddress, ), ), ), @@ -598,19 +572,18 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault(quantumResistant = QuantumResistantState.On), + uiState = VpnSettingsUiState.createDefault(quantumResistant = QuantumResistantState.On), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), ) } - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG)) // Assert - composeTestRule - .onNodeWithTagAndText(testTag = LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG, text = "On") - .assertExists() + composeTestRule.onNodeWithTagAndText( + testTag = LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG, + text = "On", + ).assertExists() } @Test @@ -620,22 +593,21 @@ class VpnSettingsScreenTest { mockk(relaxed = true) composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( quantumResistant = QuantumResistantState.Auto, ), onSelectQuantumResistanceSetting = mockSelectQuantumResistantSettingListener, toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), ) } - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_QUANTUM_ITEM_OFF_TEST_TAG)) // Assert - composeTestRule - .onNodeWithTagAndText(testTag = LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG, text = "On") - .performClick() + composeTestRule.onNodeWithTagAndText( + testTag = LAZY_LIST_QUANTUM_ITEM_ON_TEST_TAG, + text = "On", + ).performClick() verify(exactly = 1) { mockSelectQuantumResistantSettingListener.invoke(QuantumResistantState.On) } @@ -646,8 +618,7 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( dialog = VpnSettingsDialog.QuantumResistanceInfo, ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), @@ -663,8 +634,7 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( selectedWireguardPort = Constraint.Only(Port(53)), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), @@ -672,19 +642,15 @@ class VpnSettingsScreenTest { } // Act - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) - .performScrollToNode( - hasTestTag(String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 53)), - ) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG).performScrollToNode( + hasTestTag(String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 53)), + ) // Assert - composeTestRule - .onNodeWithTagAndText( - testTag = String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 51820), - text = "51820", - ) - .assertExists() + composeTestRule.onNodeWithTagAndText( + testTag = String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 51820), + text = "51820", + ).assertExists() } @Test @@ -694,8 +660,7 @@ class VpnSettingsScreenTest { mockk(relaxed = true) composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( selectedWireguardPort = Constraint.Only(Port(53)), ), onWireguardPortSelected = mockSelectWireguardPortSelectionListener, @@ -704,17 +669,13 @@ class VpnSettingsScreenTest { } // Act - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) - .performScrollToNode( - hasTestTag(String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 53)), - ) - composeTestRule - .onNodeWithTagAndText( - testTag = String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 51820), - text = "51820", - ) - .performClick() + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG).performScrollToNode( + hasTestTag(String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 53)), + ) + composeTestRule.onNodeWithTagAndText( + testTag = String.format(LAZY_LIST_WIREGUARD_PORT_ITEM_X_TEST_TAG, 51820), + text = "51820", + ).performClick() // Assert verify(exactly = 1) { @@ -727,10 +688,8 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.WireguardPortInfo( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.WireguardPortInfo( availablePortRanges = listOf(PortRange(53, 53), PortRange(120, 121)), ), ), @@ -739,11 +698,9 @@ class VpnSettingsScreenTest { } // Assert - composeTestRule - .onNodeWithText( - "The automatic setting will randomly choose from the valid port ranges shown below.", - ) - .assertExists() + composeTestRule.onNodeWithText( + "The automatic setting will randomly choose from the valid port ranges shown below.", + ).assertExists() } @Test @@ -751,10 +708,8 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.CustomPort( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.CustomPort( availablePortRanges = listOf(PortRange(53, 53), PortRange(120, 121)), ), ), @@ -771,8 +726,7 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( selectedWireguardPort = Constraint.Only(Port(4000)), ), toastMessagesSharedFlow = MutableSharedFlow().asSharedFlow(), @@ -780,8 +734,7 @@ class VpnSettingsScreenTest { } // Act - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG)) // Assert @@ -801,8 +754,7 @@ class VpnSettingsScreenTest { } // Act - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG)) composeTestRule.onNodeWithTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG).performClick() @@ -816,8 +768,7 @@ class VpnSettingsScreenTest { val mockOnShowCustomPortDialog: () -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( selectedWireguardPort = Constraint.Only(Port(4000)), ), onShowCustomPortDialog = mockOnShowCustomPortDialog, @@ -826,11 +777,9 @@ class VpnSettingsScreenTest { } // Act - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG)) - composeTestRule - .onNodeWithTag(testTag = LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG) + composeTestRule.onNodeWithTag(testTag = LAZY_LIST_WIREGUARD_CUSTOM_PORT_NUMBER_TEST_TAG) .performClick() // Assert @@ -843,8 +792,7 @@ class VpnSettingsScreenTest { val onWireguardPortSelected: (Constraint) -> Unit = mockk(relaxed = true) composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( + uiState = VpnSettingsUiState.createDefault( selectedWireguardPort = Constraint.Only(Port(4000)), ), onWireguardPortSelected = onWireguardPortSelected, @@ -853,11 +801,9 @@ class VpnSettingsScreenTest { } // Act - composeTestRule - .onNodeWithTag(LAZY_LIST_TEST_TAG) + composeTestRule.onNodeWithTag(LAZY_LIST_TEST_TAG) .performScrollToNode(hasTestTag(LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG)) - composeTestRule - .onNodeWithTag(testTag = LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG) + composeTestRule.onNodeWithTag(testTag = LAZY_LIST_WIREGUARD_CUSTOM_PORT_TEXT_TEST_TAG) .performClick() // Assert @@ -872,10 +818,8 @@ class VpnSettingsScreenTest { // Arrange composeTestRule.setContentWithTheme { VpnSettingsScreen( - uiState = - VpnSettingsUiState.createDefault( - dialog = - VpnSettingsDialog.CustomPort( + uiState = VpnSettingsUiState.createDefault( + dialog = VpnSettingsDialog.CustomPort( availablePortRanges = listOf(PortRange(53, 53), PortRange(120, 121)), ), ), @@ -884,20 +828,17 @@ class VpnSettingsScreenTest { } // Act - composeTestRule - .onNodeWithTag(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG) + composeTestRule.onNodeWithTag(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG) .performTextInput("21474836471") // Assert - composeTestRule - .onNodeWithTagAndText(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG, "21474836471") + composeTestRule.onNodeWithTagAndText(CUSTOM_PORT_DIALOG_INPUT_TEST_TAG, "21474836471") .assertDoesNotExist() } companion object { private const val LOCAL_DNS_SERVER_WARNING = - "The local DNS server will not work unless you enable " + - "\"Local Network Sharing\" under Preferences." + "The local DNS server will not work unless you enable " + "\"Local Network Sharing\" under Preferences." private const val EMPTY_STRING = "" private const val VALID_DUMMY_MTU_VALUE = "1337" private const val INVALID_DUMMY_MTU_VALUE = "1111" diff --git a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt index 553040c2897a..d87404a3bb3e 100644 --- a/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt +++ b/android/app/src/androidTest/kotlin/net/mullvad/mullvadvpn/compose/screen/WelcomeScreenTest.kt @@ -28,7 +28,8 @@ import org.junit.Rule import org.junit.Test class WelcomeScreenTest { - @get:Rule val composeTestRule = createComposeRule() + @get:Rule + val composeTestRule = createComposeRule() @Before fun setup() { @@ -83,8 +84,7 @@ class WelcomeScreenTest { onNodeWithText( "Either buy credit on our website or redeem a voucher.", substring = true, - ) - .assertDoesNotExist() + ).assertDoesNotExist() onNodeWithText("Buy credit").assertDoesNotExist() } } @@ -120,8 +120,7 @@ class WelcomeScreenTest { WelcomeScreen( showSitePayment = true, uiState = WelcomeUiState(), - uiSideEffect = - MutableStateFlow(WelcomeViewModel.UiSideEffect.OpenAccountView("222")), + uiSideEffect = MutableStateFlow(WelcomeViewModel.UiSideEffect.OpenAccountView("222")), onSitePaymentClick = {}, onRedeemVoucherClick = {}, onSettingsClick = {}, @@ -217,8 +216,7 @@ class WelcomeScreenTest { composeTestRule.setContentWithTheme { WelcomeScreen( showSitePayment = true, - uiState = - WelcomeUiState( + uiState = WelcomeUiState( paymentDialogData = PurchaseResult.Completed.Success.toPaymentDialogData(), ), uiSideEffect = MutableStateFlow(WelcomeViewModel.UiSideEffect.OpenConnectScreen), @@ -242,10 +240,9 @@ class WelcomeScreenTest { composeTestRule.setContentWithTheme { WelcomeScreen( showSitePayment = true, - uiState = - WelcomeUiState( - paymentDialogData = - PurchaseResult.Error.VerificationError(null).toPaymentDialogData(), + uiState = WelcomeUiState( + paymentDialogData = PurchaseResult.Error.VerificationError(null) + .toPaymentDialogData(), ), uiSideEffect = MutableStateFlow(WelcomeViewModel.UiSideEffect.OpenConnectScreen), onSitePaymentClick = {}, @@ -268,13 +265,12 @@ class WelcomeScreenTest { composeTestRule.setContentWithTheme { WelcomeScreen( showSitePayment = true, - uiState = - WelcomeUiState() - .copy( - paymentDialogData = - PurchaseResult.Error.FetchProductsError(ProductId(""), null) - .toPaymentDialogData(), - ), + uiState = WelcomeUiState().copy( + paymentDialogData = PurchaseResult.Error.FetchProductsError( + ProductId(""), + null, + ).toPaymentDialogData(), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), onSitePaymentClick = {}, onRedeemVoucherClick = {}, @@ -321,10 +317,8 @@ class WelcomeScreenTest { composeTestRule.setContentWithTheme { WelcomeScreen( showSitePayment = true, - uiState = - WelcomeUiState( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = WelcomeUiState( + billingPaymentState = PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), ), uiSideEffect = MutableStateFlow(WelcomeViewModel.UiSideEffect.OpenConnectScreen), onSitePaymentClick = {}, @@ -350,12 +344,13 @@ class WelcomeScreenTest { composeTestRule.setContentWithTheme { WelcomeScreen( showSitePayment = true, - uiState = - WelcomeUiState() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = WelcomeUiState().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), onSitePaymentClick = {}, onRedeemVoucherClick = {}, @@ -380,12 +375,13 @@ class WelcomeScreenTest { composeTestRule.setContentWithTheme { WelcomeScreen( showSitePayment = true, - uiState = - WelcomeUiState() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = WelcomeUiState().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), onSitePaymentClick = {}, onRedeemVoucherClick = {}, @@ -401,11 +397,9 @@ class WelcomeScreenTest { composeTestRule.onNodeWithTag(PLAY_PAYMENT_INFO_ICON_TEST_TAG).performClick() // Assert - composeTestRule - .onNodeWithText( - "We are currently verifying your purchase, this might take some time. Your time will be added if the verification is successful.", - ) - .assertExists() + composeTestRule.onNodeWithText( + "We are currently verifying your purchase, this might take some time. Your time will be added if the verification is successful.", + ).assertExists() } @Test @@ -417,12 +411,13 @@ class WelcomeScreenTest { composeTestRule.setContentWithTheme { WelcomeScreen( showSitePayment = true, - uiState = - WelcomeUiState() - .copy( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = WelcomeUiState().copy( + billingPaymentState = PaymentState.PaymentAvailable( + listOf( + mockPaymentProduct, + ), ), + ), uiSideEffect = MutableSharedFlow().asSharedFlow(), onSitePaymentClick = {}, onRedeemVoucherClick = {}, @@ -449,10 +444,8 @@ class WelcomeScreenTest { composeTestRule.setContentWithTheme { WelcomeScreen( showSitePayment = true, - uiState = - WelcomeUiState( - billingPaymentState = - PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), + uiState = WelcomeUiState( + billingPaymentState = PaymentState.PaymentAvailable(listOf(mockPaymentProduct)), ), uiSideEffect = MutableStateFlow(WelcomeViewModel.UiSideEffect.OpenConnectScreen), onSitePaymentClick = {}, diff --git a/android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt b/android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt index ee4cd5219cf3..af01b13654d4 100644 --- a/android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt +++ b/android/lib/billing/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepositoryTest.kt @@ -43,7 +43,8 @@ import kotlin.test.assertEquals import kotlin.test.assertIs class BillingRepositoryTest { - @get:Rule val testCoroutineRule = TestCoroutineRule() + @get:Rule + val testCoroutineRule = TestCoroutineRule() private val mockContext: Context = mockk() private lateinit var billingRepository: BillingRepository @@ -64,8 +65,7 @@ class BillingRepositoryTest { every { BillingClient.newBuilder(any()) } returns mockBillingClientBuilder every { mockBillingClientBuilder.enablePendingPurchases() } returns mockBillingClientBuilder - every { mockBillingClientBuilder.setListener(capture(purchaseUpdatedListenerSlot)) } returns - mockBillingClientBuilder + every { mockBillingClientBuilder.setListener(capture(purchaseUpdatedListenerSlot)) } returns mockBillingClientBuilder every { mockBillingClientBuilder.build() } returns mockBillingClient billingRepository = BillingRepository(mockContext) @@ -89,8 +89,7 @@ class BillingRepositoryTest { every { mockBillingResult.responseCode } returns BillingResponseCode.OK every { mockBillingClient.isReady } returns true every { mockBillingClient.connectionState } returns BillingClient.ConnectionState.CONNECTED - coEvery { mockBillingClient.queryProductDetails(any()) } returns - expectedProductDetailsResult + coEvery { mockBillingClient.queryProductDetails(any()) } returns expectedProductDetailsResult every { expectedProductDetailsResult.billingResult } returns mockBillingResult every { expectedProductDetailsResult.productDetailsList } returns listOf(mockProductDetails) every { mockProductDetails.productId } returns productId @@ -160,12 +159,11 @@ class BillingRepositoryTest { every { mockActivityProvider() } returns mockk() // Act - val result = - billingRepository.startPurchaseFlow( - mockProductDetails, - transactionId, - mockActivityProvider, - ) + val result = billingRepository.startPurchaseFlow( + mockProductDetails, + transactionId, + mockActivityProvider, + ) // Assert assertEquals(mockBillingResult, result) @@ -186,12 +184,11 @@ class BillingRepositoryTest { every { mockActivityProvider() } returns mockk() // Act - val result = - billingRepository.startPurchaseFlow( - mockProductDetails, - transactionId, - mockActivityProvider, - ) + val result = billingRepository.startPurchaseFlow( + mockProductDetails, + transactionId, + mockActivityProvider, + ) // Assert assertEquals(mockBillingResult, result) @@ -206,8 +203,7 @@ class BillingRepositoryTest { every { mockResult.purchasesList } returns listOf(mockPurchase) every { mockBillingClient.isReady } returns true every { mockBillingClient.connectionState } returns BillingClient.ConnectionState.CONNECTED - coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns - mockResult + coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns mockResult every { BillingFlowParams.newBuilder() } returns mockk(relaxed = true) // Act @@ -225,8 +221,7 @@ class BillingRepositoryTest { every { mockResult.purchasesList } returns emptyList() every { mockBillingClient.isReady } returns true every { mockBillingClient.connectionState } returns BillingClient.ConnectionState.CONNECTED - coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns - mockResult + coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns mockResult every { BillingFlowParams.newBuilder() } returns mockk(relaxed = true) // Act @@ -248,8 +243,7 @@ class BillingRepositoryTest { every { mockResult.purchasesList } returns emptyList() every { mockBillingClient.isReady } returns true every { mockBillingClient.connectionState } returns BillingClient.ConnectionState.CONNECTED - coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns - mockResult + coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns mockResult every { BillingFlowParams.newBuilder() } returns mockk(relaxed = true) // Act @@ -323,16 +317,14 @@ class BillingRepositoryTest { // Arrange val mockStartConnectionResult: BillingResult = mockk() every { mockBillingClient.isReady } returns false - every { mockBillingClient.connectionState } returns - BillingClient.ConnectionState.DISCONNECTED - every { mockBillingClient.startConnection(any()) } answers - { - firstArg() - .onBillingSetupFinished(mockStartConnectionResult) - } + every { mockBillingClient.connectionState } returns BillingClient.ConnectionState.DISCONNECTED + every { mockBillingClient.startConnection(any()) } answers { + firstArg().onBillingSetupFinished(mockStartConnectionResult) + } every { mockStartConnectionResult.responseCode } returns BillingResponseCode.OK - coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns - mockk(relaxed = true) + coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns mockk( + relaxed = true, + ) // Act billingRepository.queryPurchases() @@ -344,40 +336,37 @@ class BillingRepositoryTest { @OptIn(ExperimentalCoroutinesApi::class) @Test - fun testEnsureConnectedOnlyOneSuccessfulConnection() = - runTest(UnconfinedTestDispatcher()) { - // Arrange - var hasConnected = false - val mockStartConnectionResult: BillingResult = mockk() - every { mockBillingClient.isReady } answers { hasConnected } - every { mockBillingClient.connectionState } answers - { - if (hasConnected) { - BillingClient.ConnectionState.CONNECTED - } else { - BillingClient.ConnectionState.DISCONNECTED - } - } - every { mockBillingClient.startConnection(any()) } answers - { - hasConnected = true - firstArg() - .onBillingSetupFinished(mockStartConnectionResult) - } - every { mockStartConnectionResult.responseCode } returns BillingResponseCode.OK - coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns - mockk(relaxed = true) - coEvery { mockBillingClient.queryProductDetails(any()) } returns mockk(relaxed = true) - - // Act - launch { billingRepository.queryPurchases() } - launch { billingRepository.queryProducts(listOf("MOCK")) } - - // Assert - verify(exactly = 1) { mockBillingClient.startConnection(any()) } - coVerify { mockBillingClient.queryPurchasesAsync(any()) } - coVerify { mockBillingClient.queryProductDetails(any()) } + fun testEnsureConnectedOnlyOneSuccessfulConnection() = runTest(UnconfinedTestDispatcher()) { + // Arrange + var hasConnected = false + val mockStartConnectionResult: BillingResult = mockk() + every { mockBillingClient.isReady } answers { hasConnected } + every { mockBillingClient.connectionState } answers { + if (hasConnected) { + BillingClient.ConnectionState.CONNECTED + } else { + BillingClient.ConnectionState.DISCONNECTED + } } + every { mockBillingClient.startConnection(any()) } answers { + hasConnected = true + firstArg().onBillingSetupFinished(mockStartConnectionResult) + } + every { mockStartConnectionResult.responseCode } returns BillingResponseCode.OK + coEvery { mockBillingClient.queryPurchasesAsync(any()) } returns mockk( + relaxed = true, + ) + coEvery { mockBillingClient.queryProductDetails(any()) } returns mockk(relaxed = true) + + // Act + launch { billingRepository.queryPurchases() } + launch { billingRepository.queryProducts(listOf("MOCK")) } + + // Assert + verify(exactly = 1) { mockBillingClient.startConnection(any()) } + coVerify { mockBillingClient.queryPurchasesAsync(any()) } + coVerify { mockBillingClient.queryProductDetails(any()) } + } companion object { private const val BILLING_CLIENT_CLASS = "com.android.billingclient.api.BillingClient" diff --git a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepository.kt b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepository.kt index 65bdf2d8e2d5..b02c1e01673d 100644 --- a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepository.kt +++ b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepository.kt @@ -33,13 +33,10 @@ class BillingPaymentRepository( override fun queryPaymentAvailability(): Flow = flow { emit(PaymentAvailability.Loading) val purchases = billingRepository.queryPurchases() - val productIdToPaymentStatus = - purchases.purchasesList - .filter { it.products.isNotEmpty() } - .associate { it.products.first() to it.purchaseState.toPaymentStatus() } + val productIdToPaymentStatus = purchases.purchasesList.filter { it.products.isNotEmpty() } + .associate { it.products.first() to it.purchaseState.toPaymentStatus() } emit( - billingRepository - .queryProducts(listOf(ProductIds.OneMonth)) + billingRepository.queryProducts(listOf(ProductIds.OneMonth)) .toPaymentAvailability(productIdToPaymentStatus), ) } @@ -52,43 +49,40 @@ class BillingPaymentRepository( val productDetailsResult = billingRepository.queryProducts(listOf(productId.value)) - val productDetails = - when (productDetailsResult.responseCode()) { - BillingResponseCode.OK -> { - productDetailsResult.getProductDetails(productId.value) - ?: run { - emit(PurchaseResult.Error.NoProductFound(productId)) - return@flow - } - } - else -> { - emit( - PurchaseResult.Error.FetchProductsError( - productId, - productDetailsResult.toBillingException(), - ), - ) + val productDetails = when (productDetailsResult.responseCode()) { + BillingResponseCode.OK -> { + productDetailsResult.getProductDetails(productId.value) ?: run { + emit(PurchaseResult.Error.NoProductFound(productId)) return@flow } } + else -> { + emit( + PurchaseResult.Error.FetchProductsError( + productId, + productDetailsResult.toBillingException(), + ), + ) + return@flow + } + } + // Get transaction id emit(PurchaseResult.FetchingObfuscationId) - val obfuscatedId: String = - when (val result = initialisePurchase()) { - is PlayPurchaseInitResult.Ok -> result.obfuscatedId - else -> { - emit(PurchaseResult.Error.TransactionIdError(productId, null)) - return@flow - } + val obfuscatedId: String = when (val result = initialisePurchase()) { + is PlayPurchaseInitResult.Ok -> result.obfuscatedId + else -> { + emit(PurchaseResult.Error.TransactionIdError(productId, null)) + return@flow } + } - val result = - billingRepository.startPurchaseFlow( - productDetails = productDetails, - obfuscatedId = obfuscatedId, - activityProvider = activityProvider, - ) + val result = billingRepository.startPurchaseFlow( + productDetails = productDetails, + obfuscatedId = obfuscatedId, + activityProvider = activityProvider, + ) if (result.responseCode == BillingResponseCode.OK) { emit(PurchaseResult.BillingFlowStarted) @@ -105,12 +99,10 @@ class BillingPaymentRepository( when (val event = billingRepository.purchaseEvents.firstOrNull()) { is PurchaseEvent.Error -> emit(event.toPurchaseResult()) is PurchaseEvent.Completed -> { - val purchase = - event.purchases.firstOrNull() - ?: run { - emit(PurchaseResult.Error.BillingError(null)) - return@flow - } + val purchase = event.purchases.firstOrNull() ?: run { + emit(PurchaseResult.Error.BillingError(null)) + return@flow + } if (purchase.purchaseState == Purchase.PurchaseState.PENDING) { emit(PurchaseResult.Completed.Pending) } else { @@ -122,6 +114,7 @@ class BillingPaymentRepository( } } } + PurchaseEvent.UserCanceled -> emit(event.toPurchaseResult()) else -> emit(PurchaseResult.Error.BillingError(null)) } @@ -138,8 +131,10 @@ class BillingPaymentRepository( val verificationResult = verifyPurchase(purchases.first()) emit( when (verificationResult) { - is PlayPurchaseVerifyResult.Error -> - VerificationResult.Error.VerificationError(null) + is PlayPurchaseVerifyResult.Error -> VerificationResult.Error.VerificationError( + null, + ) + PlayPurchaseVerifyResult.Ok -> VerificationResult.Success }, ) @@ -147,8 +142,8 @@ class BillingPaymentRepository( emit(VerificationResult.NothingToVerify) } } - else -> - emit(VerificationResult.Error.BillingError(purchasesResult.toBillingException())) + + else -> emit(VerificationResult.Error.BillingError(purchasesResult.toBillingException())) } } diff --git a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepository.kt b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepository.kt index 2af044c277b1..f2ed1dbf4b28 100644 --- a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepository.kt +++ b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingRepository.kt @@ -39,14 +39,15 @@ class BillingRepository(context: Context) { PurchaseEvent.Completed(purchases?.toList() ?: emptyList()), ) } + BillingResponseCode.USER_CANCELED -> { _purchaseEvents.tryEmit(PurchaseEvent.UserCanceled) } + else -> { _purchaseEvents.tryEmit( PurchaseEvent.Error( - exception = - BillingException( + exception = BillingException( responseCode = result.responseCode, message = result.debugMessage, ), @@ -60,28 +61,21 @@ class BillingRepository(context: Context) { val purchaseEvents = _purchaseEvents.asSharedFlow() init { - billingClient = - BillingClient.newBuilder(context) - .enablePendingPurchases() - .setListener(purchaseUpdateListener) - .build() + billingClient = BillingClient.newBuilder(context).enablePendingPurchases() + .setListener(purchaseUpdateListener).build() } private val ensureConnectedMutex = Mutex() - private suspend fun ensureConnected() = - ensureConnectedMutex.withLock { - suspendCoroutine { - if ( - billingClient.isReady && - billingClient.connectionState == BillingClient.ConnectionState.CONNECTED - ) { - it.resume(Unit) - } else { - startConnection(it) - } + private suspend fun ensureConnected() = ensureConnectedMutex.withLock { + suspendCoroutine { + if (billingClient.isReady && billingClient.connectionState == BillingClient.ConnectionState.CONNECTED) { + it.resume(Unit) + } else { + startConnection(it) } } + } private fun startConnection(continuation: Continuation) { billingClient.startConnection( @@ -115,18 +109,14 @@ class BillingRepository(context: Context) { return try { ensureConnected() - val productDetailsParamsList = - listOf( - BillingFlowParams.ProductDetailsParams.newBuilder() - .setProductDetails(productDetails) - .build(), - ) + val productDetailsParamsList = listOf( + BillingFlowParams.ProductDetailsParams.newBuilder() + .setProductDetails(productDetails).build(), + ) val billingFlowParams = - BillingFlowParams.newBuilder() - .setProductDetailsParamsList(productDetailsParamsList) - .setObfuscatedAccountId(obfuscatedId) - .build() + BillingFlowParams.newBuilder().setProductDetailsParamsList(productDetailsParamsList) + .setObfuscatedAccountId(obfuscatedId).build() val activity = activityProvider() // Launch the billing flow @@ -145,8 +135,7 @@ class BillingRepository(context: Context) { ensureConnected() val queryPurchaseHistoryParams: QueryPurchasesParams = - QueryPurchasesParams.newBuilder() - .setProductType(BillingClient.ProductType.INAPP) + QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP) .build() billingClient.queryPurchasesAsync(queryPurchaseHistoryParams) @@ -163,13 +152,10 @@ class BillingRepository(context: Context) { return try { ensureConnected() - val productList = - productIds.map { productId -> - Product.newBuilder() - .setProductId(productId) - .setProductType(BillingClient.ProductType.INAPP) - .build() - } + val productList = productIds.map { productId -> + Product.newBuilder().setProductId(productId) + .setProductType(BillingClient.ProductType.INAPP).build() + } val params = QueryProductDetailsParams.newBuilder() params.setProductList(productList) diff --git a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt index f180fac3ed0f..5081ba3b6e36 100644 --- a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt +++ b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/ProductDetailsResultToPaymentAvailability.kt @@ -8,30 +8,24 @@ import net.mullvad.mullvadvpn.lib.payment.model.PaymentStatus fun ProductDetailsResult.toPaymentAvailability( productIdToPaymentStatus: Map, -) = - when (this.billingResult.responseCode) { - BillingClient.BillingResponseCode.OK -> { - val productDetailsList = this.productDetailsList - if (productDetailsList?.isNotEmpty() == true) { - PaymentAvailability.ProductsAvailable( - productDetailsList.toPaymentProducts(productIdToPaymentStatus), - ) - } else { - PaymentAvailability.NoProductsFounds - } - } - BillingClient.BillingResponseCode.BILLING_UNAVAILABLE -> - PaymentAvailability.Error.BillingUnavailable - BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE -> - PaymentAvailability.Error.ServiceUnavailable - BillingClient.BillingResponseCode.DEVELOPER_ERROR -> - PaymentAvailability.Error.DeveloperError - BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED -> - PaymentAvailability.Error.FeatureNotSupported - BillingClient.BillingResponseCode.ITEM_UNAVAILABLE -> - PaymentAvailability.Error.ItemUnavailable - else -> - PaymentAvailability.Error.Other( - BillingException(this.billingResult.responseCode, this.billingResult.debugMessage), +) = when (this.billingResult.responseCode) { + BillingClient.BillingResponseCode.OK -> { + val productDetailsList = this.productDetailsList + if (productDetailsList?.isNotEmpty() == true) { + PaymentAvailability.ProductsAvailable( + productDetailsList.toPaymentProducts(productIdToPaymentStatus), ) + } else { + PaymentAvailability.NoProductsFounds + } } + + BillingClient.BillingResponseCode.BILLING_UNAVAILABLE -> PaymentAvailability.Error.BillingUnavailable + BillingClient.BillingResponseCode.SERVICE_UNAVAILABLE -> PaymentAvailability.Error.ServiceUnavailable + BillingClient.BillingResponseCode.DEVELOPER_ERROR -> PaymentAvailability.Error.DeveloperError + BillingClient.BillingResponseCode.FEATURE_NOT_SUPPORTED -> PaymentAvailability.Error.FeatureNotSupported + BillingClient.BillingResponseCode.ITEM_UNAVAILABLE -> PaymentAvailability.Error.ItemUnavailable + else -> PaymentAvailability.Error.Other( + BillingException(this.billingResult.responseCode, this.billingResult.debugMessage), + ) +} diff --git a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/PurchaseEventToPurchaseResult.kt b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/PurchaseEventToPurchaseResult.kt index e0e4bf0a7784..e3bf73f6e0e8 100644 --- a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/PurchaseEventToPurchaseResult.kt +++ b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/PurchaseEventToPurchaseResult.kt @@ -3,9 +3,8 @@ package net.mullvad.mullvadvpn.lib.billing.extension import net.mullvad.mullvadvpn.lib.billing.model.PurchaseEvent import net.mullvad.mullvadvpn.lib.payment.model.PurchaseResult -fun PurchaseEvent.toPurchaseResult() = - when (this) { - is PurchaseEvent.Error -> PurchaseResult.Error.BillingError(this.exception) - is PurchaseEvent.Completed -> PurchaseResult.VerificationStarted - PurchaseEvent.UserCanceled -> PurchaseResult.Completed.Cancelled - } +fun PurchaseEvent.toPurchaseResult() = when (this) { + is PurchaseEvent.Error -> PurchaseResult.Error.BillingError(this.exception) + is PurchaseEvent.Completed -> PurchaseResult.VerificationStarted + PurchaseEvent.UserCanceled -> PurchaseResult.Completed.Cancelled +} diff --git a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/PurchaseStateToPaymentStatus.kt b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/PurchaseStateToPaymentStatus.kt index 701e5fde3dc1..0a92063ae6a7 100644 --- a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/PurchaseStateToPaymentStatus.kt +++ b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/extension/PurchaseStateToPaymentStatus.kt @@ -3,9 +3,8 @@ package net.mullvad.mullvadvpn.lib.billing.extension import com.android.billingclient.api.Purchase import net.mullvad.mullvadvpn.lib.payment.model.PaymentStatus -internal fun Int.toPaymentStatus(): PaymentStatus? = - when (this) { - Purchase.PurchaseState.PURCHASED -> PaymentStatus.VERIFICATION_IN_PROGRESS - Purchase.PurchaseState.PENDING -> PaymentStatus.PENDING - else -> null - } +internal fun Int.toPaymentStatus(): PaymentStatus? = when (this) { + Purchase.PurchaseState.PURCHASED -> PaymentStatus.VERIFICATION_IN_PROGRESS + Purchase.PurchaseState.PENDING -> PaymentStatus.PENDING + else -> null +} diff --git a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/model/BillingException.kt b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/model/BillingException.kt index 08f6a89ccab5..550dffc3afaf 100644 --- a/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/model/BillingException.kt +++ b/android/lib/billing/src/main/kotlin/net/mullvad/mullvadvpn/lib/billing/model/BillingException.kt @@ -6,9 +6,7 @@ import com.android.billingclient.api.PurchasesResult class BillingException(private val responseCode: Int, message: String) : Throwable(message) { fun toBillingResult(): BillingResult = - BillingResult.newBuilder() - .setResponseCode(responseCode) - .setDebugMessage(message ?: "") + BillingResult.newBuilder().setResponseCode(responseCode).setDebugMessage(message ?: "") .build() fun toPurchasesResult(): PurchasesResult = PurchasesResult(toBillingResult(), emptyList()) diff --git a/android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt b/android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt index 2c4312bb3b0e..133cc241c268 100644 --- a/android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt +++ b/android/lib/billing/src/test/kotlin/net/mullvad/mullvadvpn/lib/billing/BillingPaymentRepositoryTest.kt @@ -30,7 +30,8 @@ import kotlin.test.assertEquals import kotlin.test.assertIs class BillingPaymentRepositoryTest { - @get:Rule val testCoroutineRule = TestCoroutineRule() + @get:Rule + val testCoroutineRule = TestCoroutineRule() private val mockBillingRepository: BillingRepository = mockk() private val mockPlayPurchaseRepository: PlayPurchaseRepository = mockk() @@ -45,11 +46,10 @@ class BillingPaymentRepositoryTest { every { mockBillingRepository.purchaseEvents } returns purchaseEventFlow - paymentRepository = - BillingPaymentRepository( - billingRepository = mockBillingRepository, - playPurchaseRepository = mockPlayPurchaseRepository, - ) + paymentRepository = BillingPaymentRepository( + billingRepository = mockBillingRepository, + playPurchaseRepository = mockPlayPurchaseRepository, + ) } @Test @@ -98,8 +98,7 @@ class BillingPaymentRepositoryTest { fun testQueryAvailablePaymentBillingUnavailableError() = runTest { // Arrange val mockResult: ProductDetailsResult = mockk() - every { mockResult.billingResult.responseCode } returns - BillingResponseCode.BILLING_UNAVAILABLE + every { mockResult.billingResult.responseCode } returns BillingResponseCode.BILLING_UNAVAILABLE coEvery { mockBillingRepository.queryPurchases() } returns mockk(relaxed = true) coEvery { mockBillingRepository.queryProducts(any()) } returns mockResult @@ -118,11 +117,9 @@ class BillingPaymentRepositoryTest { // Arrange val mockProductId = ProductId("MOCK") val mockProductDetailsResult = mockk() - every { mockProductDetailsResult.billingResult.responseCode } returns - BillingResponseCode.BILLING_UNAVAILABLE + every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.BILLING_UNAVAILABLE every { mockProductDetailsResult.billingResult.debugMessage } returns "ERROR" - coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns - mockProductDetailsResult + coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns mockProductDetailsResult // Act, Assert paymentRepository.purchaseProduct(mockProductId, mockk()).test { @@ -140,8 +137,7 @@ class BillingPaymentRepositoryTest { val mockProductDetailsResult = mockk() every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK every { mockProductDetailsResult.productDetailsList } returns emptyList() - coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns - mockProductDetailsResult + coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns mockProductDetailsResult // Act, Assert paymentRepository.purchaseProduct(mockProductId, mockk()).test { @@ -161,10 +157,10 @@ class BillingPaymentRepositoryTest { every { mockProductDetails.productId } returns mockProductId.value every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails) - coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns - mockProductDetailsResult - coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns - PlayPurchaseInitResult.Error(PlayPurchaseInitError.OtherError) + coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns mockProductDetailsResult + coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns PlayPurchaseInitResult.Error( + PlayPurchaseInitError.OtherError, + ) // Act, Assert paymentRepository.purchaseProduct(mockProductId, mockk()).test { @@ -185,8 +181,7 @@ class BillingPaymentRepositoryTest { every { mockProductDetails.productId } returns mockProductId.value every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails) - coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns - mockProductDetailsResult + coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns mockProductDetailsResult val mockBillingResult: BillingResult = mockk() every { mockBillingResult.responseCode } returns BillingResponseCode.BILLING_UNAVAILABLE every { mockBillingResult.debugMessage } returns "Mock error" @@ -197,8 +192,9 @@ class BillingPaymentRepositoryTest { activityProvider = any(), ) } returns mockBillingResult - coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns - PlayPurchaseInitResult.Ok("MOCK") + coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns PlayPurchaseInitResult.Ok( + "MOCK", + ) // Act, Assert paymentRepository.purchaseProduct(mockProductId, mockk()).test { @@ -220,8 +216,7 @@ class BillingPaymentRepositoryTest { every { mockProductDetails.productId } returns mockProductId.value every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails) - coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns - mockProductDetailsResult + coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns mockProductDetailsResult val mockObfuscatedId = "MOCK-ID" val mockBillingResult: BillingResult = mockk() every { mockBillingResult.responseCode } returns BillingResponseCode.OK @@ -232,8 +227,9 @@ class BillingPaymentRepositoryTest { activityProvider = any(), ) } returns mockBillingResult - coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns - PlayPurchaseInitResult.Ok(mockObfuscatedId) + coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns PlayPurchaseInitResult.Ok( + mockObfuscatedId, + ) // Act, Assert paymentRepository.purchaseProduct(mockProductId, mockk()).test { @@ -256,8 +252,7 @@ class BillingPaymentRepositoryTest { every { mockProductDetails.productId } returns mockProductId.value every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails) - coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns - mockProductDetailsResult + coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns mockProductDetailsResult val mockPurchaseToken = "TOKEN" val mockBillingPurchase: Purchase = mockk() val mockBillingResult: BillingResult = mockk() @@ -272,10 +267,12 @@ class BillingPaymentRepositoryTest { activityProvider = any(), ) } returns mockBillingResult - coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns - PlayPurchaseInitResult.Ok("MOCK-ID") - coEvery { mockPlayPurchaseRepository.verifyPlayPurchase(any()) } returns - PlayPurchaseVerifyResult.Error(PlayPurchaseVerifyError.OtherError) + coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns PlayPurchaseInitResult.Ok( + "MOCK-ID", + ) + coEvery { mockPlayPurchaseRepository.verifyPlayPurchase(any()) } returns PlayPurchaseVerifyResult.Error( + PlayPurchaseVerifyError.OtherError, + ) // Act, Assert paymentRepository.purchaseProduct(mockProductId, mockk()).test { @@ -299,8 +296,7 @@ class BillingPaymentRepositoryTest { every { mockProductDetails.productId } returns mockProductId.value every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails) - coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns - mockProductDetailsResult + coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns mockProductDetailsResult val mockPurchaseToken = "TOKEN" val mockBillingPurchase: Purchase = mockk() val mockBillingResult: BillingResult = mockk() @@ -315,10 +311,10 @@ class BillingPaymentRepositoryTest { activityProvider = any(), ) } returns mockBillingResult - coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns - PlayPurchaseInitResult.Ok("MOCK") - coEvery { mockPlayPurchaseRepository.verifyPlayPurchase(any()) } returns - PlayPurchaseVerifyResult.Ok + coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns PlayPurchaseInitResult.Ok( + "MOCK", + ) + coEvery { mockPlayPurchaseRepository.verifyPlayPurchase(any()) } returns PlayPurchaseVerifyResult.Ok // Act, Assert paymentRepository.purchaseProduct(mockProductId, mockk()).test { @@ -342,8 +338,7 @@ class BillingPaymentRepositoryTest { every { mockProductDetails.productId } returns mockProductId.value every { mockProductDetailsResult.billingResult.responseCode } returns BillingResponseCode.OK every { mockProductDetailsResult.productDetailsList } returns listOf(mockProductDetails) - coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns - mockProductDetailsResult + coEvery { mockBillingRepository.queryProducts(listOf(mockProductId.value)) } returns mockProductDetailsResult val mockBillingPurchase: Purchase = mockk() val mockBillingResult: BillingResult = mockk() every { mockBillingPurchase.purchaseState } returns Purchase.PurchaseState.PENDING @@ -355,8 +350,9 @@ class BillingPaymentRepositoryTest { activityProvider = any(), ) } returns mockBillingResult - coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns - PlayPurchaseInitResult.Ok("MOCK") + coEvery { mockPlayPurchaseRepository.initializePlayPurchase() } returns PlayPurchaseInitResult.Ok( + "MOCK", + ) // Act, Assert paymentRepository.purchaseProduct(mockProductId, mockk()).test { diff --git a/android/lib/common-test/src/main/java/net/mullvad/mullvadvpn/lib/common/test/TestUtils.kt b/android/lib/common-test/src/main/java/net/mullvad/mullvadvpn/lib/common/test/TestUtils.kt index 60f991fce683..dea22dce5d44 100644 --- a/android/lib/common-test/src/main/java/net/mullvad/mullvadvpn/lib/common/test/TestUtils.kt +++ b/android/lib/common-test/src/main/java/net/mullvad/mullvadvpn/lib/common/test/TestUtils.kt @@ -2,15 +2,10 @@ package net.mullvad.mullvadvpn.lib.common.test import kotlin.test.assertTrue -fun assertLists(expected: List, actual: List, message: String? = null) = - assertTrue( - expected.size == actual.size && - expected.containsAll(actual) && - actual.containsAll(expected), - message - ?: """Expected list should have same size and contains same items. +fun assertLists(expected: List, actual: List, message: String? = null) = assertTrue( + expected.size == actual.size && expected.containsAll(actual) && actual.containsAll(expected), + message ?: """Expected list should have same size and contains same items. | Expected(${expected.size}): $expected | Actual(${actual.size}) : $actual - """ - .trimMargin(), - ) + """.trimMargin(), +) diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonFlowUtils.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonFlowUtils.kt index 8156d247b119..cbe56c97edc4 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonFlowUtils.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonFlowUtils.kt @@ -19,17 +19,16 @@ fun SendChannel.safeOffer(element: T): Boolean { } fun Context.bindServiceFlow(intent: Intent, flags: Int = 0): Flow = callbackFlow { - val connectionCallback = - object : ServiceConnection { - override fun onServiceConnected(className: ComponentName, binder: IBinder) { - safeOffer(ServiceResult(binder)) - } + val connectionCallback = object : ServiceConnection { + override fun onServiceConnected(className: ComponentName, binder: IBinder) { + safeOffer(ServiceResult(binder)) + } - override fun onServiceDisconnected(className: ComponentName) { - safeOffer(ServiceResult.NOT_CONNECTED) - bindService(intent, this, flags) - } + override fun onServiceDisconnected(className: ComponentName) { + safeOffer(ServiceResult.NOT_CONNECTED) + bindService(intent, this, flags) } + } bindService(intent, connectionCallback, flags) diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt index 2b3abb2acac5..8cf0e38dcdd8 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/CommonStringExtensions.kt @@ -21,8 +21,7 @@ fun String.groupWithSpaces(groupCharSize: Int = 4): String { formattedText.append(SPACE_CHAR) } formattedText.append(nextDigit) - } - .toString() + }.toString() } fun String.groupPasswordModeWithSpaces(groupCharSize: Int = 4): String { diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ContextExtensions.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ContextExtensions.kt index 8292f3ef2d77..46a88a0e44e5 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ContextExtensions.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ContextExtensions.kt @@ -11,20 +11,19 @@ private const val ALWAYS_ON_VPN_APP = "always_on_vpn_app" fun Context.openAccountPageInBrowser(authToken: String) { startActivity( - Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.account_url) + "?token=$authToken")), + Intent( + Intent.ACTION_VIEW, + Uri.parse(getString(R.string.account_url) + "?token=$authToken"), + ), ) } fun Context.getAlwaysOnVpnAppName(): String? { - return resolveAlwaysOnVpnPackageName() - ?.let { currentAlwaysOnVpn -> - packageManager.getInstalledPackagesList(0).singleOrNull { - it.packageName == currentAlwaysOnVpn && it.packageName != packageName - } + return resolveAlwaysOnVpnPackageName()?.let { currentAlwaysOnVpn -> + packageManager.getInstalledPackagesList(0).singleOrNull { + it.packageName == currentAlwaysOnVpn && it.packageName != packageName } - ?.applicationInfo - ?.loadLabel(packageManager) - ?.toString() + }?.applicationInfo?.loadLabel(packageManager)?.toString() } // NOTE: This function will return the current Always-on VPN package's name. In case of either diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ErrorStateExtension.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ErrorStateExtension.kt index d6436496d403..c00c1879056b 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ErrorStateExtension.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/ErrorStateExtension.kt @@ -18,9 +18,11 @@ fun ErrorState.getErrorNotificationResources(context: Context): ErrorNotificatio }, ) } + cause is ErrorStateCause.VpnPermissionDenied -> { resolveAlwaysOnVpnErrorNotificationMessage(context.getAlwaysOnVpnAppName()) } + isBlocking -> ErrorNotificationMessage(R.string.blocking_internet, cause.errorMessageId()) else -> ErrorNotificationMessage(R.string.critical_error, R.string.failed_to_block_internet) } @@ -59,12 +61,14 @@ fun ErrorStateCause.errorMessageId(): Int { -> { R.string.no_matching_relay } + ParameterGenerationError.NoWireguardKey -> R.string.no_wireguard_key ParameterGenerationError.CustomTunnelHostResultionError -> { R.string.custom_tunnel_host_resolution_error } } } + is ErrorStateCause.VpnPermissionDenied -> R.string.vpn_permission_denied_error } } diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/Intermittent.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/Intermittent.kt index d66ab953782d..950aea5262db 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/Intermittent.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/Intermittent.kt @@ -68,11 +68,10 @@ class Intermittent { synchronized(this@Intermittent) { val previousUpdate = updateJob - updateJob = - GlobalScope.launch(Dispatchers.Default) { - previousUpdate?.join() - update(newValue) - } + updateJob = GlobalScope.launch(Dispatchers.Default) { + previousUpdate?.join() + update(newValue) + } } } diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/LocationConstraintExtensions.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/LocationConstraintExtensions.kt index d384f2090fb4..b1abb6128abf 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/LocationConstraintExtensions.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/LocationConstraintExtensions.kt @@ -12,11 +12,10 @@ fun LocationConstraint.toGeographicLocationConstraint(): GeographicLocationConst fun Constraint.toGeographicLocationConstraint(): Constraint = when (this) { - is Constraint.Only -> - when (value) { - is LocationConstraint.Location -> - Constraint.Only((value as LocationConstraint.Location).location) - is LocationConstraint.CustomList -> Constraint.Any() - } + is Constraint.Only -> when (value) { + is LocationConstraint.Location -> Constraint.Only((value as LocationConstraint.Location).location) + is LocationConstraint.CustomList -> Constraint.Any() + } + is Constraint.Any -> Constraint.Any() } diff --git a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/SdkUtils.kt b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/SdkUtils.kt index b91681e96ea4..5222de1cdbd1 100644 --- a/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/SdkUtils.kt +++ b/android/lib/common/src/main/kotlin/net/mullvad/mullvadvpn/lib/common/util/SdkUtils.kt @@ -13,9 +13,7 @@ import android.widget.Toast object SdkUtils { fun getSupportedPendingIntentFlags(): Int { return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - PendingIntent.FLAG_UPDATE_CURRENT or - PendingIntent.FLAG_MUTABLE or - FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE or FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE } else { @@ -24,9 +22,9 @@ object SdkUtils { } fun Context.isNotificationPermissionGranted(): Boolean { - return (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) || - checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == - PackageManager.PERMISSION_GRANTED + return (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) || checkSelfPermission( + Manifest.permission.POST_NOTIFICATIONS, + ) == PackageManager.PERMISSION_GRANTED } fun Tile.setSubtitleIfSupported(subtitleText: CharSequence) { diff --git a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt index 6f34b579d5fe..1ca55569c168 100644 --- a/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt +++ b/android/lib/endpoint/src/main/kotlin/net/mullvad/mullvadvpn/lib/endpoint/CustomApiEndpointConfiguration.kt @@ -13,11 +13,10 @@ data class CustomApiEndpointConfiguration( val disableTls: Boolean = false, val forceDirectConnection: Boolean = true, ) : ApiEndpointConfiguration { - override fun apiEndpoint() = - ApiEndpoint( - address = InetSocketAddress(hostname, port), - disableAddressCache = disableAddressCache, - disableTls = disableTls, - forceDirectConnection = forceDirectConnection, - ) + override fun apiEndpoint() = ApiEndpoint( + address = InetSocketAddress(hostname, port), + disableAddressCache = disableAddressCache, + disableTls = disableTls, + forceDirectConnection = forceDirectConnection, + ) } diff --git a/android/lib/ipc/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/ipc/HandlerFlowTest.kt b/android/lib/ipc/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/ipc/HandlerFlowTest.kt index c619f3dc783c..eafa701933ea 100644 --- a/android/lib/ipc/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/ipc/HandlerFlowTest.kt +++ b/android/lib/ipc/src/androidTest/kotlin/net/mullvad/mullvadvpn/lib/ipc/HandlerFlowTest.kt @@ -39,6 +39,7 @@ class HandlerFlowTest { companion object { const val DATA_KEY = "data" - @Parcelize data class Data(val id: Int) : Parcelable + @Parcelize + data class Data(val id: Int) : Parcelable } } diff --git a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Event.kt b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Event.kt index 95f82c359d67..4982e168b890 100644 --- a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Event.kt +++ b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Event.kt @@ -20,40 +20,54 @@ import net.mullvad.mullvadvpn.model.TunnelState sealed class Event : Message.EventMessage() { override val messageKey = MESSAGE_KEY - @Parcelize data class AccountCreationEvent(val result: AccountCreationResult) : Event() + @Parcelize + data class AccountCreationEvent(val result: AccountCreationResult) : Event() - @Parcelize data class AccountExpiryEvent(val expiry: AccountExpiry) : Event() + @Parcelize + data class AccountExpiryEvent(val expiry: AccountExpiry) : Event() - @Parcelize data class AccountHistoryEvent(val history: AccountHistory) : Event() + @Parcelize + data class AccountHistoryEvent(val history: AccountHistory) : Event() @Parcelize data class AppVersionInfo(val versionInfo: net.mullvad.mullvadvpn.model.AppVersionInfo?) : Event() - @Parcelize data class AuthToken(val token: String?) : Event() + @Parcelize + data class AuthToken(val token: String?) : Event() - @Parcelize data class CurrentVersion(val version: String?) : Event() + @Parcelize + data class CurrentVersion(val version: String?) : Event() - @Parcelize data class DeviceStateEvent(val newState: DeviceState) : Event() + @Parcelize + data class DeviceStateEvent(val newState: DeviceState) : Event() - @Parcelize data class DeviceListUpdate(val event: DeviceListEvent) : Event() + @Parcelize + data class DeviceListUpdate(val event: DeviceListEvent) : Event() @Parcelize data class DeviceRemovalEvent(val deviceId: String, val result: RemoveDeviceResult) : Event() - @Parcelize data class ListenerReady(val connection: Messenger, val listenerId: Int) : Event() + @Parcelize + data class ListenerReady(val connection: Messenger, val listenerId: Int) : Event() - @Parcelize data class LoginEvent(val result: LoginResult) : Event() + @Parcelize + data class LoginEvent(val result: LoginResult) : Event() - @Parcelize data class NewLocation(val location: GeoIpLocation?) : Event() + @Parcelize + data class NewLocation(val location: GeoIpLocation?) : Event() - @Parcelize data class NewRelayList(val relayList: RelayList?) : Event() + @Parcelize + data class NewRelayList(val relayList: RelayList?) : Event() - @Parcelize data class SettingsUpdate(val settings: Settings?) : Event() + @Parcelize + data class SettingsUpdate(val settings: Settings?) : Event() - @Parcelize data class SplitTunnelingUpdate(val excludedApps: List?) : Event() + @Parcelize + data class SplitTunnelingUpdate(val excludedApps: List?) : Event() - @Parcelize data class TunnelStateChange(val tunnelState: TunnelState) : Event() + @Parcelize + data class TunnelStateChange(val tunnelState: TunnelState) : Event() @Parcelize data class VoucherSubmissionResult( @@ -61,12 +75,14 @@ sealed class Event : Message.EventMessage() { val result: net.mullvad.mullvadvpn.model.VoucherSubmissionResult, ) : Event() - @Parcelize data class PlayPurchaseInitResultEvent(val result: PlayPurchaseInitResult) : Event() + @Parcelize + data class PlayPurchaseInitResultEvent(val result: PlayPurchaseInitResult) : Event() @Parcelize data class PlayPurchaseVerifyResultEvent(val result: PlayPurchaseVerifyResult) : Event() - @Parcelize object VpnPermissionRequest : Event() + @Parcelize + object VpnPermissionRequest : Event() companion object { private const val MESSAGE_KEY = "event" diff --git a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/HandlerFlow.kt b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/HandlerFlow.kt index f33d5b9934a5..fd3b1faf0656 100644 --- a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/HandlerFlow.kt +++ b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/HandlerFlow.kt @@ -15,7 +15,8 @@ import kotlinx.coroutines.flow.consumeAsFlow import kotlinx.coroutines.flow.onCompletion class HandlerFlow(looper: Looper, private val extractor: (Message) -> T) : - Handler(looper), Flow { + Handler(looper), + Flow { private val channel = Channel(Channel.UNLIMITED) private val flow = channel.consumeAsFlow().onCompletion { removeCallbacksAndMessages(null) } @@ -35,6 +36,7 @@ class HandlerFlow(looper: Looper, private val extractor: (Message) -> T) : Log.w("mullvad", "Received a message after HandlerFlow was closed", exception) removeCallbacksAndMessages(null) } + else -> throw exception } } diff --git a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Message.kt b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Message.kt index c9b3bf38f916..41a398e1ef3a 100644 --- a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Message.kt +++ b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Message.kt @@ -12,12 +12,11 @@ sealed class Message(private val messageId: Int) : Parcelable { protected abstract val messageKey: String val message: RawMessage - get() = - RawMessage.obtain().also { message -> - message.what = messageId - message.data = Bundle() - message.data.putParcelable(messageKey, this) - } + get() = RawMessage.obtain().also { message -> + message.what = messageId + message.data = Bundle() + message.data.putParcelable(messageKey, this) + } companion object { internal fun fromMessage(message: RawMessage, key: String): T? { diff --git a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Request.kt b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Request.kt index d988db360fcf..0ce3ccb3c5a0 100644 --- a/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Request.kt +++ b/android/lib/ipc/src/main/kotlin/net/mullvad/mullvadvpn/lib/ipc/Request.kt @@ -22,41 +22,59 @@ sealed class Request : Message.RequestMessage() { @Deprecated("Use SetDnsOptions") data class AddCustomDnsServer(val address: InetAddress) : Request() - @Parcelize object Connect : Request() + @Parcelize + object Connect : Request() - @Parcelize object CreateAccount : Request() + @Parcelize + object CreateAccount : Request() - @Parcelize object Disconnect : Request() + @Parcelize + object Disconnect : Request() - @Parcelize data class ExcludeApp(val packageName: String) : Request() + @Parcelize + data class ExcludeApp(val packageName: String) : Request() - @Parcelize object FetchAccountExpiry : Request() + @Parcelize + object FetchAccountExpiry : Request() - @Parcelize object FetchAccountHistory : Request() + @Parcelize + object FetchAccountHistory : Request() - @Parcelize object FetchAuthToken : Request() + @Parcelize + object FetchAuthToken : Request() - @Parcelize data class IncludeApp(val packageName: String) : Request() + @Parcelize + data class IncludeApp(val packageName: String) : Request() - @Parcelize data class Login(val account: String?) : Request() + @Parcelize + data class Login(val account: String?) : Request() - @Parcelize object RefreshDeviceState : Request() + @Parcelize + object RefreshDeviceState : Request() - @Parcelize object GetDevice : Request() + @Parcelize + object GetDevice : Request() - @Parcelize data class GetDeviceList(val accountToken: String) : Request() + @Parcelize + data class GetDeviceList(val accountToken: String) : Request() - @Parcelize data class RemoveDevice(val accountToken: String, val deviceId: String) : Request() + @Parcelize + data class RemoveDevice(val accountToken: String, val deviceId: String) : Request() - @Parcelize object Logout : Request() + @Parcelize + object Logout : Request() - @Parcelize object PersistExcludedApps : Request() + @Parcelize + object PersistExcludedApps : Request() - @Parcelize object Reconnect : Request() + @Parcelize + object Reconnect : Request() - @Parcelize data class RegisterListener(val listener: Messenger) : Request() + @Parcelize + data class RegisterListener(val listener: Messenger) : Request() - @Parcelize object ClearAccountHistory : Request() + @Parcelize + object ClearAccountHistory : Request() @Parcelize @Deprecated("Use SetDnsOptions") @@ -67,43 +85,54 @@ sealed class Request : Message.RequestMessage() { data class ReplaceCustomDnsServer(val oldAddress: InetAddress, val newAddress: InetAddress) : Request() - @Parcelize data class SetAllowLan(val allow: Boolean) : Request() + @Parcelize + data class SetAllowLan(val allow: Boolean) : Request() - @Parcelize data class SetAutoConnect(val autoConnect: Boolean) : Request() + @Parcelize + data class SetAutoConnect(val autoConnect: Boolean) : Request() @Parcelize @Deprecated("Use SetDnsOptions") data class SetEnableCustomDns(val enable: Boolean) : Request() - @Parcelize data class SetEnableSplitTunneling(val enable: Boolean) : Request() + @Parcelize + data class SetEnableSplitTunneling(val enable: Boolean) : Request() @Parcelize data class SetRelayLocation(val relayLocation: GeographicLocationConstraint) : Request() - @Parcelize data class SetWireGuardMtu(val mtu: Int?) : Request() + @Parcelize + data class SetWireGuardMtu(val mtu: Int?) : Request() - @Parcelize data class SubmitVoucher(val voucher: String) : Request() + @Parcelize + data class SubmitVoucher(val voucher: String) : Request() - @Parcelize data object InitPlayPurchase : Request() + @Parcelize + data object InitPlayPurchase : Request() - @Parcelize data class VerifyPlayPurchase(val playPurchase: PlayPurchase) : Request() + @Parcelize + data class VerifyPlayPurchase(val playPurchase: PlayPurchase) : Request() - @Parcelize data class UnregisterListener(val listenerId: Int) : Request() + @Parcelize + data class UnregisterListener(val listenerId: Int) : Request() - @Parcelize data class VpnPermissionResponse(val isGranted: Boolean) : Request() + @Parcelize + data class VpnPermissionResponse(val isGranted: Boolean) : Request() - @Parcelize data class SetDnsOptions(val dnsOptions: DnsOptions) : Request() + @Parcelize + data class SetDnsOptions(val dnsOptions: DnsOptions) : Request() - @Parcelize data class SetObfuscationSettings(val settings: ObfuscationSettings?) : Request() + @Parcelize + data class SetObfuscationSettings(val settings: ObfuscationSettings?) : Request() @Parcelize data class SetWireguardConstraints(val wireguardConstraints: WireguardConstraints) : Request() @Parcelize - data class SetWireGuardQuantumResistant(val quantumResistant: QuantumResistantState) : - Request() + data class SetWireGuardQuantumResistant(val quantumResistant: QuantumResistantState) : Request() - @Parcelize data object FetchRelayList : Request() + @Parcelize + data object FetchRelayList : Request() @Parcelize data class SetOwnershipAndProviders( diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountAndDevice.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountAndDevice.kt index f5137ebbb72c..8d40ead7885a 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountAndDevice.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountAndDevice.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class AccountAndDevice(val account_token: String, val device: Device) : Parcelable +@Parcelize +data class AccountAndDevice(val account_token: String, val device: Device) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountCreationResult.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountCreationResult.kt index 4bb4c613842d..23115b606d43 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountCreationResult.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountCreationResult.kt @@ -4,7 +4,9 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize sealed class AccountCreationResult : Parcelable { - @Parcelize data class Success(val accountToken: String) : AccountCreationResult() + @Parcelize + data class Success(val accountToken: String) : AccountCreationResult() - @Parcelize object Failure : AccountCreationResult() + @Parcelize + object Failure : AccountCreationResult() } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountExpiry.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountExpiry.kt index f856ef8c8961..f61a45d564da 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountExpiry.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountExpiry.kt @@ -5,9 +5,11 @@ import kotlinx.parcelize.Parcelize import org.joda.time.DateTime sealed class AccountExpiry : Parcelable { - @Parcelize data class Available(val expiryDateTime: DateTime) : AccountExpiry() + @Parcelize + data class Available(val expiryDateTime: DateTime) : AccountExpiry() - @Parcelize data object Missing : AccountExpiry() + @Parcelize + data object Missing : AccountExpiry() fun date(): DateTime? { return (this as? Available)?.expiryDateTime diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountHistory.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountHistory.kt index 008eb1ea7ae0..11e9b20604b9 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountHistory.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountHistory.kt @@ -4,9 +4,11 @@ import android.os.Parcelable import kotlinx.android.parcel.Parcelize sealed class AccountHistory : Parcelable { - @Parcelize data class Available(val accountToken: String) : AccountHistory() + @Parcelize + data class Available(val accountToken: String) : AccountHistory() - @Parcelize object Missing : AccountHistory() + @Parcelize + object Missing : AccountHistory() fun accountToken() = (this as? Available)?.accountToken } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountToken.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountToken.kt index 2aeca352d088..c1c66e5acac3 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountToken.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/AccountToken.kt @@ -1,3 +1,4 @@ package net.mullvad.mullvadvpn.model -@JvmInline value class AccountToken(val value: String) +@JvmInline +value class AccountToken(val value: String) diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Constraint.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Constraint.kt index fc78247b01a5..ec83612a8aa4 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Constraint.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Constraint.kt @@ -8,5 +8,6 @@ sealed class Constraint : Parcelable { @Suppress("PARCELABLE_PRIMARY_CONSTRUCTOR_IS_EMPTY") class Any : Constraint() - @Parcelize data class Only(val value: T) : Constraint() + @Parcelize + data class Only(val value: T) : Constraint() } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/CustomDnsOptions.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/CustomDnsOptions.kt index 6d00f7bbe938..ffddbc666619 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/CustomDnsOptions.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/CustomDnsOptions.kt @@ -4,4 +4,5 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize import java.net.InetAddress -@Parcelize data class CustomDnsOptions(val addresses: ArrayList) : Parcelable +@Parcelize +data class CustomDnsOptions(val addresses: ArrayList) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DefaultDnsOptions.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DefaultDnsOptions.kt index 69f4d4d220dd..46103cbbd8b9 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DefaultDnsOptions.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DefaultDnsOptions.kt @@ -13,11 +13,6 @@ data class DefaultDnsOptions( val blockSocialMedia: Boolean = false, ) : Parcelable { fun isAnyBlockerEnabled(): Boolean { - return blockAds || - blockTrackers || - blockMalware || - blockAdultContent || - blockGambling || - blockSocialMedia + return blockAds || blockTrackers || blockMalware || blockAdultContent || blockGambling || blockSocialMedia } } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Device.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Device.kt index 17f1c8dd385b..87219a03309d 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Device.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Device.kt @@ -34,7 +34,6 @@ data class Device( } private fun String.capitalizeFirstCharOfEachWord(): String { - return split(" ") - .joinToString(" ") { word -> word.replaceFirstChar { firstChar -> firstChar.uppercase() } } + return split(" ").joinToString(" ") { word -> word.replaceFirstChar { firstChar -> firstChar.uppercase() } } .trimEnd() } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceEventCause.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceEventCause.kt index 981e832425b8..4c254706ff67 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceEventCause.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceEventCause.kt @@ -5,9 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class DeviceEventCause : Parcelable { - LoggedIn, - LoggedOut, - Revoked, - Updated, - RotatedKey, + LoggedIn, LoggedOut, Revoked, Updated, RotatedKey, } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceListEvent.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceListEvent.kt index 7a2883617bdf..1e0f78e98591 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceListEvent.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceListEvent.kt @@ -7,7 +7,8 @@ sealed class DeviceListEvent : Parcelable { @Parcelize data class Available(val accountToken: String, val devices: List) : DeviceListEvent() - @Parcelize object Error : DeviceListEvent() + @Parcelize + object Error : DeviceListEvent() fun isAvailable(): Boolean { return (this is Available) diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DevicePort.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DevicePort.kt index e43eae3e6bab..1159fa1a47e8 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DevicePort.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DevicePort.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class DevicePort(val id: String) : Parcelable +@Parcelize +data class DevicePort(val id: String) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceState.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceState.kt index fb34c9e64588..63341d4a2b53 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceState.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DeviceState.kt @@ -4,15 +4,20 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize sealed class DeviceState : Parcelable { - @Parcelize object Initial : DeviceState() + @Parcelize + object Initial : DeviceState() - @Parcelize object Unknown : DeviceState() + @Parcelize + object Unknown : DeviceState() - @Parcelize data class LoggedIn(val accountAndDevice: AccountAndDevice) : DeviceState() + @Parcelize + data class LoggedIn(val accountAndDevice: AccountAndDevice) : DeviceState() - @Parcelize object LoggedOut : DeviceState() + @Parcelize + object LoggedOut : DeviceState() - @Parcelize object Revoked : DeviceState() + @Parcelize + object Revoked : DeviceState() fun isUnknown(): Boolean { return this is Unknown diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DnsState.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DnsState.kt index 196804438ac2..f69d955d95fa 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DnsState.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/DnsState.kt @@ -1,6 +1,5 @@ package net.mullvad.mullvadvpn.model enum class DnsState { - Default, - Custom, + Default, Custom, } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LocationConstraint.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LocationConstraint.kt index 0c9d331e3b88..b07891727407 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LocationConstraint.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LocationConstraint.kt @@ -7,5 +7,6 @@ sealed class LocationConstraint : Parcelable { @Parcelize data class Location(val location: GeographicLocationConstraint) : LocationConstraint() - @Parcelize data class CustomList(val listId: String) : LocationConstraint() + @Parcelize + data class CustomList(val listId: String) : LocationConstraint() } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LoginResult.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LoginResult.kt index 5b266cb950cd..378cdf632e8e 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LoginResult.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/LoginResult.kt @@ -5,9 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class LoginResult : Parcelable { - Ok, - InvalidAccount, - MaxDevicesReached, - RpcError, - OtherError, + Ok, InvalidAccount, MaxDevicesReached, RpcError, OtherError, } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Ownership.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Ownership.kt index 3398dc132252..e68a71385bd9 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Ownership.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Ownership.kt @@ -5,6 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class Ownership : Parcelable { - MullvadOwned, - Rented, + MullvadOwned, Rented, } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchase.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchase.kt index 8ae46a07a9b6..49da7c45d829 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchase.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchase.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class PlayPurchase(val productId: String, val purchaseToken: String) : Parcelable +@Parcelize +data class PlayPurchase(val productId: String, val purchaseToken: String) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchaseInitResult.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchaseInitResult.kt index 41407474af7c..e9b1612e304a 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchaseInitResult.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchaseInitResult.kt @@ -4,7 +4,9 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize sealed class PlayPurchaseInitResult : Parcelable { - @Parcelize data class Ok(val obfuscatedId: String) : PlayPurchaseInitResult() + @Parcelize + data class Ok(val obfuscatedId: String) : PlayPurchaseInitResult() - @Parcelize data class Error(val error: PlayPurchaseInitError) : PlayPurchaseInitResult() + @Parcelize + data class Error(val error: PlayPurchaseInitError) : PlayPurchaseInitResult() } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchaseVerifyResult.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchaseVerifyResult.kt index 7c5ee4d95314..927ece3e1bed 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchaseVerifyResult.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PlayPurchaseVerifyResult.kt @@ -4,7 +4,9 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize sealed class PlayPurchaseVerifyResult : Parcelable { - @Parcelize data object Ok : PlayPurchaseVerifyResult() + @Parcelize + data object Ok : PlayPurchaseVerifyResult() - @Parcelize data class Error(val error: PlayPurchaseVerifyError) : PlayPurchaseVerifyResult() + @Parcelize + data class Error(val error: PlayPurchaseVerifyError) : PlayPurchaseVerifyResult() } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Port.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Port.kt index 52f495a7a7fd..bec43daac557 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Port.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Port.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class Port(val value: Int) : Parcelable +@Parcelize +data class Port(val value: Int) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PortRange.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PortRange.kt index 376f5ef7a4f4..23f10010ed5b 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PortRange.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PortRange.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class PortRange(val from: Int, val to: Int) : Parcelable +@Parcelize +data class PortRange(val from: Int, val to: Int) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PublicKey.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PublicKey.kt index 169b6c3856fb..4ee6ad51df85 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PublicKey.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/PublicKey.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class PublicKey(val key: ByteArray, val dateCreated: String) : Parcelable +@Parcelize +data class PublicKey(val key: ByteArray, val dateCreated: String) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/QuantumResistantState.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/QuantumResistantState.kt index be8d347cac26..9a2f50d03713 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/QuantumResistantState.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/QuantumResistantState.kt @@ -5,7 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class QuantumResistantState : Parcelable { - Auto, - On, - Off, + Auto, On, Off, } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayEndpointData.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayEndpointData.kt index 86b3f0fa35df..84e8adf57914 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayEndpointData.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RelayEndpointData.kt @@ -4,9 +4,11 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize sealed class RelayEndpointData : Parcelable { - @Parcelize object Openvpn : RelayEndpointData() + @Parcelize + object Openvpn : RelayEndpointData() - @Parcelize object Bridge : RelayEndpointData() + @Parcelize + object Bridge : RelayEndpointData() @Parcelize data class Wireguard(val wireguardRelayEndpointData: WireguardRelayEndpointData) : diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RelaySettings.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RelaySettings.kt index 642046f1b84b..471acd3795dc 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RelaySettings.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RelaySettings.kt @@ -4,9 +4,11 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize sealed class RelaySettings : Parcelable { - @Parcelize data object CustomTunnelEndpoint : RelaySettings() + @Parcelize + data object CustomTunnelEndpoint : RelaySettings() - @Parcelize data class Normal(val relayConstraints: RelayConstraints) : RelaySettings() + @Parcelize + data class Normal(val relayConstraints: RelayConstraints) : RelaySettings() fun relayConstraints(): RelayConstraints? = (this as? Normal)?.relayConstraints } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceResult.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceResult.kt index 07b3345ab048..f7bdc6e6de98 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceResult.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/RemoveDeviceResult.kt @@ -5,8 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class RemoveDeviceResult : Parcelable { - Ok, - NotFound, - RpcError, - OtherError, + Ok, NotFound, RpcError, OtherError, } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/SelectedObfuscation.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/SelectedObfuscation.kt index a69a9358f153..0593f7ace022 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/SelectedObfuscation.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/SelectedObfuscation.kt @@ -5,7 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class SelectedObfuscation : Parcelable { - Auto, - Off, - Udp2Tcp, + Auto, Off, Udp2Tcp, } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/ServiceResult.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/ServiceResult.kt index 3bb3c26f06a0..372206851ffe 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/ServiceResult.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/ServiceResult.kt @@ -4,8 +4,7 @@ import android.os.IBinder data class ServiceResult(val binder: IBinder?) { enum class ConnectionState { - CONNECTED, - DISCONNECTED, + CONNECTED, DISCONNECTED, } val connectionState: ConnectionState diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt index a242dc95ddc9..d98718e31d80 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/TunnelState.kt @@ -9,21 +9,26 @@ import net.mullvad.talpid.tunnel.ErrorStateCause import net.mullvad.talpid.tunnel.FirewallPolicyError sealed class TunnelState : Parcelable { - @Parcelize object Disconnected : TunnelState(), Parcelable + @Parcelize + object Disconnected : TunnelState(), Parcelable @Parcelize class Connecting(val endpoint: TunnelEndpoint?, val location: GeoIpLocation?) : - TunnelState(), Parcelable + TunnelState(), + Parcelable @Parcelize class Connected(val endpoint: TunnelEndpoint, val location: GeoIpLocation?) : - TunnelState(), Parcelable + TunnelState(), + Parcelable @Parcelize class Disconnecting(val actionAfterDisconnect: ActionAfterDisconnect) : - TunnelState(), Parcelable + TunnelState(), + Parcelable - @Parcelize class Error(val errorState: ErrorState) : TunnelState(), Parcelable + @Parcelize + class Error(val errorState: ErrorState) : TunnelState(), Parcelable fun isSecured(): Boolean { return when (this) { @@ -31,31 +36,32 @@ sealed class TunnelState : Parcelable { is Connecting, is Disconnecting, -> true + is Disconnected -> false is Error -> this.errorState.isBlocking } } - override fun toString(): String = - when (this) { - is Disconnected -> DISCONNECTED - is Connecting -> CONNECTING - is Connected -> CONNECTED - is Disconnecting -> { - if (actionAfterDisconnect == ActionAfterDisconnect.Reconnect) { - RECONNECTING - } else { - DISCONNECTING - } + override fun toString(): String = when (this) { + is Disconnected -> DISCONNECTED + is Connecting -> CONNECTING + is Connected -> CONNECTED + is Disconnecting -> { + if (actionAfterDisconnect == ActionAfterDisconnect.Reconnect) { + RECONNECTING + } else { + DISCONNECTING } - is Error -> { - if (errorState.isBlocking) { - BLOCKING - } else { - ERROR - } + } + + is Error -> { + if (errorState.isBlocking) { + BLOCKING + } else { + ERROR } } + } companion object { const val DISCONNECTED = "disconnected" @@ -82,13 +88,13 @@ sealed class TunnelState : Parcelable { ), ) } - else -> - Error( - ErrorState( - ErrorStateCause.SetFirewallPolicyError(FirewallPolicyError.Generic), - false, - ), - ) + + else -> Error( + ErrorState( + ErrorStateCause.SetFirewallPolicyError(FirewallPolicyError.Generic), + false, + ), + ) } } } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings.kt index f01bb35c6f5e..b552e7785868 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/Udp2TcpObfuscationSettings.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class Udp2TcpObfuscationSettings(val port: Constraint) : Parcelable +@Parcelize +data class Udp2TcpObfuscationSettings(val port: Constraint) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmission.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmission.kt index efe05e2f5c11..bf9664651659 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmission.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmission.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class VoucherSubmission(val timeAdded: Long, val newExpiry: String) : Parcelable +@Parcelize +data class VoucherSubmission(val timeAdded: Long, val newExpiry: String) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmissionError.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmissionError.kt index 1cf778400afe..b55d7e36257d 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmissionError.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmissionError.kt @@ -5,8 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class VoucherSubmissionError : Parcelable { - InvalidVoucher, - VoucherAlreadyUsed, - RpcError, - OtherError, + InvalidVoucher, VoucherAlreadyUsed, RpcError, OtherError, } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmissionResult.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmissionResult.kt index 4163b782d4d8..b78957d5c0b7 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmissionResult.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/VoucherSubmissionResult.kt @@ -4,7 +4,9 @@ import android.os.Parcelable import kotlinx.parcelize.Parcelize sealed class VoucherSubmissionResult : Parcelable { - @Parcelize data class Ok(val submission: VoucherSubmission) : VoucherSubmissionResult() + @Parcelize + data class Ok(val submission: VoucherSubmission) : VoucherSubmissionResult() - @Parcelize data class Error(val error: VoucherSubmissionError) : VoucherSubmissionResult() + @Parcelize + data class Error(val error: VoucherSubmissionError) : VoucherSubmissionResult() } diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardConstraints.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardConstraints.kt index 1725b01f0fb0..ca54367e6c51 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardConstraints.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardConstraints.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class WireguardConstraints(val port: Constraint) : Parcelable +@Parcelize +data class WireguardConstraints(val port: Constraint) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardEndpointData.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardEndpointData.kt index 0a21221bb079..bf8b097664c4 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardEndpointData.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardEndpointData.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class WireguardEndpointData(val portRanges: ArrayList) : Parcelable +@Parcelize +data class WireguardEndpointData(val portRanges: ArrayList) : Parcelable diff --git a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardRelayEndpointData.kt b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardRelayEndpointData.kt index 4a1930dd4376..b3ef17f98af8 100644 --- a/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardRelayEndpointData.kt +++ b/android/lib/model/src/main/kotlin/net/mullvad/mullvadvpn/model/WireguardRelayEndpointData.kt @@ -3,4 +3,5 @@ package net.mullvad.mullvadvpn.model import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize object WireguardRelayEndpointData : Parcelable +@Parcelize +object WireguardRelayEndpointData : Parcelable diff --git a/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentStatus.kt b/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentStatus.kt index 294802c1d78a..f00ae814814d 100644 --- a/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentStatus.kt +++ b/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/PaymentStatus.kt @@ -1,6 +1,5 @@ package net.mullvad.mullvadvpn.lib.payment.model enum class PaymentStatus { - PENDING, - VERIFICATION_IN_PROGRESS, + PENDING, VERIFICATION_IN_PROGRESS, } diff --git a/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/ProductId.kt b/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/ProductId.kt index f14fefab28b3..49a367f7c2d2 100644 --- a/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/ProductId.kt +++ b/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/ProductId.kt @@ -1,3 +1,4 @@ package net.mullvad.mullvadvpn.lib.payment.model -@JvmInline value class ProductId(val value: String) +@JvmInline +value class ProductId(val value: String) diff --git a/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/ProductPrice.kt b/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/ProductPrice.kt index 5dc90db5fb6f..4939eac3a523 100644 --- a/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/ProductPrice.kt +++ b/android/lib/payment/src/main/kotlin/net/mullvad/mullvadvpn/lib/payment/model/ProductPrice.kt @@ -1,3 +1,4 @@ package net.mullvad.mullvadvpn.lib.payment.model -@JvmInline value class ProductPrice(val value: String) +@JvmInline +value class ProductPrice(val value: String) diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt index 9ce355b87b33..dc42934babcc 100644 --- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt +++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/ConnectivityListener.kt @@ -12,42 +12,38 @@ import kotlin.properties.Delegates.observable class ConnectivityListener { private val availableNetworks = HashSet() - private val callback = - object : NetworkCallback() { - override fun onAvailable(network: Network) { - availableNetworks.add(network) - isConnected = true - } + private val callback = object : NetworkCallback() { + override fun onAvailable(network: Network) { + availableNetworks.add(network) + isConnected = true + } - override fun onLost(network: Network) { - availableNetworks.remove(network) - isConnected = !availableNetworks.isEmpty() - } + override fun onLost(network: Network) { + availableNetworks.remove(network) + isConnected = !availableNetworks.isEmpty() } + } private lateinit var connectivityManager: ConnectivityManager val connectivityNotifier = EventNotifier(false) - var isConnected by - observable(false) { _, oldValue, newValue -> - if (newValue != oldValue) { - if (senderAddress != 0L) { - notifyConnectivityChange(newValue, senderAddress) - } - - connectivityNotifier.notify(newValue) + var isConnected by observable(false) { _, oldValue, newValue -> + if (newValue != oldValue) { + if (senderAddress != 0L) { + notifyConnectivityChange(newValue, senderAddress) } + + connectivityNotifier.notify(newValue) } + } var senderAddress = 0L fun register(context: Context) { val request = - NetworkRequest.Builder() - .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) - .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN) - .build() + NetworkRequest.Builder().addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) + .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN).build() connectivityManager = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt index 3f9b7a596b56..ba5f20083855 100644 --- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt +++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/TalpidVpnService.kt @@ -10,19 +10,17 @@ import java.net.InetAddress import kotlin.properties.Delegates.observable open class TalpidVpnService : VpnService() { - private var activeTunStatus by - observable(null) { _, oldTunStatus, _ -> - val oldTunFd = - when (oldTunStatus) { - is CreateTunResult.Success -> oldTunStatus.tunFd - is CreateTunResult.InvalidDnsServers -> oldTunStatus.tunFd - else -> null - } + private var activeTunStatus by observable(null) { _, oldTunStatus, _ -> + val oldTunFd = when (oldTunStatus) { + is CreateTunResult.Success -> oldTunStatus.tunFd + is CreateTunResult.InvalidDnsServers -> oldTunStatus.tunFd + else -> null + } - if (oldTunFd != null) { - ParcelFileDescriptor.adoptFd(oldTunFd).close() - } + if (oldTunFd != null) { + ParcelFileDescriptor.adoptFd(oldTunFd).close() } + } private val tunIsOpen get() = activeTunStatus?.isOpen ?: false @@ -89,33 +87,32 @@ open class TalpidVpnService : VpnService() { var invalidDnsServerAddresses = ArrayList() - val builder = - Builder().apply { - for (address in config.addresses) { - addAddress(address, prefixForAddress(address)) - } + val builder = Builder().apply { + for (address in config.addresses) { + addAddress(address, prefixForAddress(address)) + } - for (dnsServer in config.dnsServers) { - try { - addDnsServer(dnsServer) - } catch (exception: IllegalArgumentException) { - invalidDnsServerAddresses.add(dnsServer) - } + for (dnsServer in config.dnsServers) { + try { + addDnsServer(dnsServer) + } catch (exception: IllegalArgumentException) { + invalidDnsServerAddresses.add(dnsServer) } + } - for (route in config.routes) { - addRoute(route.address, route.prefixLength.toInt()) - } + for (route in config.routes) { + addRoute(route.address, route.prefixLength.toInt()) + } - disallowedApps?.let { apps -> - for (app in apps) { - addDisallowedApplication(app) - } + disallowedApps?.let { apps -> + for (app in apps) { + addDisallowedApplication(app) } - setMtu(config.mtu) - setBlocking(false) - setMeteredIfSupported(false) } + setMtu(config.mtu) + setBlocking(false) + setMeteredIfSupported(false) + } val vpnInterface = builder.establish() val tunFd = vpnInterface?.detachFd() diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/net/TransportProtocol.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/net/TransportProtocol.kt index 9cfdc19681f1..f31658b094ea 100644 --- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/net/TransportProtocol.kt +++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/net/TransportProtocol.kt @@ -5,6 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class TransportProtocol : Parcelable { - Tcp, - Udp, + Tcp, Udp, } diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ActionAfterDisconnect.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ActionAfterDisconnect.kt index de8377194a98..1ec6e91c6206 100644 --- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ActionAfterDisconnect.kt +++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ActionAfterDisconnect.kt @@ -5,7 +5,5 @@ import kotlinx.parcelize.Parcelize @Parcelize enum class ActionAfterDisconnect : Parcelable { - Nothing, - Block, - Reconnect, + Nothing, Block, Reconnect, } diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorState.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorState.kt index 070d190beb0c..2c5ba00bf5d9 100644 --- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorState.kt +++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorState.kt @@ -3,4 +3,5 @@ package net.mullvad.talpid.tunnel import android.os.Parcelable import kotlinx.parcelize.Parcelize -@Parcelize data class ErrorState(val cause: ErrorStateCause, val isBlocking: Boolean) : Parcelable +@Parcelize +data class ErrorState(val cause: ErrorStateCause, val isBlocking: Boolean) : Parcelable diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorStateCause.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorStateCause.kt index 2a24e67c8b14..9d5001d3b26b 100644 --- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorStateCause.kt +++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ErrorStateCause.kt @@ -14,23 +14,28 @@ sealed class ErrorStateCause : Parcelable { } } - @Parcelize data object Ipv6Unavailable : ErrorStateCause() + @Parcelize + data object Ipv6Unavailable : ErrorStateCause() @Parcelize data class SetFirewallPolicyError(val firewallPolicyError: FirewallPolicyError) : ErrorStateCause() - @Parcelize data object SetDnsError : ErrorStateCause() + @Parcelize + data object SetDnsError : ErrorStateCause() @Parcelize data class InvalidDnsServers(val addresses: ArrayList) : ErrorStateCause() - @Parcelize data object StartTunnelError : ErrorStateCause() + @Parcelize + data object StartTunnelError : ErrorStateCause() @Parcelize data class TunnelParameterError(val error: ParameterGenerationError) : ErrorStateCause() - @Parcelize data object IsOffline : ErrorStateCause() + @Parcelize + data object IsOffline : ErrorStateCause() - @Parcelize data object VpnPermissionDenied : ErrorStateCause() + @Parcelize + data object VpnPermissionDenied : ErrorStateCause() } diff --git a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ParameterGenerationError.kt b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ParameterGenerationError.kt index fdfd38546a64..76119fd33c8b 100644 --- a/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ParameterGenerationError.kt +++ b/android/lib/talpid/src/main/kotlin/net/mullvad/talpid/tunnel/ParameterGenerationError.kt @@ -1,8 +1,5 @@ package net.mullvad.talpid.tunnel enum class ParameterGenerationError { - NoMatchingRelay, - NoMatchingBridgeRelay, - NoWireguardKey, - CustomTunnelHostResultionError, + NoMatchingRelay, NoMatchingBridgeRelay, NoWireguardKey, CustomTunnelHostResultionError, } diff --git a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/Theme.kt b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/Theme.kt index 1fd0855ce738..fb387c612e03 100644 --- a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/Theme.kt +++ b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/Theme.kt @@ -33,65 +33,60 @@ import net.mullvad.mullvadvpn.lib.theme.dimensions.defaultDimensions import net.mullvad.mullvadvpn.lib.theme.typeface.TypeScale // Add our own definitions here -private val MullvadTypography = - Typography( - headlineLarge = TextStyle(fontSize = TypeScale.TextHuge, fontWeight = FontWeight.Bold), - headlineSmall = TextStyle(fontSize = TypeScale.TextBig, fontWeight = FontWeight.Bold), - bodySmall = TextStyle(fontSize = TypeScale.TextSmall), - titleSmall = TextStyle(fontSize = TypeScale.TextMedium, fontWeight = FontWeight.SemiBold), - bodyMedium = TextStyle(fontSize = TypeScale.TextMediumPlus, fontWeight = FontWeight.Bold), - titleMedium = - TextStyle(fontSize = TypeScale.TextMediumPlus, fontWeight = FontWeight.SemiBold), - titleLarge = TextStyle(fontSize = TypeScale.TitleLarge, fontFamily = FontFamily.SansSerif), - labelMedium = TextStyle(fontSize = TypeScale.TextSmall, fontWeight = FontWeight.SemiBold), - labelLarge = - TextStyle( - fontWeight = FontWeight.Normal, - letterSpacing = TextUnit.Unspecified, - fontSize = TypeScale.TextMedium, - ), - ) +private val MullvadTypography = Typography( + headlineLarge = TextStyle(fontSize = TypeScale.TextHuge, fontWeight = FontWeight.Bold), + headlineSmall = TextStyle(fontSize = TypeScale.TextBig, fontWeight = FontWeight.Bold), + bodySmall = TextStyle(fontSize = TypeScale.TextSmall), + titleSmall = TextStyle(fontSize = TypeScale.TextMedium, fontWeight = FontWeight.SemiBold), + bodyMedium = TextStyle(fontSize = TypeScale.TextMediumPlus, fontWeight = FontWeight.Bold), + titleMedium = TextStyle(fontSize = TypeScale.TextMediumPlus, fontWeight = FontWeight.SemiBold), + titleLarge = TextStyle(fontSize = TypeScale.TitleLarge, fontFamily = FontFamily.SansSerif), + labelMedium = TextStyle(fontSize = TypeScale.TextSmall, fontWeight = FontWeight.SemiBold), + labelLarge = TextStyle( + fontWeight = FontWeight.Normal, + letterSpacing = TextUnit.Unspecified, + fontSize = TypeScale.TextMedium, + ), +) -private val darkColorScheme = - darkColorScheme( - primary = md_theme_dark_primary, - onPrimary = md_theme_dark_onPrimary, - // primaryContainer = md_theme_dark_primaryContainer, - // onPrimaryContainer = md_theme_dark_onPrimaryContainer, - secondary = MullvadDarkBlue, - onSecondary = MullvadWhite60, - secondaryContainer = MullvadBlue20, - // onSecondaryContainer = md_theme_dark_onSecondaryContainer, - tertiary = MullvadRed, - // onTertiary = md_theme_dark_onTertiary, - // tertiaryContainer = md_theme_dark_tertiaryContainer, - // onTertiaryContainer = md_theme_dark_onTertiaryContainer, - error = md_theme_dark_error, - errorContainer = MullvadYellow, - onError = md_theme_dark_onError, - // onErrorContainer = md_theme_dark_onErrorContainer, - background = MullvadDarkBlue, - onBackground = MullvadWhite, - surface = MullvadGreen, - onSurface = MullvadWhite, - surfaceVariant = md_theme_dark_surfaceVariant, - onSurfaceVariant = md_theme_dark_onSurfaceVariant, - // outline = md_theme_dark_outline, - // inverseOnSurface = md_theme_dark_inverseOnSurface, - inverseSurface = MullvadWhite, - inversePrimary = MullvadGreen, - // surfaceTint = md_theme_dark_surfaceTint, - outlineVariant = Color.Transparent, // Used by divider, - // scrim = md_theme_dark_scrim, - ) +private val darkColorScheme = darkColorScheme( + primary = md_theme_dark_primary, + onPrimary = md_theme_dark_onPrimary, + // primaryContainer = md_theme_dark_primaryContainer, + // onPrimaryContainer = md_theme_dark_onPrimaryContainer, + secondary = MullvadDarkBlue, + onSecondary = MullvadWhite60, + secondaryContainer = MullvadBlue20, + // onSecondaryContainer = md_theme_dark_onSecondaryContainer, + tertiary = MullvadRed, + // onTertiary = md_theme_dark_onTertiary, + // tertiaryContainer = md_theme_dark_tertiaryContainer, + // onTertiaryContainer = md_theme_dark_onTertiaryContainer, + error = md_theme_dark_error, + errorContainer = MullvadYellow, + onError = md_theme_dark_onError, + // onErrorContainer = md_theme_dark_onErrorContainer, + background = MullvadDarkBlue, + onBackground = MullvadWhite, + surface = MullvadGreen, + onSurface = MullvadWhite, + surfaceVariant = md_theme_dark_surfaceVariant, + onSurfaceVariant = md_theme_dark_onSurfaceVariant, + // outline = md_theme_dark_outline, + // inverseOnSurface = md_theme_dark_inverseOnSurface, + inverseSurface = MullvadWhite, + inversePrimary = MullvadGreen, + // surfaceTint = md_theme_dark_surfaceTint, + outlineVariant = Color.Transparent, // Used by divider, + // scrim = md_theme_dark_scrim, +) -val Shapes = - Shapes( - small = RoundedCornerShape(4.dp), - medium = RoundedCornerShape(4.dp), - large = RoundedCornerShape(0.dp), - extraLarge = RoundedCornerShape(11.dp), - ) +val Shapes = Shapes( + small = RoundedCornerShape(4.dp), + medium = RoundedCornerShape(4.dp), + large = RoundedCornerShape(0.dp), + extraLarge = RoundedCornerShape(11.dp), +) val Dimens: Dimensions @Composable get() = LocalAppDimens.current diff --git a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/Type.kt b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/Type.kt index 8699ac8d8116..c6e0df268f2b 100644 --- a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/Type.kt +++ b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/Type.kt @@ -6,28 +6,25 @@ import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.sp -internal val MullvadMaterial3Typography = - Typography( - displayLarge = TextStyle(fontFamily = FontFamily.SansSerif), - displayMedium = TextStyle(fontFamily = FontFamily.SansSerif), - displaySmall = TextStyle(fontFamily = FontFamily.SansSerif), - headlineLarge = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.Black), - headlineMedium = TextStyle(fontFamily = FontFamily.SansSerif), - headlineSmall = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.Black), - titleLarge = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.Black), - titleMedium = TextStyle(fontFamily = FontFamily.SansSerif), - titleSmall = TextStyle(fontFamily = FontFamily.SansSerif), - bodyLarge = TextStyle(fontFamily = FontFamily.SansSerif), - bodyMedium = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.SemiBold), - bodySmall = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.SemiBold), - labelLarge = - TextStyle( - fontFamily = FontFamily.SansSerif, - fontWeight = FontWeight.SemiBold, - fontSize = 18.sp, - lineHeight = 23.sp, - ), - labelMedium = - TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.SemiBold), - labelSmall = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.SemiBold), - ) +internal val MullvadMaterial3Typography = Typography( + displayLarge = TextStyle(fontFamily = FontFamily.SansSerif), + displayMedium = TextStyle(fontFamily = FontFamily.SansSerif), + displaySmall = TextStyle(fontFamily = FontFamily.SansSerif), + headlineLarge = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.Black), + headlineMedium = TextStyle(fontFamily = FontFamily.SansSerif), + headlineSmall = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.Black), + titleLarge = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.Black), + titleMedium = TextStyle(fontFamily = FontFamily.SansSerif), + titleSmall = TextStyle(fontFamily = FontFamily.SansSerif), + bodyLarge = TextStyle(fontFamily = FontFamily.SansSerif), + bodyMedium = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.SemiBold), + bodySmall = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.SemiBold), + labelLarge = TextStyle( + fontFamily = FontFamily.SansSerif, + fontWeight = FontWeight.SemiBold, + fontSize = 18.sp, + lineHeight = 23.sp, + ), + labelMedium = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.SemiBold), + labelSmall = TextStyle(fontFamily = FontFamily.SansSerif, fontWeight = FontWeight.SemiBold), +) diff --git a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/typeface/Typeface.kt b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/typeface/Typeface.kt index 9ea368382dcf..629639fc1572 100644 --- a/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/typeface/Typeface.kt +++ b/android/lib/theme/src/main/kotlin/net/mullvad/mullvadvpn/lib/theme/typeface/Typeface.kt @@ -8,8 +8,7 @@ import androidx.compose.ui.unit.TextUnit // Add text styles not in the material theme here val Typography.listItemText: TextStyle - @Composable - get() { + @Composable get() { return TextStyle( fontWeight = FontWeight.Normal, letterSpacing = TextUnit.Unspecified, @@ -18,8 +17,7 @@ val Typography.listItemText: TextStyle } val Typography.listItemSubText: TextStyle - @Composable - get() { + @Composable get() { return TextStyle( fontWeight = FontWeight.SemiBold, letterSpacing = TextUnit.Unspecified, @@ -28,8 +26,7 @@ val Typography.listItemSubText: TextStyle } val Typography.connectionStatus: TextStyle - @Composable - get() { + @Composable get() { return TextStyle( fontWeight = FontWeight.Bold, letterSpacing = TextUnit.Unspecified, diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt index c354113fa565..d053421cb498 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/DaemonInstance.kt @@ -25,8 +25,7 @@ class DaemonInstance(private val vpnService: MullvadVpnService) { private val commandChannel = spawnActor() - private var daemon by - observable(null) { _, oldInstance, _ -> oldInstance?.onDestroy() } + private var daemon by observable(null) { _, oldInstance, _ -> oldInstance?.onDestroy() } val intermittentDaemon = Intermittent() @@ -43,19 +42,18 @@ class DaemonInstance(private val vpnService: MullvadVpnService) { intermittentDaemon.onDestroy() } - private fun spawnActor() = - GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { - var isRunning = true + private fun spawnActor() = GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { + var isRunning = true - prepareFiles() + prepareFiles() - while (isRunning) { - val startCommand = waitForCommand(channel, Command.Start::class) ?: break - startDaemon(startCommand.apiEndpointConfiguration) - isRunning = waitForCommand(channel, Command.Stop::class) is Command.Stop - stopDaemon() - } + while (isRunning) { + val startCommand = waitForCommand(channel, Command.Start::class) ?: break + startDaemon(startCommand.apiEndpointConfiguration) + isRunning = waitForCommand(channel, Command.Stop::class) is Command.Stop + stopDaemon() } + } private suspend fun waitForCommand( channel: ReceiveChannel, @@ -80,13 +78,12 @@ class DaemonInstance(private val vpnService: MullvadVpnService) { } private suspend fun startDaemon(apiEndpointConfiguration: ApiEndpointConfiguration) { - val newDaemon = - MullvadDaemon(vpnService, apiEndpointConfiguration).apply { - onDaemonStopped = { - intermittentDaemon.spawnUpdate(null) - daemon = null - } + val newDaemon = MullvadDaemon(vpnService, apiEndpointConfiguration).apply { + onDaemonStopped = { + intermittentDaemon.spawnUpdate(null) + daemon = null } + } daemon = newDaemon intermittentDaemon.update(newDaemon) diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/ForegroundNotificationManager.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/ForegroundNotificationManager.kt index 76bce389fcd1..b68927646885 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/ForegroundNotificationManager.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/ForegroundNotificationManager.kt @@ -9,7 +9,6 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.channels.actor import kotlinx.coroutines.channels.trySendBlocking -import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onStart import net.mullvad.mullvadvpn.lib.common.util.Intermittent import net.mullvad.mullvadvpn.lib.common.util.JobTracker @@ -37,8 +36,7 @@ class ForegroundNotificationManager( private val tunnelStateNotification = TunnelStateNotification(service) - private var loggedIn by - observable(false) { _, _, _ -> updater.trySendBlocking(UpdaterMessage.UpdateAction()) } + private var loggedIn by observable(false) { _, _, _ -> updater.trySendBlocking(UpdaterMessage.UpdateAction()) } private val tunnelState get() = connectionProxy.onStateChange.latestEvent @@ -49,10 +47,9 @@ class ForegroundNotificationManager( var onForeground = false private set - var lockedToForeground by - observable(false) { _, _, _ -> - updater.trySendBlocking(UpdaterMessage.UpdateNotification()) - } + var lockedToForeground by observable(false) { _, _, _ -> + updater.trySendBlocking(UpdaterMessage.UpdateNotification()) + } init { connectionProxy.onStateChange.subscribe(this) { newState -> @@ -61,10 +58,9 @@ class ForegroundNotificationManager( intermittentDaemon.registerListener(this) { daemon -> jobTracker.newBackgroundJob("notificationLoggedInJob") { - daemon - ?.deviceStateUpdates - ?.onStart { daemon.getAndEmitDeviceState()?.let { emit(it) } } - ?.collect { deviceState -> loggedIn = deviceState is DeviceState.LoggedIn } + daemon?.deviceStateUpdates?.onStart { + daemon.getAndEmitDeviceState()?.let { emit(it) } + }?.collect { deviceState -> loggedIn = deviceState is DeviceState.LoggedIn } } } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt index e2f8fcebfaed..999f75d7e355 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/MullvadVpnService.kt @@ -31,14 +31,11 @@ import kotlin.properties.Delegates.observable class MullvadVpnService : TalpidVpnService() { private enum class PendingAction { - Connect, - Disconnect, + Connect, Disconnect, } private enum class State { - Running, - Stopping, - Stopped, + Running, Stopping, Stopped, } private val connectionProxy @@ -54,10 +51,9 @@ class MullvadVpnService : TalpidVpnService() { private lateinit var keyguardManager: KeyguardManager private lateinit var notificationManager: ForegroundNotificationManager - private var pendingAction by - observable(null) { _, _, _ -> - endpoint.settingsListener.settings?.let { settings -> handlePendingAction(settings) } - } + private var pendingAction by observable(null) { _, _, _ -> + endpoint.settingsListener.settings?.let { settings -> handlePendingAction(settings) } + } private lateinit var apiEndpointConfiguration: ApiEndpointConfiguration @@ -72,13 +68,12 @@ class MullvadVpnService : TalpidVpnService() { daemonInstance = DaemonInstance(this) keyguardManager = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager - endpoint = - ServiceEndpoint( - Looper.getMainLooper(), - daemonInstance.intermittentDaemon, - connectivityListener, - this, - ) + endpoint = ServiceEndpoint( + Looper.getMainLooper(), + daemonInstance.intermittentDaemon, + connectivityListener, + this, + ) endpoint.splitTunneling.onChange.subscribe(this@MullvadVpnService) { excludedApps -> disallowedApps = excludedApps @@ -89,12 +84,11 @@ class MullvadVpnService : TalpidVpnService() { notificationManager = ForegroundNotificationManager(this, connectionProxy, daemonInstance.intermittentDaemon) - accountExpiryNotification = - AccountExpiryNotification( - this, - daemonInstance.intermittentDaemon, - endpoint.accountCache, - ) + accountExpiryNotification = AccountExpiryNotification( + this, + daemonInstance.intermittentDaemon, + endpoint.accountCache, + ) // Remove any leftover tunnel state persistence data getSharedPreferences("tunnel_state", MODE_PRIVATE).edit().clear().commit() @@ -103,12 +97,11 @@ class MullvadVpnService : TalpidVpnService() { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { Log.d(TAG, "Starting service") - val intentProvidedConfiguration = - if (BuildConfig.DEBUG) { - intent?.getApiEndpointConfigurationExtras() - } else { - null - } + val intentProvidedConfiguration = if (BuildConfig.DEBUG) { + intent?.getApiEndpointConfigurationExtras() + } else { + null + } apiEndpointConfiguration = intentProvidedConfiguration ?: get() @@ -210,18 +203,17 @@ class MullvadVpnService : TalpidVpnService() { } } - private fun setUpDaemon(daemon: MullvadDaemon) = - GlobalScope.launch(Dispatchers.Main) { - if (state != State.Stopped) { - val settings = daemon.getSettings() + private fun setUpDaemon(daemon: MullvadDaemon) = GlobalScope.launch(Dispatchers.Main) { + if (state != State.Stopped) { + val settings = daemon.getSettings() - if (settings != null) { - handlePendingAction(settings) - } else { - restart() - } + if (settings != null) { + handlePendingAction(settings) + } else { + restart() } } + } private fun stop() { Log.d(TAG, "Stopping service") @@ -254,6 +246,7 @@ class MullvadVpnService : TalpidVpnService() { openUi() } } + PendingAction.Disconnect -> connectionProxy.disconnect() null -> return } @@ -262,12 +255,11 @@ class MullvadVpnService : TalpidVpnService() { } private fun openUi() { - val intent = - Intent().apply { - setClassName(applicationContext.packageName, MAIN_ACTIVITY_CLASS) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - } + val intent = Intent().apply { + setClassName(applicationContext.packageName, MAIN_ACTIVITY_CLASS) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + } startActivity(intent) } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AccountCache.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AccountCache.kt index 64459dbfb985..3b29f2b480d3 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AccountCache.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AccountCache.kt @@ -40,12 +40,8 @@ class AccountCache(private val endpoint: ServiceEndpoint) { init { jobTracker.newBackgroundJob("autoFetchAccountExpiry") { daemon.await().deviceStateUpdates.collect { deviceState -> - accountExpiry = - deviceState - .token() - .also { cachedAccountToken = it } - ?.let { fetchAccountExpiry(it) } - ?: AccountExpiry.Missing + accountExpiry = deviceState.token().also { cachedAccountToken = it } + ?.let { fetchAccountExpiry(it) } ?: AccountExpiry.Missing } } @@ -99,20 +95,19 @@ class AccountCache(private val endpoint: ServiceEndpoint) { commandChannel.close() } - private fun spawnActor() = - GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { - try { - for (command in channel) { - when (command) { - is Command.CreateAccount -> doCreateAccount() - is Command.Login -> doLogin(command.account) - is Command.Logout -> doLogout() - } + private fun spawnActor() = GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { + try { + for (command in channel) { + when (command) { + is Command.CreateAccount -> doCreateAccount() + is Command.Login -> doLogin(command.account) + is Command.Logout -> doLogout() } - } catch (exception: ClosedReceiveChannelException) { - // Command channel was closed, stop the actor } + } catch (exception: ClosedReceiveChannelException) { + // Command channel was closed, stop the actor } + } private suspend fun clearAccountHistory() { daemon.await().clearAccountHistory() @@ -120,9 +115,7 @@ class AccountCache(private val endpoint: ServiceEndpoint) { } private suspend fun doCreateAccount() { - daemon - .await() - .createNewAccount() + daemon.await().createNewAccount() .also { newAccountToken -> cachedCreatedAccountToken = newAccountToken } .let { newAccountToken -> if (newAccountToken != null) { @@ -130,8 +123,7 @@ class AccountCache(private val endpoint: ServiceEndpoint) { } else { AccountCreationResult.Failure } - } - .also { result -> endpoint.sendEvent(Event.AccountCreationEvent(result)) } + }.also { result -> endpoint.sendEvent(Event.AccountCreationEvent(result)) } } private suspend fun doLogin(account: String) { @@ -162,6 +154,7 @@ class AccountCache(private val endpoint: ServiceEndpoint) { is GetAccountDataResult.Ok -> { result.accountData.expiry.parseAsDateTime()?.let { AccountExpiry.Available(it) } } + GetAccountDataResult.InvalidAccount -> AccountExpiry.Missing GetAccountDataResult.OtherError -> null GetAccountDataResult.RpcError -> null diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AppVersionInfoCache.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AppVersionInfoCache.kt index f4d03a029b1c..62acbb9bc396 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AppVersionInfoCache.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AppVersionInfoCache.kt @@ -8,16 +8,14 @@ import kotlin.properties.Delegates.observable class AppVersionInfoCache(endpoint: ServiceEndpoint) { private val daemon = endpoint.intermittentDaemon - var appVersionInfo by - observable(null) { _, _, info -> - endpoint.sendEvent(Event.AppVersionInfo(info)) - } + var appVersionInfo by observable(null) { _, _, info -> + endpoint.sendEvent(Event.AppVersionInfo(info)) + } private set - var currentVersion by - observable(null) { _, _, version -> - endpoint.sendEvent(Event.CurrentVersion(version)) - } + var currentVersion by observable(null) { _, _, version -> + endpoint.sendEvent(Event.CurrentVersion(version)) + } private set init { diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AuthTokenCache.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AuthTokenCache.kt index a72be4584700..46ca1f704dd7 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AuthTokenCache.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/AuthTokenCache.kt @@ -14,8 +14,13 @@ class AuthTokenCache(endpoint: ServiceEndpoint) { private val daemon = endpoint.intermittentDaemon private val requestQueue = spawnActor() - var authToken by - observable(null) { _, _, token -> endpoint.sendEvent(Event.AuthToken(token)) } + var authToken by observable(null) { _, _, token -> + endpoint.sendEvent( + Event.AuthToken( + token, + ), + ) + } private set init { @@ -28,18 +33,17 @@ class AuthTokenCache(endpoint: ServiceEndpoint) { requestQueue.close() } - private fun spawnActor() = - GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { - try { - for (command in channel) { - when (command) { - Command.Fetch -> authToken = daemon.await().getWwwAuthToken() - } + private fun spawnActor() = GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { + try { + for (command in channel) { + when (command) { + Command.Fetch -> authToken = daemon.await().getWwwAuthToken() } - } catch (exception: ClosedReceiveChannelException) { - // Closed sender, so stop the actor } + } catch (exception: ClosedReceiveChannelException) { + // Closed sender, so stop the actor } + } companion object { private enum class Command { diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ConnectionProxy.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ConnectionProxy.kt index a2c97a05bd1a..fe65d9f4de2b 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ConnectionProxy.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ConnectionProxy.kt @@ -13,9 +13,7 @@ import net.mullvad.talpid.util.EventNotifier class ConnectionProxy(val vpnPermission: VpnPermission, endpoint: ServiceEndpoint) { private enum class Command { - CONNECT, - RECONNECT, - DISCONNECT, + CONNECT, RECONNECT, DISCONNECT, } private val commandChannel = spawnActor() @@ -63,23 +61,23 @@ class ConnectionProxy(val vpnPermission: VpnPermission, endpoint: ServiceEndpoin daemon.unregisterListener(this) } - private fun spawnActor() = - GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { - try { - while (true) { - val command = channel.receive() + private fun spawnActor() = GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { + try { + while (true) { + val command = channel.receive() - when (command) { - Command.CONNECT -> { - vpnPermission.request() - daemon.await().connect() - } - Command.RECONNECT -> daemon.await().reconnect() - Command.DISCONNECT -> daemon.await().disconnect() + when (command) { + Command.CONNECT -> { + vpnPermission.request() + daemon.await().connect() } + + Command.RECONNECT -> daemon.await().reconnect() + Command.DISCONNECT -> daemon.await().disconnect() } - } catch (exception: ClosedReceiveChannelException) { - // Closed sender, so stop the actor } + } catch (exception: ClosedReceiveChannelException) { + // Closed sender, so stop the actor } + } } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/CustomDns.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/CustomDns.kt index ea0dc2a895a1..824ee664d436 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/CustomDns.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/CustomDns.kt @@ -77,26 +77,26 @@ class CustomDns(private val endpoint: ServiceEndpoint) { commandChannel.close() } - private fun spawnActor() = - GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { - try { - while (true) { - val command = channel.receive() - - when (command) { - is Command.AddDnsServer -> doAddDnsServer(command.server) - is Command.RemoveDnsServer -> doRemoveDnsServer(command.server) - is Command.ReplaceDnsServer -> { - doReplaceDnsServer(command.oldServer, command.newServer) - } - is Command.SetEnabled -> changeDnsOptions(command.enabled) - is Command.SetDnsOptions -> setDnsOptions(command.dnsOptions) + private fun spawnActor() = GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { + try { + while (true) { + val command = channel.receive() + + when (command) { + is Command.AddDnsServer -> doAddDnsServer(command.server) + is Command.RemoveDnsServer -> doRemoveDnsServer(command.server) + is Command.ReplaceDnsServer -> { + doReplaceDnsServer(command.oldServer, command.newServer) } + + is Command.SetEnabled -> changeDnsOptions(command.enabled) + is Command.SetDnsOptions -> setDnsOptions(command.dnsOptions) } - } catch (exception: ClosedReceiveChannelException) { - // Closed sender, so stop the actor } + } catch (exception: ClosedReceiveChannelException) { + // Closed sender, so stop the actor } + } private suspend fun doAddDnsServer(server: InetAddress) { if (!dnsServers.contains(server)) { @@ -124,12 +124,11 @@ class CustomDns(private val endpoint: ServiceEndpoint) { } private suspend fun changeDnsOptions(enable: Boolean) { - val options = - DnsOptions( - state = if (enable) DnsState.Custom else DnsState.Default, - customOptions = CustomDnsOptions(dnsServers), - defaultOptions = DefaultDnsOptions(), - ) + val options = DnsOptions( + state = if (enable) DnsState.Custom else DnsState.Default, + customOptions = CustomDnsOptions(dnsServers), + defaultOptions = DefaultDnsOptions(), + ) daemon.await().setDnsOptions(options) } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/DaemonDeviceDataSource.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/DaemonDeviceDataSource.kt index db264ed1fee8..75204acec4dd 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/DaemonDeviceDataSource.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/DaemonDeviceDataSource.kt @@ -1,6 +1,5 @@ package net.mullvad.mullvadvpn.service.endpoint -import kotlinx.coroutines.flow.collect import net.mullvad.mullvadvpn.lib.common.util.JobTracker import net.mullvad.mullvadvpn.lib.ipc.Event import net.mullvad.mullvadvpn.lib.ipc.Request diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/LocationInfoCache.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/LocationInfoCache.kt index fe7cbb03e898..c551d212dbb6 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/LocationInfoCache.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/LocationInfoCache.kt @@ -23,12 +23,11 @@ import kotlin.properties.Delegates.observable class LocationInfoCache(private val endpoint: ServiceEndpoint) { - private val fetchRetryDelays = - ExponentialBackoff().apply { - scale = 50 - cap = 30 /* min */ * 60 /* s */ * 1000 /* ms */ - count = 17 // ceil(log2(cap / scale) + 1) - } + private val fetchRetryDelays = ExponentialBackoff().apply { + scale = 50 + cap = 30 /* min */ * 60 /* s */ * 1000 /* ms */ + count = 17 // ceil(log2(cap / scale) + 1) + } private val fetchRequestChannel = runFetcher() @@ -38,33 +37,40 @@ class LocationInfoCache(private val endpoint: ServiceEndpoint) { private var lastKnownRealLocation: GeoIpLocation? = null private var selectedRelayLocation: GeoIpLocation? = null - var location: GeoIpLocation? by - observable(null) { _, _, newLocation -> endpoint.sendEvent(Event.NewLocation(newLocation)) } + var location: GeoIpLocation? by observable(null) { _, _, newLocation -> + endpoint.sendEvent( + Event.NewLocation( + newLocation, + ), + ) + } - var state by - observable(TunnelState.Disconnected) { _, _, newState -> - when (newState) { - is TunnelState.Disconnected -> { - location = lastKnownRealLocation - fetchRequestChannel.trySendBlocking(RequestFetch.ForRealLocation) - } - is TunnelState.Connecting -> location = newState.location - is TunnelState.Connected -> { - location = newState.location - fetchRequestChannel.trySendBlocking(RequestFetch.ForRelayLocation) - } - is TunnelState.Disconnecting -> { - when (newState.actionAfterDisconnect) { - ActionAfterDisconnect.Nothing -> location = lastKnownRealLocation - ActionAfterDisconnect.Block -> location = null - ActionAfterDisconnect.Reconnect -> { - lastKnownRealLocation?.let { location = it } - } + var state by observable(TunnelState.Disconnected) { _, _, newState -> + when (newState) { + is TunnelState.Disconnected -> { + location = lastKnownRealLocation + fetchRequestChannel.trySendBlocking(RequestFetch.ForRealLocation) + } + + is TunnelState.Connecting -> location = newState.location + is TunnelState.Connected -> { + location = newState.location + fetchRequestChannel.trySendBlocking(RequestFetch.ForRelayLocation) + } + + is TunnelState.Disconnecting -> { + when (newState.actionAfterDisconnect) { + ActionAfterDisconnect.Nothing -> location = lastKnownRealLocation + ActionAfterDisconnect.Block -> location = null + ActionAfterDisconnect.Reconnect -> { + lastKnownRealLocation?.let { location = it } } } - is TunnelState.Error -> location = null } + + is TunnelState.Error -> location = null } + } init { endpoint.connectionProxy.onStateChange.subscribe(this) { newState -> state = newState } @@ -90,13 +96,12 @@ class LocationInfoCache(private val endpoint: ServiceEndpoint) { GlobalScope.actor(Dispatchers.Default, Channel.CONFLATED) { try { fetcherLoop(channel) - } catch (exception: ClosedReceiveChannelException) {} + } catch (exception: ClosedReceiveChannelException) { + } } private suspend fun fetcherLoop(channel: ReceiveChannel) { - channel - .receiveAsFlow() - .flatMapLatest(::fetchCurrentLocation) + channel.receiveAsFlow().flatMapLatest(::fetchCurrentLocation) .collect(::handleFetchedLocation) } @@ -132,8 +137,7 @@ class LocationInfoCache(private val endpoint: ServiceEndpoint) { companion object { private enum class RequestFetch { - ForRealLocation, - ForRelayLocation, + ForRealLocation, ForRelayLocation, } } } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/PlayPurchaseHandler.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/PlayPurchaseHandler.kt index d1d98b292740..913d8e00ccdc 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/PlayPurchaseHandler.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/PlayPurchaseHandler.kt @@ -21,14 +21,12 @@ class PlayPurchaseHandler( init { scope.launch { - endpoint.dispatcher.parsedMessages - .filterIsInstance() + endpoint.dispatcher.parsedMessages.filterIsInstance() .collect { initializePurchase() } } scope.launch { - endpoint.dispatcher.parsedMessages - .filterIsInstance() + endpoint.dispatcher.parsedMessages.filterIsInstance() .collect { verifyPlayPurchase(it.playPurchase) } } } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/RelayListListener.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/RelayListListener.kt index 6cc3f9c11120..bc1b528134b6 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/RelayListListener.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/RelayListListener.kt @@ -25,10 +25,9 @@ class RelayListListener( private val scope: CoroutineScope = CoroutineScope(SupervisorJob() + dispatcher) private val daemon = endpoint.intermittentDaemon - var relayList by - observable(null) { _, _, relays -> - endpoint.sendEvent(Event.NewRelayList(relays)) - } + var relayList by observable(null) { _, _, relays -> + endpoint.sendEvent(Event.NewRelayList(relays)) + } private set init { @@ -40,28 +39,22 @@ class RelayListListener( } scope.launch { - endpoint.dispatcher.parsedMessages - .filterIsInstance() + endpoint.dispatcher.parsedMessages.filterIsInstance() .collect { request -> - val update = - getCurrentRelayConstraints() - .copy( - location = - Constraint.Only( - LocationConstraint.Location(request.relayLocation), - ), - ) + val update = getCurrentRelayConstraints().copy( + location = Constraint.Only( + LocationConstraint.Location(request.relayLocation), + ), + ) daemon.await().setRelaySettings(RelaySettings.Normal(update)) } } scope.launch { - endpoint.dispatcher.parsedMessages - .filterIsInstance() + endpoint.dispatcher.parsedMessages.filterIsInstance() .collect { request -> val update = - getCurrentRelayConstraints() - .copy(wireguardConstraints = request.wireguardConstraints) + getCurrentRelayConstraints().copy(wireguardConstraints = request.wireguardConstraints) daemon.await().setRelaySettings(RelaySettings.Normal(update)) } } @@ -73,12 +66,12 @@ class RelayListListener( } scope.launch { - endpoint.dispatcher.parsedMessages - .filterIsInstance() + endpoint.dispatcher.parsedMessages.filterIsInstance() .collect { request -> - val update = - getCurrentRelayConstraints() - .copy(ownership = request.ownership, providers = request.providers) + val update = getCurrentRelayConstraints().copy( + ownership = request.ownership, + providers = request.providers, + ) daemon.await().setRelaySettings(RelaySettings.Normal(update)) } } @@ -104,12 +97,11 @@ class RelayListListener( private suspend fun getCurrentRelayConstraints(): RelayConstraints = when (val relaySettings = daemon.await().getSettings()?.relaySettings) { is RelaySettings.Normal -> relaySettings.relayConstraints - else -> - RelayConstraints( - location = Constraint.Any(), - providers = Constraint.Any(), - ownership = Constraint.Any(), - wireguardConstraints = WireguardConstraints(Constraint.Any()), - ) + else -> RelayConstraints( + location = Constraint.Any(), + providers = Constraint.Any(), + ownership = Constraint.Any(), + wireguardConstraints = WireguardConstraints(Constraint.Any()), + ) } } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ServiceEndpoint.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ServiceEndpoint.kt index e91ebd3be205..209c0dcab5d8 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ServiceEndpoint.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/ServiceEndpoint.kt @@ -108,6 +108,7 @@ class ServiceEndpoint( registerListener(command.listener) } + is Command.UnregisterListener -> unregisterListener(command.listenerId) } } @@ -122,28 +123,26 @@ class ServiceEndpoint( listeners.put(listenerId, listener) - val initialEvents = - mutableListOf( - Event.TunnelStateChange(connectionProxy.state), - Event.AccountHistoryEvent(accountCache.onAccountHistoryChange.latestEvent), - Event.SettingsUpdate(settingsListener.settings), - Event.NewLocation(locationInfoCache.location), - Event.SplitTunnelingUpdate(splitTunneling.onChange.latestEvent), - Event.CurrentVersion(appVersionInfoCache.currentVersion), - Event.AppVersionInfo(appVersionInfoCache.appVersionInfo), - Event.NewRelayList(relayListListener.relayList), - Event.AuthToken(authTokenCache.authToken), - Event.ListenerReady(messenger, listenerId), - ) + val initialEvents = mutableListOf( + Event.TunnelStateChange(connectionProxy.state), + Event.AccountHistoryEvent(accountCache.onAccountHistoryChange.latestEvent), + Event.SettingsUpdate(settingsListener.settings), + Event.NewLocation(locationInfoCache.location), + Event.SplitTunnelingUpdate(splitTunneling.onChange.latestEvent), + Event.CurrentVersion(appVersionInfoCache.currentVersion), + Event.AppVersionInfo(appVersionInfoCache.appVersionInfo), + Event.NewRelayList(relayListListener.relayList), + Event.AuthToken(authTokenCache.authToken), + Event.ListenerReady(messenger, listenerId), + ) if (vpnPermission.waitingForResponse) { initialEvents.add(Event.VpnPermissionRequest) } - val didSuccessfullySendAllMessages = - initialEvents.all { event -> - listener.trySendEvent(event, SHOULD_LOG_DEAD_OBJECT_EXCEPTION) - } + val didSuccessfullySendAllMessages = initialEvents.all { event -> + listener.trySendEvent(event, SHOULD_LOG_DEAD_OBJECT_EXCEPTION) + } if (didSuccessfullySendAllMessages.not()) { listeners.remove(listenerId) } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SettingsListener.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SettingsListener.kt index 2470a82ad5ab..375c96c0220d 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SettingsListener.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SettingsListener.kt @@ -8,7 +8,11 @@ import kotlinx.coroutines.channels.actor import kotlinx.coroutines.channels.trySendBlocking import net.mullvad.mullvadvpn.lib.ipc.Event import net.mullvad.mullvadvpn.lib.ipc.Request -import net.mullvad.mullvadvpn.model.* +import net.mullvad.mullvadvpn.model.DnsOptions +import net.mullvad.mullvadvpn.model.ObfuscationSettings +import net.mullvad.mullvadvpn.model.QuantumResistantState +import net.mullvad.mullvadvpn.model.RelaySettings +import net.mullvad.mullvadvpn.model.Settings import net.mullvad.mullvadvpn.service.MullvadDaemon import net.mullvad.talpid.util.EventNotifier @@ -121,23 +125,22 @@ class SettingsListener(endpoint: ServiceEndpoint) { } } - private fun spawnActor() = - GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { - try { - for (command in channel) { - when (command) { - is Command.SetAllowLan -> daemon.await().setAllowLan(command.allow) - is Command.SetAutoConnect -> - daemon.await().setAutoConnect(command.autoConnect) - is Command.SetWireGuardMtu -> daemon.await().setWireguardMtu(command.mtu) - is Command.SetObfuscationSettings -> - daemon.await().setObfuscationSettings(command.settings) - is Command.SetQuantumResistant -> - daemon.await().setQuantumResistant(command.quantumResistant) - } + private fun spawnActor() = GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { + try { + for (command in channel) { + when (command) { + is Command.SetAllowLan -> daemon.await().setAllowLan(command.allow) + is Command.SetAutoConnect -> daemon.await().setAutoConnect(command.autoConnect) + is Command.SetWireGuardMtu -> daemon.await().setWireguardMtu(command.mtu) + is Command.SetObfuscationSettings -> daemon.await() + .setObfuscationSettings(command.settings) + + is Command.SetQuantumResistant -> daemon.await() + .setQuantumResistant(command.quantumResistant) } - } catch (exception: ClosedReceiveChannelException) { - // Closed sender, so stop the actor } + } catch (exception: ClosedReceiveChannelException) { + // Closed sender, so stop the actor } + } } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SplitTunneling.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SplitTunneling.kt index 70e996fa0197..a6ec44e57c13 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SplitTunneling.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/SplitTunneling.kt @@ -9,13 +9,12 @@ import kotlin.properties.Delegates.observable class SplitTunneling(persistence: SplitTunnelingPersistence, endpoint: ServiceEndpoint) { private val excludedApps = persistence.excludedApps.toMutableSet() - private var enabled by - observable(persistence.enabled) { _, wasEnabled, isEnabled -> - if (wasEnabled != isEnabled) { - persistence.enabled = isEnabled - update() - } + private var enabled by observable(persistence.enabled) { _, wasEnabled, isEnabled -> + if (wasEnabled != isEnabled) { + persistence.enabled = isEnabled + update() } + } val onChange = EventNotifier?>(excludedApps.toList()) diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/VoucherRedeemer.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/VoucherRedeemer.kt index 31c739d6719c..4fc26f60f0a4 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/VoucherRedeemer.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/VoucherRedeemer.kt @@ -31,25 +31,24 @@ class VoucherRedeemer( voucherChannel.close() } - private fun spawnActor() = - GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { - try { - for (voucher in channel) { - val result = daemon.await().submitVoucher(voucher) + private fun spawnActor() = GlobalScope.actor(Dispatchers.Default, Channel.UNLIMITED) { + try { + for (voucher in channel) { + val result = daemon.await().submitVoucher(voucher) - // Let AccountCache know about the new expiry - if (result is VoucherSubmissionResult.Ok) { - val newExpiry = result.submission.newExpiry.parseAsDateTime() - if (newExpiry != null) { - accountCache.onAccountExpiryChange.notify( - AccountExpiry.Available(newExpiry), - ) - } + // Let AccountCache know about the new expiry + if (result is VoucherSubmissionResult.Ok) { + val newExpiry = result.submission.newExpiry.parseAsDateTime() + if (newExpiry != null) { + accountCache.onAccountExpiryChange.notify( + AccountExpiry.Available(newExpiry), + ) } - endpoint.sendEvent(Event.VoucherSubmissionResult(voucher, result)) } - } catch (exception: ClosedReceiveChannelException) { - // Voucher channel was closed, stop the actor + endpoint.sendEvent(Event.VoucherSubmissionResult(voucher, result)) } + } catch (exception: ClosedReceiveChannelException) { + // Voucher channel was closed, stop the actor } + } } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/VpnPermission.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/VpnPermission.kt index 57fd6dc40c98..ebc0143667e2 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/VpnPermission.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/endpoint/VpnPermission.kt @@ -27,12 +27,11 @@ class VpnPermission(private val context: Context, private val endpoint: ServiceE if (intent == null) { isGranted.update(true) } else { - val activityIntent = - Intent().apply { - setClassName(context.packageName, MAIN_ACTIVITY_CLASS) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) - } + val activityIntent = Intent().apply { + setClassName(context.packageName, MAIN_ACTIVITY_CLASS) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP) + } isGranted.update(null) waitingForResponse = true diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/AccountExpiryNotification.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/AccountExpiryNotification.kt index f959362c5b84..9f79f0d5045e 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/AccountExpiryNotification.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/AccountExpiryNotification.kt @@ -34,24 +34,22 @@ class AccountExpiryNotification( private val buyMoreTimeUrl = resources.getString(R.string.account_url) - private val channel = - NotificationChannel( - context, - "mullvad_account_time", - NotificationCompat.VISIBILITY_PRIVATE, - R.string.account_time_notification_channel_name, - R.string.account_time_notification_channel_description, - NotificationManager.IMPORTANCE_HIGH, - true, - true, - ) - - var accountExpiry by - observable(AccountExpiry.Missing) { _, oldValue, newValue -> - if (oldValue != newValue) { - jobTracker.newUiJob("update") { update(newValue) } - } + private val channel = NotificationChannel( + context, + "mullvad_account_time", + NotificationCompat.VISIBILITY_PRIVATE, + R.string.account_time_notification_channel_name, + R.string.account_time_notification_channel_description, + NotificationManager.IMPORTANCE_HIGH, + true, + true, + ) + + var accountExpiry by observable(AccountExpiry.Missing) { _, oldValue, newValue -> + if (oldValue != newValue) { + jobTracker.newUiJob("update") { update(newValue) } } + } init { accountCache.onAccountExpiryChange.subscribe(this) { expiry -> accountExpiry = expiry } @@ -93,20 +91,18 @@ class AccountExpiryNotification( } private suspend fun build(expiry: DateTime, remainingTime: Duration): Notification { - val url = - jobTracker.runOnBackground { - Uri.parse("$buyMoreTimeUrl?token=${daemon.await().getWwwAuthToken()}") - } - val intent = - if (IS_PLAY_BUILD) { - Intent().apply { - setClassName(context.packageName, MAIN_ACTIVITY_CLASS) - flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP - action = Intent.ACTION_MAIN - } - } else { - Intent(Intent.ACTION_VIEW, url) + val url = jobTracker.runOnBackground { + Uri.parse("$buyMoreTimeUrl?token=${daemon.await().getWwwAuthToken()}") + } + val intent = if (IS_PLAY_BUILD) { + Intent().apply { + setClassName(context.packageName, MAIN_ACTIVITY_CLASS) + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP + action = Intent.ACTION_MAIN } + } else { + Intent(Intent.ACTION_VIEW, url) + } val pendingIntent = PendingIntent.getActivity(context, 1, intent, SdkUtils.getSupportedPendingIntentFlags()) diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/NotificationChannel.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/NotificationChannel.kt index 7b1cab0133dc..3af5222dc22a 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/NotificationChannel.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/NotificationChannel.kt @@ -26,13 +26,9 @@ class NotificationChannel( val channelName = context.getString(name) val channelDescription = context.getString(description) - val channel = - NotificationChannelCompat.Builder(id, importance) - .setName(channelName) - .setDescription(channelDescription) - .setShowBadge(isBadgeEnabled) - .setVibrationEnabled(isVibrationEnabled) - .build() + val channel = NotificationChannelCompat.Builder(id, importance).setName(channelName) + .setDescription(channelDescription).setShowBadge(isBadgeEnabled) + .setVibrationEnabled(isVibrationEnabled).build() notificationManager.createNotificationChannel(channel) } @@ -79,13 +75,9 @@ class NotificationChannel( isOngoing: Boolean = false, ): Notification { val builder = - NotificationCompat.Builder(context, id) - .setSmallIcon(R.drawable.small_logo_black) - .setColor(badgeColor) - .setContentTitle(title) - .setContentIntent(pendingIntent) - .setVisibility(visibility) - .setOngoing(isOngoing) + NotificationCompat.Builder(context, id).setSmallIcon(R.drawable.small_logo_black) + .setColor(badgeColor).setContentTitle(title).setContentIntent(pendingIntent) + .setVisibility(visibility).setOngoing(isOngoing) for (action in actions) { builder.addAction(action) } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/TunnelStateNotification.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/TunnelStateNotification.kt index f02d80cde8bc..80e45c96e68c 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/TunnelStateNotification.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/TunnelStateNotification.kt @@ -18,111 +18,101 @@ import net.mullvad.talpid.tunnel.ErrorStateCause import kotlin.properties.Delegates.observable class TunnelStateNotification(val context: Context) { - private val channel = - NotificationChannel( - context, - "vpn_tunnel_status", - NotificationCompat.VISIBILITY_SECRET, - R.string.foreground_notification_channel_name, - R.string.foreground_notification_channel_description, - NotificationManager.IMPORTANCE_MIN, - false, - false, - ) + private val channel = NotificationChannel( + context, + "vpn_tunnel_status", + NotificationCompat.VISIBILITY_SECRET, + R.string.foreground_notification_channel_name, + R.string.foreground_notification_channel_description, + NotificationManager.IMPORTANCE_MIN, + false, + false, + ) private val notificationText: Int - get() = - when (val state = tunnelState) { - is TunnelState.Disconnected -> R.string.unsecured - is TunnelState.Connecting -> { - if (reconnecting) { - R.string.reconnecting - } else { - R.string.connecting - } + get() = when (val state = tunnelState) { + is TunnelState.Disconnected -> R.string.unsecured + is TunnelState.Connecting -> { + if (reconnecting) { + R.string.reconnecting + } else { + R.string.connecting } - is TunnelState.Connected -> R.string.secured - is TunnelState.Disconnecting -> { - when (state.actionAfterDisconnect) { - ActionAfterDisconnect.Reconnect -> R.string.reconnecting - else -> R.string.disconnecting - } + } + + is TunnelState.Connected -> R.string.secured + is TunnelState.Disconnecting -> { + when (state.actionAfterDisconnect) { + ActionAfterDisconnect.Reconnect -> R.string.reconnecting + else -> R.string.disconnecting } - is TunnelState.Error -> { - if (state.isDeviceOffline()) { - R.string.blocking_internet_device_offline - } else { - state.errorState.getErrorNotificationResources(context).titleResourceId - } + } + + is TunnelState.Error -> { + if (state.isDeviceOffline()) { + R.string.blocking_internet_device_offline + } else { + state.errorState.getErrorNotificationResources(context).titleResourceId } } + } private fun TunnelState.isDeviceOffline(): Boolean { return (this as? TunnelState.Error)?.errorState?.cause is ErrorStateCause.IsOffline } private val shouldDisplayOngoingNotification: Boolean - get() = - when (tunnelState) { - is TunnelState.Connected -> true - is TunnelState.Disconnected, - is TunnelState.Connecting, - is TunnelState.Disconnecting, - is TunnelState.Error, - -> false - } + get() = when (tunnelState) { + is TunnelState.Connected -> true + is TunnelState.Disconnected, + is TunnelState.Connecting, + is TunnelState.Disconnecting, + is TunnelState.Error, + -> false + } private var reconnecting = false private var showingReconnecting = false var showAction by observable(false) { _, _, _ -> update() } - var tunnelState by - observable(TunnelState.Disconnected) { _, _, newState -> - val isReconnecting = newState is TunnelState.Connecting && reconnecting - val shouldBeginReconnecting = - (newState as? TunnelState.Disconnecting)?.actionAfterDisconnect == - ActionAfterDisconnect.Reconnect - reconnecting = isReconnecting || shouldBeginReconnecting - update() - } + var tunnelState by observable(TunnelState.Disconnected) { _, _, newState -> + val isReconnecting = newState is TunnelState.Connecting && reconnecting + val shouldBeginReconnecting = + (newState as? TunnelState.Disconnecting)?.actionAfterDisconnect == ActionAfterDisconnect.Reconnect + reconnecting = isReconnecting || shouldBeginReconnecting + update() + } - var visible by - observable(true) { _, _, newValue -> - if (newValue == true) { - update() - } else { - channel.notificationManager.cancel(NOTIFICATION_ID) - } + var visible by observable(true) { _, _, newValue -> + if (newValue == true) { + update() + } else { + channel.notificationManager.cancel(NOTIFICATION_ID) } + } // Suppressing since the permission check is done by calling a common util in another module. @SuppressLint("MissingPermission") private fun update() { - if ( - context.isNotificationPermissionGranted() && - visible && - (!reconnecting || !showingReconnecting) - ) { + if (context.isNotificationPermissionGranted() && visible && (!reconnecting || !showingReconnecting)) { channel.notificationManager.notify(NOTIFICATION_ID, build()) } } fun build(): Notification { - val intent = - Intent().apply { - setClassName(context.packageName, MAIN_ACTIVITY_CLASS) - flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP - action = Intent.ACTION_MAIN - } + val intent = Intent().apply { + setClassName(context.packageName, MAIN_ACTIVITY_CLASS) + flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP + action = Intent.ACTION_MAIN + } val pendingIntent = PendingIntent.getActivity(context, 1, intent, SdkUtils.getSupportedPendingIntentFlags()) - val actions = - if (showAction) { - listOf(buildAction()) - } else { - emptyList() - } + val actions = if (showAction) { + listOf(buildAction()) + } else { + emptyList() + } return channel.buildNotification( pendingIntent, @@ -136,13 +126,12 @@ class TunnelStateNotification(val context: Context) { val action = TunnelStateNotificationAction.from(tunnelState) val label = context.getString(action.text) val intent = Intent(action.key).setPackage(context.packageName) - val pendingIntent = - PendingIntent.getForegroundService( - context, - 1, - intent, - SdkUtils.getSupportedPendingIntentFlags(), - ) + val pendingIntent = PendingIntent.getForegroundService( + context, + 1, + intent, + SdkUtils.getSupportedPendingIntentFlags(), + ) return NotificationCompat.Action(action.icon, label, pendingIntent) } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/TunnelStateNotificationAction.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/TunnelStateNotificationAction.kt index 97d3285c3b43..38e12d398784 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/TunnelStateNotificationAction.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/notifications/TunnelStateNotificationAction.kt @@ -7,54 +7,48 @@ import net.mullvad.mullvadvpn.service.R import net.mullvad.talpid.tunnel.ActionAfterDisconnect enum class TunnelStateNotificationAction { - Connect, - Disconnect, - Cancel, - Dismiss, + Connect, Disconnect, Cancel, Dismiss, ; val text - get() = - when (this) { - Connect -> R.string.connect - Disconnect -> R.string.disconnect - Cancel -> R.string.cancel - Dismiss -> R.string.dismiss - } + get() = when (this) { + Connect -> R.string.connect + Disconnect -> R.string.disconnect + Cancel -> R.string.cancel + Dismiss -> R.string.dismiss + } val key - get() = - when (this) { - Connect -> KEY_CONNECT_ACTION - else -> KEY_DISCONNECT_ACTION - } + get() = when (this) { + Connect -> KEY_CONNECT_ACTION + else -> KEY_DISCONNECT_ACTION + } val icon - get() = - when (this) { - Connect -> R.drawable.icon_notification_connect - else -> R.drawable.icon_notification_disconnect - } + get() = when (this) { + Connect -> R.drawable.icon_notification_connect + else -> R.drawable.icon_notification_disconnect + } companion object { - fun from(tunnelState: TunnelState) = - when (tunnelState) { - is TunnelState.Disconnected -> Connect - is TunnelState.Connecting -> Cancel - is TunnelState.Connected -> Disconnect - is TunnelState.Disconnecting -> { - when (tunnelState.actionAfterDisconnect) { - ActionAfterDisconnect.Reconnect -> Cancel - else -> Connect - } + fun from(tunnelState: TunnelState) = when (tunnelState) { + is TunnelState.Disconnected -> Connect + is TunnelState.Connecting -> Cancel + is TunnelState.Connected -> Disconnect + is TunnelState.Disconnecting -> { + when (tunnelState.actionAfterDisconnect) { + ActionAfterDisconnect.Reconnect -> Cancel + else -> Connect } - is TunnelState.Error -> { - if (tunnelState.errorState.isBlocking) { - Disconnect - } else { - Dismiss - } + } + + is TunnelState.Error -> { + if (tunnelState.errorState.isBlocking) { + Disconnect + } else { + Dismiss } } + } } } diff --git a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/persistence/SplitTunnelingPersistence.kt b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/persistence/SplitTunnelingPersistence.kt index 264304ab3f67..425aec883652 100644 --- a/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/persistence/SplitTunnelingPersistence.kt +++ b/android/service/src/main/kotlin/net/mullvad/mullvadvpn/service/persistence/SplitTunnelingPersistence.kt @@ -15,18 +15,16 @@ class SplitTunnelingPersistence(context: Context) { private val appListFile = File(context.filesDir, "split-tunnelling.txt") private val preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE) - var enabled by - observable(preferences.getBoolean(KEY_ENABLED, false)) { _, _, isEnabled -> - preferences.edit().apply { - putBoolean(KEY_ENABLED, isEnabled) - apply() - } + var enabled by observable(preferences.getBoolean(KEY_ENABLED, false)) { _, _, isEnabled -> + preferences.edit().apply { + putBoolean(KEY_ENABLED, isEnabled) + apply() } + } - var excludedApps by - observable(loadExcludedApps()) { _, _, excludedAppsSet -> - appListFile.writeText(excludedAppsSet.joinToString(separator = "\n")) - } + var excludedApps by observable(loadExcludedApps()) { _, _, excludedAppsSet -> + appListFile.writeText(excludedAppsSet.joinToString(separator = "\n")) + } private fun loadExcludedApps(): Set { return when { diff --git a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/ViewModelTests.kt b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/ViewModelTests.kt index 1e530de7c106..3c986fe74238 100644 --- a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/ViewModelTests.kt +++ b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/ViewModelTests.kt @@ -19,10 +19,10 @@ class ViewModelTests { // properties that shouldn't be exposed. @Test fun `ensure public properties use permitted names`() = - allViewModels().properties(includeNested = false).withPublicOrDefaultModifier().assert { - property -> - property.name == "uiState" || property.name == "uiSideEffect" - } + allViewModels().properties(includeNested = false).withPublicOrDefaultModifier() + .assert { property -> + property.name == "uiState" || property.name == "uiSideEffect" + } @Test fun `ensure public functions have no return type`() = diff --git a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/ClassTests.kt b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/ClassTests.kt index 918139bf2458..ec1e939cca59 100644 --- a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/ClassTests.kt +++ b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/ClassTests.kt @@ -11,8 +11,8 @@ class ClassTests { val companionObject = it.objects(includeNested = false).lastOrNull { obj -> obj.hasCompanionModifier } if (companionObject != null) { - it.declarations(includeNested = false, includeLocal = false).last() == - companionObject + it.declarations(includeNested = false, includeLocal = false) + .last() == companionObject } else { true } diff --git a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/DataClassTests.kt b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/DataClassTests.kt index cc2f7262b128..78a2e2a49fa1 100644 --- a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/DataClassTests.kt +++ b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/DataClassTests.kt @@ -9,9 +9,6 @@ import org.junit.Test class DataClasses { @Test fun `ensure data classes only use immutable properties`() = - Konsist.scopeFromProject() - .classes(includeNested = true) - .withDataModifier() - .properties(includeNested = false, includeLocal = false) - .assertNot { it.hasVarModifier } + Konsist.scopeFromProject().classes(includeNested = true).withDataModifier() + .properties(includeNested = false, includeLocal = false).assertNot { it.hasVarModifier } } diff --git a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/ValueClassTests.kt b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/ValueClassTests.kt index 6b40e051e868..5f7885d41916 100644 --- a/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/ValueClassTests.kt +++ b/android/test/arch/src/test/kotlin/net/mullvad/mullvadvpn/test/arch/classes/ValueClassTests.kt @@ -2,7 +2,6 @@ package net.mullvad.mullvadvpn.test.arch.classes import com.lemonappdev.konsist.api.Konsist import com.lemonappdev.konsist.api.ext.list.modifierprovider.withValueModifier -import com.lemonappdev.konsist.api.ext.list.properties import com.lemonappdev.konsist.api.verify.assertTrue import org.junit.Test diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt index 0462afb05536..3dcba7b2b7da 100644 --- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt +++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/interactor/AppInteractor.kt @@ -50,10 +50,9 @@ class AppInteractor(private val device: UiDevice, private val targetContext: Con } fun attemptLogin(accountToken: String) { - val loginObject = - device.findObjectWithTimeout(By.clazz("android.widget.EditText")).apply { - text = accountToken - } + val loginObject = device.findObjectWithTimeout(By.clazz("android.widget.EditText")).apply { + text = accountToken + } loginObject.parent.findObject(By.clazz(Button::class.java)).click() } @@ -63,10 +62,10 @@ class AppInteractor(private val device: UiDevice, private val targetContext: Con fun extractIpAddress(): String { device.findObjectWithTimeout(By.res(TUNNEL_INFO_ID)).click() - return device - .findObjectWithTimeout(By.res(TUNNEL_OUT_ADDRESS_ID), CONNECTION_TIMEOUT) - .text - .extractIpAddress() + return device.findObjectWithTimeout( + By.res(TUNNEL_OUT_ADDRESS_ID), + CONNECTION_TIMEOUT, + ).text.extractIpAddress() } fun clickSettingsCog() { diff --git a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt index b5b5452034ca..42467ba9d95f 100644 --- a/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt +++ b/android/test/common/src/main/kotlin/net/mullvad/mullvadvpn/test/common/rule/CaptureScreenshotOnFailedTestRule.kt @@ -86,17 +86,14 @@ class CaptureScreenshotOnFailedTestRule(private val testTag: String) : TestWatch baseDir: String, filename: String, ) { - val screenshotBaseDirectory = - Paths.get( - Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES).path, - baseDir, - ) - .toFile() - .apply { - if (exists().not()) { - mkdirs() - } - } + val screenshotBaseDirectory = Paths.get( + Environment.getExternalStoragePublicDirectory(DIRECTORY_PICTURES).path, + baseDir, + ).toFile().apply { + if (exists().not()) { + mkdirs() + } + } FileOutputStream(File(screenshotBaseDirectory, filename)).use { outputStream -> try { this.compress(Bitmap.CompressFormat.JPEG, 50, outputStream) @@ -107,9 +104,8 @@ class CaptureScreenshotOnFailedTestRule(private val testTag: String) : TestWatch contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues) } - private fun createBaseScreenshotContentValues() = - ContentValues().apply { - put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") - put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) - } + private fun createBaseScreenshotContentValues() = ContentValues().apply { + put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg") + put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis()) + } } diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt index 218e86c21073..8f72fef0bec7 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/ConnectionTest.kt @@ -12,10 +12,12 @@ import org.junit.Test class ConnectionTest : EndToEndTest() { - @Rule @JvmField + @Rule + @JvmField val cleanupAccountTestRule = CleanupAccountTestRule() - @Rule @JvmField + @Rule + @JvmField val forgetAllVpnAppsInSettingsTestRule = ForgetAllVpnAppsInSettingsTestRule() @Test diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt index 044dd0c70f1d..50244750e2ec 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/EndToEndTest.kt @@ -19,16 +19,16 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) abstract class EndToEndTest { - @Rule @JvmField + @Rule + @JvmField val rule = CaptureScreenshotOnFailedTestRule(LOG_TAG) @Rule @JvmField - val permissionRule: GrantPermissionRule = - GrantPermissionRule.grant( - Manifest.permission.WRITE_EXTERNAL_STORAGE, - Manifest.permission.READ_EXTERNAL_STORAGE, - ) + val permissionRule: GrantPermissionRule = GrantPermissionRule.grant( + Manifest.permission.WRITE_EXTERNAL_STORAGE, + Manifest.permission.READ_EXTERNAL_STORAGE, + ) lateinit var device: UiDevice lateinit var targetContext: Context @@ -41,12 +41,10 @@ abstract class EndToEndTest { device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) targetContext = InstrumentationRegistry.getInstrumentation().targetContext - validTestAccountToken = - InstrumentationRegistry.getArguments() - .getRequiredArgument(VALID_TEST_ACCOUNT_TOKEN_ARGUMENT_KEY) - invalidTestAccountToken = - InstrumentationRegistry.getArguments() - .getRequiredArgument(INVALID_TEST_ACCOUNT_TOKEN_ARGUMENT_KEY) + validTestAccountToken = InstrumentationRegistry.getArguments() + .getRequiredArgument(VALID_TEST_ACCOUNT_TOKEN_ARGUMENT_KEY) + invalidTestAccountToken = InstrumentationRegistry.getArguments() + .getRequiredArgument(INVALID_TEST_ACCOUNT_TOKEN_ARGUMENT_KEY) app = AppInteractor(device, targetContext) } diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt index 095b554821fb..42944d5a9f79 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/LoginTest.kt @@ -15,7 +15,8 @@ import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) class LoginTest : EndToEndTest() { - @Rule @JvmField + @Rule + @JvmField val cleanupAccountTestRule = CleanupAccountTestRule() @Test diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/interactor/SystemSettingsInteractor.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/interactor/SystemSettingsInteractor.kt index bcf4adcc9e91..e5f8ff132e4e 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/interactor/SystemSettingsInteractor.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/interactor/SystemSettingsInteractor.kt @@ -9,11 +9,10 @@ import net.mullvad.mullvadvpn.test.common.extension.findObjectByCaseInsensitiveT class SystemSettingsInteractor(private val uiDevice: UiDevice, private val context: Context) { fun openVpnSettings() { - val intent = - Intent("com.intent.MAIN").apply { - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - } + val intent = Intent("com.intent.MAIN").apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK) + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + } intent.component = ComponentName.unflattenFromString("com.android.settings/.Settings\$VpnSettingsActivity") context.startActivity(intent) diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/CleanupAccountTestRule.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/CleanupAccountTestRule.kt index 2e19cb42fe7d..6557fb23ff3d 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/CleanupAccountTestRule.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/CleanupAccountTestRule.kt @@ -13,10 +13,11 @@ class CleanupAccountTestRule : TestWatcher() { override fun starting(description: Description) { Log.d(LOG_TAG, "Cleaning up account before test: ${description.methodName}") val targetContext = InstrumentationRegistry.getInstrumentation().targetContext - val validTestAccountToken = - InstrumentationRegistry.getArguments() - .getRequiredArgument(VALID_TEST_ACCOUNT_TOKEN_ARGUMENT_KEY) - MullvadAccountInteractor(SimpleMullvadHttpClient(targetContext), validTestAccountToken) - .cleanupAccount() + val validTestAccountToken = InstrumentationRegistry.getArguments() + .getRequiredArgument(VALID_TEST_ACCOUNT_TOKEN_ARGUMENT_KEY) + MullvadAccountInteractor( + SimpleMullvadHttpClient(targetContext), + validTestAccountToken, + ).cleanupAccount() } } diff --git a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/SimpleMullvadHttpClient.kt b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/SimpleMullvadHttpClient.kt index bbf837c02f41..3778fee140c8 100644 --- a/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/SimpleMullvadHttpClient.kt +++ b/android/test/e2e/src/main/kotlin/net/mullvad/mullvadvpn/test/e2e/misc/SimpleMullvadHttpClient.kt @@ -40,23 +40,16 @@ class SimpleMullvadHttpClient(context: Context) { fun getDeviceList(accessToken: String): List { Log.v(LOG_TAG, "Get devices") - val response = - sendSimpleSynchronousRequestArray( - Request.Method.GET, - DEVICE_LIST_URL, - token = accessToken, - ) + val response = sendSimpleSynchronousRequestArray( + Request.Method.GET, + DEVICE_LIST_URL, + token = accessToken, + ) - return response!! - .iterator() - .asSequence() - .toList() - .also { - it.map { jsonObject -> jsonObject.getString("name") } - .also { deviceNames -> Log.v(LOG_TAG, "Devices received: $deviceNames") } - } - .map { it.getString("id") } - .toList() + return response!!.iterator().asSequence().toList().also { + it.map { jsonObject -> jsonObject.getString("name") } + .also { deviceNames -> Log.v(LOG_TAG, "Devices received: $deviceNames") } + }.map { it.getString("id") }.toList() } fun removeDevice(token: String, deviceId: String) { @@ -69,14 +62,15 @@ class SimpleMullvadHttpClient(context: Context) { } fun runConnectionCheck(): ConnCheckState? { - return sendSimpleSynchronousRequestString(Request.Method.GET, CONN_CHECK_URL) - ?.let { respose -> JSONObject(respose) } - ?.let { json -> - ConnCheckState( - isConnected = json.getBoolean("mullvad_exit_ip"), - ipAddress = json.getString("ip"), - ) - } + return sendSimpleSynchronousRequestString( + Request.Method.GET, + CONN_CHECK_URL, + )?.let { respose -> JSONObject(respose) }?.let { json -> + ConnCheckState( + isConnected = json.getBoolean("mullvad_exit_ip"), + ipAddress = json.getString("ip"), + ) + } } private fun sendSimpleSynchronousRequest( @@ -86,19 +80,18 @@ class SimpleMullvadHttpClient(context: Context) { token: String? = null, ): JSONObject? { val future = RequestFuture.newFuture() - val request = - object : JsonObjectRequest(method, url, body, future, future) { - override fun getHeaders(): MutableMap { - val headers = HashMap() - if (body != null) { - headers.put("Content-Type", "application/json") - } - if (token != null) { - headers.put("Authorization", "Bearer $token") - } - return headers + val request = object : JsonObjectRequest(method, url, body, future, future) { + override fun getHeaders(): MutableMap { + val headers = HashMap() + if (body != null) { + headers.put("Content-Type", "application/json") } + if (token != null) { + headers.put("Authorization", "Bearer $token") + } + return headers } + } queue.add(request) return try { future.get().also { response -> @@ -117,19 +110,18 @@ class SimpleMullvadHttpClient(context: Context) { token: String? = null, ): String? { val future = RequestFuture.newFuture() - val request = - object : StringRequest(method, url, future, future) { - override fun getHeaders(): MutableMap { - val headers = HashMap() - if (body != null) { - headers.put("Content-Type", "application/json") - } - if (token != null) { - headers.put("Authorization", "Bearer $token") - } - return headers + val request = object : StringRequest(method, url, future, future) { + override fun getHeaders(): MutableMap { + val headers = HashMap() + if (body != null) { + headers.put("Content-Type", "application/json") + } + if (token != null) { + headers.put("Authorization", "Bearer $token") } + return headers } + } queue.add(request) return try { future.get().also { response -> Log.v(LOG_TAG, "String request response: $response") } @@ -146,17 +138,16 @@ class SimpleMullvadHttpClient(context: Context) { token: String? = null, ): JSONArray? { val future = RequestFuture.newFuture() - val request = - object : JsonArrayRequest(method, url, null, future, future) { - override fun getHeaders(): MutableMap { - val headers = HashMap() - headers.put("Content-Type", "application/json") - if (token != null) { - headers.put("Authorization", "Bearer $token") - } - return headers + val request = object : JsonArrayRequest(method, url, null, future, future) { + override fun getHeaders(): MutableMap { + val headers = HashMap() + headers.put("Content-Type", "application/json") + if (token != null) { + headers.put("Authorization", "Bearer $token") } + return headers } + } queue.add(request) return try { future.get().also { response -> diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt index 9654be575c4d..81a921a16625 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/LoginMockApiTest.kt @@ -32,10 +32,8 @@ class LoginMockApiTest : MockApiTest() { app.attemptLogin(validAccountToken) // Assert - val result = - device - .findObject(By.res(LOGIN_TITLE_TEST_TAG)) - .wait(Until.textEquals("Login failed"), DEFAULT_INTERACTION_TIMEOUT) + val result = device.findObject(By.res(LOGIN_TITLE_TEST_TAG)) + .wait(Until.textEquals("Login failed"), DEFAULT_INTERACTION_TIMEOUT) assertTrue(result) } diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt index 27c5cf8ef333..c949ba93b3bf 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiDispatcher.kt @@ -35,12 +35,15 @@ class MockApiDispatcher : Dispatcher() { "get", "GET", -> handleDeviceListRequest() + "post", "POST", -> handleDeviceCreationRequest(request.body) + else -> MockResponse().setResponseCode(404) } } + "$DEVICES_URL_PATH/$DUMMY_ID" -> handleDeviceInfoRequest() ACCOUNT_URL_PATH -> handleAccountInfoRequest() else -> MockResponse().setResponseCode(404) @@ -53,16 +56,12 @@ class MockApiDispatcher : Dispatcher() { val accountToken = requestBody.getAccountToken() return if (accountToken != null && accountToken == expectedAccountToken) { - MockResponse() - .setResponseCode(200) - .addJsonHeader() - .setBody( - accessTokenJsonResponse( - accessToken = DUMMY_ACCESS_TOKEN, - expiry = currentUtcTimeWithOffsetZero().plusDays(1), - ) - .toString(), - ) + MockResponse().setResponseCode(200).addJsonHeader().setBody( + accessTokenJsonResponse( + accessToken = DUMMY_ACCESS_TOKEN, + expiry = currentUtcTimeWithOffsetZero().plusDays(1), + ).toString(), + ) } else { Log.e( LOG_TAG, @@ -74,71 +73,50 @@ class MockApiDispatcher : Dispatcher() { private fun handleAccountInfoRequest(): MockResponse { return accountExpiry?.let { expiry -> - MockResponse() - .setResponseCode(200) - .addJsonHeader() + MockResponse().setResponseCode(200).addJsonHeader() .setBody(accountInfoJson(id = DUMMY_ID, expiry = expiry).toString()) - } - ?: MockResponse().setResponseCode(400) + } ?: MockResponse().setResponseCode(400) } private fun handleDeviceInfoRequest(): MockResponse { return cachedPubKeyFromAppUnderTest?.let { cachedKey -> - MockResponse() - .setResponseCode(200) - .addJsonHeader() - .setBody( + MockResponse().setResponseCode(200).addJsonHeader().setBody( + deviceJson( + id = DUMMY_ID, + name = DUMMY_DEVICE_NAME, + publicKey = cachedKey, + creationDate = currentUtcTimeWithOffsetZero().minusDays(1), + ).toString(), + ) + } ?: MockResponse().setResponseCode(400) + } + + private fun handleDeviceCreationRequest(body: Buffer): MockResponse { + return body.getPubKey().also { newKey -> cachedPubKeyFromAppUnderTest = newKey } + ?.let { newKey -> + MockResponse().setResponseCode(201).addJsonHeader().setBody( deviceJson( id = DUMMY_ID, name = DUMMY_DEVICE_NAME, - publicKey = cachedKey, + publicKey = newKey, creationDate = currentUtcTimeWithOffsetZero().minusDays(1), - ) - .toString(), + ).toString(), ) - } - ?: MockResponse().setResponseCode(400) - } - - private fun handleDeviceCreationRequest(body: Buffer): MockResponse { - return body - .getPubKey() - .also { newKey -> cachedPubKeyFromAppUnderTest = newKey } - ?.let { newKey -> - MockResponse() - .setResponseCode(201) - .addJsonHeader() - .setBody( - deviceJson( - id = DUMMY_ID, - name = DUMMY_DEVICE_NAME, - publicKey = newKey, - creationDate = currentUtcTimeWithOffsetZero().minusDays(1), - ) - .toString(), - ) - } - ?: MockResponse().setResponseCode(400) + } ?: MockResponse().setResponseCode(400) } private fun handleDeviceListRequest(): MockResponse { return cachedPubKeyFromAppUnderTest?.let { cachedKey -> - MockResponse() - .setResponseCode(200) - .addJsonHeader() - .setBody( - JSONArray() - .put( - deviceJson( - id = DUMMY_ID, - name = DUMMY_DEVICE_NAME, - publicKey = cachedKey, - creationDate = currentUtcTimeWithOffsetZero().minusDays(1), - ), - ) - .toString(), - ) - } - ?: MockResponse().setResponseCode(400) + MockResponse().setResponseCode(200).addJsonHeader().setBody( + JSONArray().put( + deviceJson( + id = DUMMY_ID, + name = DUMMY_DEVICE_NAME, + publicKey = cachedKey, + creationDate = currentUtcTimeWithOffsetZero().minusDays(1), + ), + ).toString(), + ) + } ?: MockResponse().setResponseCode(400) } } diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt index b5ec95b32294..d604332e2c0a 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/MockApiTest.kt @@ -22,7 +22,8 @@ import java.net.InetAddress @RunWith(AndroidJUnit4::class) abstract class MockApiTest { - @Rule @JvmField + @Rule + @JvmField val rule = CaptureScreenshotOnFailedTestRule(LOG_TAG) @Rule diff --git a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt index 2ccae9499e67..5f2df6f9e4f3 100644 --- a/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt +++ b/android/test/mockapi/src/main/kotlin/net/mullvad/mullvadvpn/test/mockapi/util/JsonUtils.kt @@ -3,13 +3,12 @@ package net.mullvad.mullvadvpn.test.mockapi.util import org.joda.time.DateTime import org.json.JSONObject -fun accountInfoJson(id: String, expiry: DateTime) = - JSONObject().apply { - put("id", id) - put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339()) - put("max_devices", 5) - put("can_add_devices", true) - } +fun accountInfoJson(id: String, expiry: DateTime) = JSONObject().apply { + put("id", id) + put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339()) + put("max_devices", 5) + put("can_add_devices", true) +} fun deviceJson(id: String, name: String, publicKey: String, creationDate: DateTime) = JSONObject().apply { @@ -22,8 +21,7 @@ fun deviceJson(id: String, name: String, publicKey: String, creationDate: DateTi put("ipv6_address", "fc00::1/128") } -fun accessTokenJsonResponse(accessToken: String, expiry: DateTime) = - JSONObject().apply { - put("access_token", accessToken) - put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339()) - } +fun accessTokenJsonResponse(accessToken: String, expiry: DateTime) = JSONObject().apply { + put("access_token", accessToken) + put("expiry", expiry.formatStrictlyAccordingToIso8601AndRfc3339()) +} diff --git a/android/tile/src/main/kotlin/net/mullvad/mullvadvpn/tile/MullvadTileService.kt b/android/tile/src/main/kotlin/net/mullvad/mullvadvpn/tile/MullvadTileService.kt index 6786dd2ea8a4..76262361cc55 100644 --- a/android/tile/src/main/kotlin/net/mullvad/mullvadvpn/tile/MullvadTileService.kt +++ b/android/tile/src/main/kotlin/net/mullvad/mullvadvpn/tile/MullvadTileService.kt @@ -51,17 +51,15 @@ class MullvadTileService : TileService() { delay(unlockCheckDelayMillis) } return@withTimeoutOrNull true - } - ?: false + } ?: false } unlockAndRun { runBlocking { - val isUnlockStatusPropagated = - isUnlockStatusPropagatedWithinTimeout( - unlockTimeoutMillis = 1000L, - unlockCheckDelayMillis = 100L, - ) + val isUnlockStatusPropagated = isUnlockStatusPropagatedWithinTimeout( + unlockTimeoutMillis = 1000L, + unlockCheckDelayMillis = 100L, + ) if (isUnlockStatusPropagated) { toggleTunnel() @@ -87,30 +85,25 @@ class MullvadTileService : TileService() { if (!isSetup) { Log.d("MullvadTileService", "VPN service not setup, starting main activity") - val intent = - Intent().apply { - setClassName(applicationContext.packageName, MAIN_ACTIVITY_CLASS) - flags = - Intent.FLAG_ACTIVITY_CLEAR_TOP or - Intent.FLAG_ACTIVITY_SINGLE_TOP or - Intent.FLAG_ACTIVITY_NEW_TASK - action = Intent.ACTION_MAIN - } + val intent = Intent().apply { + setClassName(applicationContext.packageName, MAIN_ACTIVITY_CLASS) + flags = + Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP or Intent.FLAG_ACTIVITY_NEW_TASK + action = Intent.ACTION_MAIN + } startActivityAndCollapseCompat(intent) return } else { Log.d("MullvadTileService", "VPN service is setup") } - val intent = - Intent().apply { - setClassName(applicationContext.packageName, VPN_SERVICE_CLASS) - action = - if (qsTile.state == Tile.STATE_INACTIVE) { - KEY_CONNECT_ACTION - } else { - KEY_DISCONNECT_ACTION - } + val intent = Intent().apply { + setClassName(applicationContext.packageName, VPN_SERVICE_CLASS) + action = if (qsTile.state == Tile.STATE_INACTIVE) { + KEY_CONNECT_ACTION + } else { + KEY_DISCONNECT_ACTION } + } // Always start as foreground in case tile is out-of-sync. startForegroundService(intent) @@ -119,13 +112,12 @@ class MullvadTileService : TileService() { @SuppressLint("StartActivityAndCollapseDeprecated") private fun MullvadTileService.startActivityAndCollapseCompat(intent: Intent) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { - val pendingIntent = - PendingIntent.getActivity( - applicationContext, - 0, - intent, - SdkUtils.getSupportedPendingIntentFlags(), - ) + val pendingIntent = PendingIntent.getActivity( + applicationContext, + 0, + intent, + SdkUtils.getSupportedPendingIntentFlags(), + ) startActivityAndCollapse(pendingIntent) } else { startActivityAndCollapse(intent) @@ -134,9 +126,7 @@ class MullvadTileService : TileService() { @OptIn(FlowPreview::class) private fun CoroutineScope.launchListenToTunnelState() = launch { - ServiceConnection(this@MullvadTileService, this) - .tunnelState - .debounce(300L) + ServiceConnection(this@MullvadTileService, this).tunnelState.debounce(300L) .map { (tunnelState, connectionState) -> mapToTileState(tunnelState, connectionState) } .collect { updateTileState(it) } } @@ -157,6 +147,7 @@ class MullvadTileService : TileService() { Tile.STATE_INACTIVE } } + is TunnelState.Error -> { if (tunnelState.errorState.isBlocking) { Tile.STATE_ACTIVE diff --git a/android/tile/src/main/kotlin/net/mullvad/mullvadvpn/tile/ServiceConnection.kt b/android/tile/src/main/kotlin/net/mullvad/mullvadvpn/tile/ServiceConnection.kt index d1f1933b988c..d0fa24d1bad8 100644 --- a/android/tile/src/main/kotlin/net/mullvad/mullvadvpn/tile/ServiceConnection.kt +++ b/android/tile/src/main/kotlin/net/mullvad/mullvadvpn/tile/ServiceConnection.kt @@ -49,31 +49,27 @@ class ServiceConnection(context: Context, scope: CoroutineScope) { Channel(Channel.RENDEZVOUS) init { - val dispatcher = - handler.filterNotNull().dispatchTo { - listenerRegistrations = - subscribeToState(Event.ListenerReady::class, scope) { - Pair(connection, listenerId) - } - - val tunnelStateEvents = - subscribeToState( - Event.TunnelStateChange::class, - scope, - TunnelState.Disconnected, - ) { - tunnelState - } - - tunnelState = - tunnelStateEvents.combine(serviceConnectionStateChannel.consumeAsFlow()) { - tunnelState, - serviceConnectionState, - -> - tunnelState to serviceConnectionState - } + val dispatcher = handler.filterNotNull().dispatchTo { + listenerRegistrations = subscribeToState(Event.ListenerReady::class, scope) { + Pair(connection, listenerId) } + val tunnelStateEvents = subscribeToState( + Event.TunnelStateChange::class, + scope, + TunnelState.Disconnected, + ) { + tunnelState + } + + tunnelState = tunnelStateEvents.combine(serviceConnectionStateChannel.consumeAsFlow()) { + tunnelState, + serviceConnectionState, + -> + tunnelState to serviceConnectionState + } + } + scope.launch { connect(context) } scope.launch { dispatcher.collect() } scope.launch { unregisterOldListeners() } @@ -83,9 +79,7 @@ class ServiceConnection(context: Context, scope: CoroutineScope) { private suspend fun connect(context: Context) { val intent = Intent().apply { setClassName(context.packageName, VPN_SERVICE_CLASS) } - context - .bindServiceFlow(intent) - .onStart { emit(ServiceResult.NOT_CONNECTED) } + context.bindServiceFlow(intent).onStart { emit(ServiceResult.NOT_CONNECTED) } .onEach { result -> serviceConnectionStateChannel.send(result.connectionState) } .collect { result -> activeListeners.value = null @@ -103,8 +97,7 @@ class ServiceConnection(context: Context, scope: CoroutineScope) { private suspend fun unregisterOldListeners() { var oldListener: Pair? = null - activeListeners - .onCompletion { oldListener?.let(::unregisterListener) } + activeListeners.onCompletion { oldListener?.let(::unregisterListener) } .collect { newListener -> oldListener?.let(::unregisterListener) oldListener = newListener