summaryrefslogtreecommitdiffhomepage
path: root/android/app/src/main
diff options
context:
space:
mode:
authorKalle Lindström <karl.lindstrom@mullvad.net>2025-10-22 10:19:32 +0200
committerKalle Lindström <karl.lindstrom@mullvad.net>2025-10-22 10:19:32 +0200
commit907b64d55b82eaf7600ff56e0a380c8ebcdd3235 (patch)
tree7de54fb33b3fa79f8f80b0de798d9fbfc2c7a152 /android/app/src/main
parent771f8a8cf3d429a0a6f5fcb445d8ef302e8f147b (diff)
parent65f4204221cc0285f4c97426503fe99b21610bf5 (diff)
downloadmullvadvpn-907b64d55b82eaf7600ff56e0a380c8ebcdd3235.tar.xz
mullvadvpn-907b64d55b82eaf7600ff56e0a380c8ebcdd3235.zip
Merge branch 'clear-out-of-time-notification-on-login-revoke-screens-droid-2245'
Diffstat (limited to 'android/app/src/main')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/MullvadApplication.kt10
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt4
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/NotificationAlarmReceiver.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/ScheduleNotificationBootCompletedReceiver.kt2
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/ScheduleNotificationAlarmUseCase.kt13
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt15
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt12
8 files changed, 35 insertions, 25 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/MullvadApplication.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/MullvadApplication.kt
index 43686b723b..655ed045e6 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/MullvadApplication.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/MullvadApplication.kt
@@ -59,17 +59,11 @@ class MullvadApplication : Application() {
when (action) {
NotificationAction.CancelExisting -> {
accountExpiryNotificationProvider.cancelNotification()
- scheduleNotificationAlarmUseCase(
- context = this@MullvadApplication,
- accountExpiry = null,
- )
+ scheduleNotificationAlarmUseCase(accountExpiry = null)
}
is NotificationAction.ScheduleAlarm ->
- scheduleNotificationAlarmUseCase(
- context = this@MullvadApplication,
- accountExpiry = action.alarmTime,
- )
+ scheduleNotificationAlarmUseCase(accountExpiry = action.alarmTime)
}
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt
index 58b1a6e478..05c5e6d92a 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/AppModule.kt
@@ -64,7 +64,7 @@ val appModule = module {
single { ConnectionProxy(get(), get(), get()) }
single { LocaleRepository(get()) }
single { RelayLocationTranslationRepository(get(), get(), MainScope()) }
- single { ScheduleNotificationAlarmUseCase(get()) }
+ single { ScheduleNotificationAlarmUseCase(androidContext(), get()) }
single { AccountExpiryNotificationActionUseCase(get(), get()) }
single { NotificationChannel.TunnelUpdates } bind NotificationChannel::class
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
index 7b2ae9986e..ffe1d078ed 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/di/UiModule.kt
@@ -255,11 +255,11 @@ val uiModule = module {
}
viewModel { DeviceListViewModel(get(), get()) }
viewModel { ManageDevicesViewModel(get(), get()) }
- viewModel { DeviceRevokedViewModel(get(), get()) }
+ viewModel { DeviceRevokedViewModel(get(), get(), get(), get()) }
viewModel { MtuDialogViewModel(get(), get()) }
viewModel { DnsDialogViewModel(get(), get(), get(), get()) }
viewModel { WireguardCustomPortDialogViewModel(get()) }
- viewModel { LoginViewModel(get(), get(), get()) }
+ viewModel { LoginViewModel(get(), get(), get(), get(), get()) }
viewModel { PrivacyDisclaimerViewModel(get(), IS_PLAY_BUILD) }
viewModel {
SelectLocationViewModel(get(), get(), get(), get(), get(), get(), get(), get(), get())
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/NotificationAlarmReceiver.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/NotificationAlarmReceiver.kt
index 49bd290230..a638152530 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/NotificationAlarmReceiver.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/NotificationAlarmReceiver.kt
@@ -33,7 +33,7 @@ class NotificationAlarmReceiver : BroadcastReceiver(), KoinComponent {
goAsync {
// Only schedule the next alarm if we still have time left on the account.
if (context != null && expiry > ZonedDateTime.now()) {
- scheduleNotificationAlarmUseCase(context = context, accountExpiry = expiry)
+ scheduleNotificationAlarmUseCase(accountExpiry = expiry, customContext = context)
}
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/ScheduleNotificationBootCompletedReceiver.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/ScheduleNotificationBootCompletedReceiver.kt
index d7ad2660e4..e972a55b93 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/ScheduleNotificationBootCompletedReceiver.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/receiver/ScheduleNotificationBootCompletedReceiver.kt
@@ -27,6 +27,6 @@ class ScheduleNotificationBootCompletedReceiver : BroadcastReceiver(), KoinCompo
private suspend fun scheduleAccountExpiryNotification(context: Context) {
val expiry = userPreferencesRepository.accountExpiry() ?: return
- scheduleNotificationAlarmUseCase(context, expiry)
+ scheduleNotificationAlarmUseCase(expiry, customContext = context)
}
}
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/ScheduleNotificationAlarmUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/ScheduleNotificationAlarmUseCase.kt
index 1c2bc63eb6..41045beb36 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/ScheduleNotificationAlarmUseCase.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/ScheduleNotificationAlarmUseCase.kt
@@ -12,13 +12,14 @@ import net.mullvad.mullvadvpn.repository.UserPreferencesRepository
import net.mullvad.mullvadvpn.service.notifications.accountexpiry.accountExpiryNotificationTriggerAt
class ScheduleNotificationAlarmUseCase(
- private val userPreferencesRepository: UserPreferencesRepository
+ private val applicationContext: Context,
+ private val userPreferencesRepository: UserPreferencesRepository,
) {
- suspend operator fun invoke(context: Context, accountExpiry: ZonedDateTime?) {
- val appContext = context.applicationContext
- val alarmManager = appContext.getSystemService(AlarmManager::class.java) ?: return
+ suspend operator fun invoke(accountExpiry: ZonedDateTime?, customContext: Context? = null) {
+ val context = customContext ?: applicationContext
+ val alarmManager = context.getSystemService(AlarmManager::class.java) ?: return
- cancelExisting(appContext, alarmManager)
+ cancelExisting(context, alarmManager)
if (accountExpiry == null) {
userPreferencesRepository.clearAccountExpiry()
@@ -29,7 +30,7 @@ class ScheduleNotificationAlarmUseCase(
accountExpiryNotificationTriggerAt(now = ZonedDateTime.now(), expiry = accountExpiry)
val triggerAtMillis = triggerAt.toInstant().toEpochMilli()
- val intent = alarmIntent(appContext, accountExpiry)
+ val intent = alarmIntent(context, accountExpiry)
alarmManager.set(AlarmManager.RTC, triggerAtMillis, intent)
// Change to UTC to avoid leaking the user's time zone in the logs
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt
index 020a384c6c..60a1101f43 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/DeviceRevokedViewModel.kt
@@ -2,13 +2,11 @@ package net.mullvad.mullvadvpn.viewmodel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.WhileSubscribed
import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
@@ -16,15 +14,22 @@ import net.mullvad.mullvadvpn.compose.state.DeviceRevokedUiState
import net.mullvad.mullvadvpn.constant.VIEW_MODEL_STOP_TIMEOUT
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.lib.shared.ConnectionProxy
+import net.mullvad.mullvadvpn.service.notifications.accountexpiry.AccountExpiryNotificationProvider
+import net.mullvad.mullvadvpn.usecase.ScheduleNotificationAlarmUseCase
class DeviceRevokedViewModel(
private val accountRepository: AccountRepository,
private val connectionProxy: ConnectionProxy,
- dispatcher: CoroutineDispatcher = Dispatchers.IO,
+ private val scheduleNotificationAlarmUseCase: ScheduleNotificationAlarmUseCase,
+ private val accountExpiryNotificationProvider: AccountExpiryNotificationProvider,
) : ViewModel() {
val uiState =
connectionProxy.tunnelState
+ .onStart {
+ accountExpiryNotificationProvider.cancelNotification()
+ scheduleNotificationAlarmUseCase(accountExpiry = null)
+ }
.map {
if (it.isSecured()) {
DeviceRevokedUiState.SECURED
@@ -33,7 +38,7 @@ class DeviceRevokedViewModel(
}
}
.stateIn(
- scope = CoroutineScope(dispatcher),
+ scope = viewModelScope,
started = SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT),
initialValue = DeviceRevokedUiState.UNKNOWN,
)
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt
index e114ccde7c..6092c30bf1 100644
--- a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/viewmodel/LoginViewModel.kt
@@ -33,7 +33,9 @@ import net.mullvad.mullvadvpn.lib.model.CreateAccountError
import net.mullvad.mullvadvpn.lib.model.LoginAccountError
import net.mullvad.mullvadvpn.lib.shared.AccountRepository
import net.mullvad.mullvadvpn.repository.NewDeviceRepository
+import net.mullvad.mullvadvpn.service.notifications.accountexpiry.AccountExpiryNotificationProvider
import net.mullvad.mullvadvpn.usecase.InternetAvailableUseCase
+import net.mullvad.mullvadvpn.usecase.ScheduleNotificationAlarmUseCase
import net.mullvad.mullvadvpn.util.delayAtLeast
import net.mullvad.mullvadvpn.util.getOrDefault
import net.mullvad.mullvadvpn.viewmodel.LoginUiSideEffect.NavigateToWelcome
@@ -59,6 +61,8 @@ class LoginViewModel(
private val accountRepository: AccountRepository,
private val newDeviceRepository: NewDeviceRepository,
private val internetAvailableUseCase: InternetAvailableUseCase,
+ private val scheduleNotificationAlarmUseCase: ScheduleNotificationAlarmUseCase,
+ private val accountExpiryNotificationProvider: AccountExpiryNotificationProvider,
private val dispatcher: CoroutineDispatcher = Dispatchers.IO,
) : ViewModel() {
private val _loginState = MutableStateFlow(LoginUiState.INITIAL.loginState)
@@ -77,7 +81,13 @@ class LoginViewModel(
val uiState: StateFlow<LoginUiState> =
_uiState
- .onStart { viewModelScope.launch { accountRepository.fetchAccountHistory() } }
+ .onStart {
+ viewModelScope.launch {
+ accountRepository.fetchAccountHistory()
+ accountExpiryNotificationProvider.cancelNotification()
+ scheduleNotificationAlarmUseCase(accountExpiry = null)
+ }
+ }
.stateIn(
viewModelScope,
SharingStarted.WhileSubscribed(VIEW_MODEL_STOP_TIMEOUT),