diff --git a/changelog.d/7512.feature b/changelog.d/7512.feature new file mode 100644 index 0000000000..00411a75ad --- /dev/null +++ b/changelog.d/7512.feature @@ -0,0 +1 @@ +Push notifications toggle: align implementation for current session diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index f05a2a11e6..372692770e 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -1679,7 +1679,8 @@ Create New Room Create New Space No network. Please check your Internet connection. - Something went wrong. Please check your network connection and try again. + + Something went wrong. Please check your network connection and try again. "Change network" "Please wait…" Updating your data… diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesService.kt index 9d2c48e194..c65a5382fb 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/homeserver/HomeServerCapabilitiesService.kt @@ -16,6 +16,9 @@ package org.matrix.android.sdk.api.session.homeserver +import androidx.lifecycle.LiveData +import org.matrix.android.sdk.api.util.Optional + /** * This interface defines a method to retrieve the homeserver capabilities. */ @@ -30,4 +33,9 @@ interface HomeServerCapabilitiesService { * Get the HomeServer capabilities. */ fun getHomeServerCapabilities(): HomeServerCapabilities + + /** + * Get a LiveData on the HomeServer capabilities. + */ + fun getHomeServerCapabilitiesLive(): LiveData> } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt index 4c755b54b5..eb9e862de2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/DefaultHomeServerCapabilitiesService.kt @@ -16,8 +16,10 @@ package org.matrix.android.sdk.internal.session.homeserver +import androidx.lifecycle.LiveData import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService +import org.matrix.android.sdk.api.util.Optional import javax.inject.Inject internal class DefaultHomeServerCapabilitiesService @Inject constructor( @@ -33,4 +35,8 @@ internal class DefaultHomeServerCapabilitiesService @Inject constructor( return homeServerCapabilitiesDataSource.getHomeServerCapabilities() ?: HomeServerCapabilities() } + + override fun getHomeServerCapabilitiesLive(): LiveData> { + return homeServerCapabilitiesDataSource.getHomeServerCapabilitiesLive() + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesDataSource.kt index 6c913fa41e..beb1e67e40 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/homeserver/HomeServerCapabilitiesDataSource.kt @@ -16,9 +16,14 @@ package org.matrix.android.sdk.internal.session.homeserver +import androidx.lifecycle.LiveData +import androidx.lifecycle.Transformations import com.zhuinden.monarchy.Monarchy import io.realm.Realm +import io.realm.kotlin.where import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities +import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.api.util.toOptional import org.matrix.android.sdk.internal.database.mapper.HomeServerCapabilitiesMapper import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntity import org.matrix.android.sdk.internal.database.query.get @@ -26,7 +31,7 @@ import org.matrix.android.sdk.internal.di.SessionDatabase import javax.inject.Inject internal class HomeServerCapabilitiesDataSource @Inject constructor( - @SessionDatabase private val monarchy: Monarchy + @SessionDatabase private val monarchy: Monarchy, ) { fun getHomeServerCapabilities(): HomeServerCapabilities? { return Realm.getInstance(monarchy.realmConfiguration).use { realm -> @@ -35,4 +40,14 @@ internal class HomeServerCapabilitiesDataSource @Inject constructor( } } } + + fun getHomeServerCapabilitiesLive(): LiveData> { + val liveData = monarchy.findAllMappedWithChanges( + { realm: Realm -> realm.where() }, + { HomeServerCapabilitiesMapper.map(it) } + ) + return Transformations.map(liveData) { + it.firstOrNull().toOptional() + } + } } diff --git a/vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt b/vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt new file mode 100644 index 0000000000..81b524cde9 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.notification + +import im.vector.app.features.session.coroutineScope +import kotlinx.coroutines.Job +import kotlinx.coroutines.launch +import org.matrix.android.sdk.api.session.Session +import javax.inject.Inject +import javax.inject.Singleton + +@Singleton +class EnableNotificationsSettingUpdater @Inject constructor( + private val updateEnableNotificationsSettingOnChangeUseCase: UpdateEnableNotificationsSettingOnChangeUseCase, +) { + + private var job: Job? = null + + fun onSessionsStarted(session: Session) { + job?.cancel() + job = session.coroutineScope.launch { + updateEnableNotificationsSettingOnChangeUseCase.execute(session) + } + } +} diff --git a/vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.kt b/vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.kt new file mode 100644 index 0000000000..36df939bad --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.notification + +import im.vector.app.features.settings.VectorPreferences +import im.vector.app.features.settings.devices.v2.notification.GetNotificationsStatusUseCase +import im.vector.app.features.settings.devices.v2.notification.NotificationsStatus +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.onEach +import org.matrix.android.sdk.api.session.Session +import javax.inject.Inject + +/** + * Listen for changes in either Pusher or Account data to update the local enable notifications + * setting for the current device. + */ +class UpdateEnableNotificationsSettingOnChangeUseCase @Inject constructor( + private val vectorPreferences: VectorPreferences, + private val getNotificationsStatusUseCase: GetNotificationsStatusUseCase, +) { + + suspend fun execute(session: Session) { + val deviceId = session.sessionParams.deviceId ?: return + getNotificationsStatusUseCase.execute(session, deviceId) + .onEach(::updatePreference) + .collect() + } + + private fun updatePreference(notificationStatus: NotificationsStatus) { + when (notificationStatus) { + NotificationsStatus.ENABLED -> vectorPreferences.setNotificationEnabledForDevice(true) + NotificationsStatus.DISABLED -> vectorPreferences.setNotificationEnabledForDevice(false) + else -> Unit + } + } +} diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index cda6f5bae8..6f186262fc 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -97,12 +97,6 @@ class PushersManager @Inject constructor( return session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId } } - suspend fun togglePusherForCurrentSession(enable: Boolean) { - val session = activeSessionHolder.getSafeActiveSession() ?: return - val pusher = getPusherForCurrentSession() ?: return - session.pushersService().togglePusher(pusher, enable) - } - suspend fun unregisterEmailPusher(email: String) { val currentSession = activeSessionHolder.getSafeActiveSession() ?: return currentSession.pushersService().removeEmailPusher(email) diff --git a/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt index a5e1fe68bd..71863b8642 100644 --- a/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt +++ b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt @@ -19,6 +19,7 @@ package im.vector.app.core.session import android.content.Context import dagger.hilt.android.qualifiers.ApplicationContext import im.vector.app.core.extensions.startSyncing +import im.vector.app.core.notification.EnableNotificationsSettingUpdater import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.settings.VectorPreferences @@ -32,6 +33,7 @@ class ConfigureAndStartSessionUseCase @Inject constructor( private val webRtcCallManager: WebRtcCallManager, private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase, private val vectorPreferences: VectorPreferences, + private val enableNotificationsSettingUpdater: EnableNotificationsSettingUpdater, ) { suspend fun execute(session: Session, startSyncing: Boolean = true) { @@ -46,5 +48,6 @@ class ConfigureAndStartSessionUseCase @Inject constructor( if (vectorPreferences.isClientInfoRecordingEnabled()) { updateMatrixClientInfoUseCase.execute(session) } + enableNotificationsSettingUpdater.onSessionsStarted(session) } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCase.kt new file mode 100644 index 0000000000..0125d92ba6 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCase.kt @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import androidx.lifecycle.asFlow +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.map +import org.matrix.android.sdk.api.session.Session +import org.matrix.android.sdk.flow.unwrap +import javax.inject.Inject + +class CanTogglePushNotificationsViaPusherUseCase @Inject constructor() { + + fun execute(session: Session): Flow { + return session + .homeServerCapabilitiesService() + .getHomeServerCapabilitiesLive() + .asFlow() + .unwrap() + .map { it.canRemotelyTogglePushNotificationsOfDevices } + .distinctUntilChanged() + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCase.kt index dbf9adca14..194a2aebbf 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCase.kt @@ -16,18 +16,15 @@ package im.vector.app.features.settings.devices.v2.notification -import im.vector.app.core.di.ActiveSessionHolder +import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import javax.inject.Inject -class CheckIfCanTogglePushNotificationsViaAccountDataUseCase @Inject constructor( - private val activeSessionHolder: ActiveSessionHolder, -) { +class CheckIfCanTogglePushNotificationsViaAccountDataUseCase @Inject constructor() { - fun execute(deviceId: String): Boolean { - return activeSessionHolder - .getSafeActiveSession() - ?.accountDataService() - ?.getUserAccountDataEvent(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) != null + fun execute(session: Session, deviceId: String): Boolean { + return session + .accountDataService() + .getUserAccountDataEvent(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) != null } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCase.kt index 0d5bce663a..ca314bf145 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCase.kt @@ -16,20 +16,15 @@ package im.vector.app.features.settings.devices.v2.notification -import im.vector.app.core.di.ActiveSessionHolder -import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.Session import javax.inject.Inject -class CheckIfCanTogglePushNotificationsViaPusherUseCase @Inject constructor( - private val activeSessionHolder: ActiveSessionHolder, -) { +class CheckIfCanTogglePushNotificationsViaPusherUseCase @Inject constructor() { - fun execute(): Boolean { - return activeSessionHolder - .getSafeActiveSession() - ?.homeServerCapabilitiesService() - ?.getHomeServerCapabilities() - ?.canRemotelyTogglePushNotificationsOfDevices - .orFalse() + fun execute(session: Session): Boolean { + return session + .homeServerCapabilitiesService() + .getHomeServerCapabilities() + .canRemotelyTogglePushNotificationsOfDevices } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCase.kt index 69659bf23f..03e4e31f2e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCase.kt @@ -16,12 +16,13 @@ package im.vector.app.features.settings.devices.v2.notification -import im.vector.app.core.di.ActiveSessionHolder import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.distinctUntilChanged +import kotlinx.coroutines.flow.flatMapLatest import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map import org.matrix.android.sdk.api.account.LocalNotificationSettingsContent +import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.accountdata.UserAccountDataTypes import org.matrix.android.sdk.api.session.events.model.toModel import org.matrix.android.sdk.flow.flow @@ -29,16 +30,13 @@ import org.matrix.android.sdk.flow.unwrap import javax.inject.Inject class GetNotificationsStatusUseCase @Inject constructor( - private val activeSessionHolder: ActiveSessionHolder, - private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase, + private val canTogglePushNotificationsViaPusherUseCase: CanTogglePushNotificationsViaPusherUseCase, private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, ) { - fun execute(deviceId: String): Flow { - val session = activeSessionHolder.getSafeActiveSession() + fun execute(session: Session, deviceId: String): Flow { return when { - session == null -> flowOf(NotificationsStatus.NOT_SUPPORTED) - checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(deviceId) -> { + checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId) -> { session.flow() .liveUserAccountData(UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId) .unwrap() @@ -46,15 +44,19 @@ class GetNotificationsStatusUseCase @Inject constructor( .map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED } .distinctUntilChanged() } - checkIfCanTogglePushNotificationsViaPusherUseCase.execute() -> { - session.flow() - .livePushers() - .map { it.filter { pusher -> pusher.deviceId == deviceId } } - .map { it.takeIf { it.isNotEmpty() }?.any { pusher -> pusher.enabled } } - .map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED } - .distinctUntilChanged() - } - else -> flowOf(NotificationsStatus.NOT_SUPPORTED) + else -> canTogglePushNotificationsViaPusherUseCase.execute(session) + .flatMapLatest { canToggle -> + if (canToggle) { + session.flow() + .livePushers() + .map { it.filter { pusher -> pusher.deviceId == deviceId } } + .map { it.takeIf { it.isNotEmpty() }?.any { pusher -> pusher.enabled } } + .map { if (it == true) NotificationsStatus.ENABLED else NotificationsStatus.DISABLED } + .distinctUntilChanged() + } else { + flowOf(NotificationsStatus.NOT_SUPPORTED) + } + } } } } diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCase.kt index be9012e9f1..7969bbbe9b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCase.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCase.kt @@ -31,14 +31,14 @@ class TogglePushNotificationUseCase @Inject constructor( suspend fun execute(deviceId: String, enabled: Boolean) { val session = activeSessionHolder.getSafeActiveSession() ?: return - if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute()) { + if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) { val devicePusher = session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId } devicePusher?.let { pusher -> session.pushersService().togglePusher(pusher, enabled) } } - if (checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(deviceId)) { + if (checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId)) { val newNotificationSettingsContent = LocalNotificationSettingsContent(isSilenced = !enabled) session.accountDataService().updateUserAccountData( UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + deviceId, diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt index 9c4ece7e02..a56872e648 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModel.kt @@ -96,9 +96,11 @@ class SessionOverviewViewModel @AssistedInject constructor( } private fun observeNotificationsStatus(deviceId: String) { - getNotificationsStatusUseCase.execute(deviceId) - .onEach { setState { copy(notificationsStatus = it) } } - .launchIn(viewModelScope) + activeSessionHolder.getSafeActiveSession()?.let { session -> + getNotificationsStatusUseCase.execute(session, deviceId) + .onEach { setState { copy(notificationsStatus = it) } } + .launchIn(viewModelScope) + } } override fun handle(action: SessionOverviewAction) { diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt new file mode 100644 index 0000000000..61c884f0bc --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.pushers.PushersManager +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.features.settings.devices.v2.notification.CheckIfCanTogglePushNotificationsViaPusherUseCase +import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase +import javax.inject.Inject + +class DisableNotificationsForCurrentSessionUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, + private val unifiedPushHelper: UnifiedPushHelper, + private val pushersManager: PushersManager, + private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase, + private val togglePushNotificationUseCase: TogglePushNotificationUseCase, +) { + + suspend fun execute() { + val session = activeSessionHolder.getSafeActiveSession() ?: return + val deviceId = session.sessionParams.deviceId ?: return + if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) { + togglePushNotificationUseCase.execute(deviceId, enabled = false) + } else { + unifiedPushHelper.unregister(pushersManager) + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt new file mode 100644 index 0000000000..180627a15f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import androidx.fragment.app.FragmentActivity +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.pushers.FcmHelper +import im.vector.app.core.pushers.PushersManager +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.features.settings.devices.v2.notification.CheckIfCanTogglePushNotificationsViaPusherUseCase +import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase +import javax.inject.Inject +import kotlin.coroutines.resume +import kotlin.coroutines.resumeWithException +import kotlin.coroutines.suspendCoroutine + +class EnableNotificationsForCurrentSessionUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, + private val unifiedPushHelper: UnifiedPushHelper, + private val pushersManager: PushersManager, + private val fcmHelper: FcmHelper, + private val checkIfCanTogglePushNotificationsViaPusherUseCase: CheckIfCanTogglePushNotificationsViaPusherUseCase, + private val togglePushNotificationUseCase: TogglePushNotificationUseCase, +) { + + suspend fun execute(fragmentActivity: FragmentActivity) { + val pusherForCurrentSession = pushersManager.getPusherForCurrentSession() + if (pusherForCurrentSession == null) { + registerPusher(fragmentActivity) + } + + val session = activeSessionHolder.getSafeActiveSession() ?: return + if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) { + val deviceId = session.sessionParams.deviceId ?: return + togglePushNotificationUseCase.execute(deviceId, enabled = true) + } + } + + private suspend fun registerPusher(fragmentActivity: FragmentActivity) { + suspendCoroutine { continuation -> + try { + unifiedPushHelper.register(fragmentActivity) { + if (unifiedPushHelper.isEmbeddedDistributor()) { + fcmHelper.ensureFcmTokenIsRetrieved( + fragmentActivity, + pushersManager, + registerPusher = true + ) + } + continuation.resume(Unit) + } + } catch (error: Exception) { + continuation.resumeWithException(error) + } + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index f800c518f3..58f86bc949 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -57,7 +57,6 @@ import im.vector.app.features.settings.VectorSettingsBaseFragment import im.vector.app.features.settings.VectorSettingsFragmentInteractionListener import im.vector.lib.core.utils.compat.getParcelableExtraCompat import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.flow.map import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.session.Session @@ -81,6 +80,8 @@ class VectorSettingsNotificationPreferenceFragment : @Inject lateinit var guardServiceStarter: GuardServiceStarter @Inject lateinit var vectorFeatures: VectorFeatures @Inject lateinit var notificationPermissionManager: NotificationPermissionManager + @Inject lateinit var disableNotificationsForCurrentSessionUseCase: DisableNotificationsForCurrentSessionUseCase + @Inject lateinit var enableNotificationsForCurrentSessionUseCase: EnableNotificationsForCurrentSessionUseCase override var titleRes: Int = R.string.settings_notifications override val preferenceXmlRes = R.xml.vector_settings_notifications @@ -119,48 +120,25 @@ class VectorSettingsNotificationPreferenceFragment : (pref as SwitchPreference).isChecked = areNotifEnabledAtAccountLevel } - findPreference(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)?.let { - pushersManager.getPusherForCurrentSession()?.let { pusher -> - it.isChecked = pusher.enabled - } + findPreference(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY) + ?.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked -> + if (isChecked) { + enableNotificationsForCurrentSessionUseCase.execute(requireActivity()) - it.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked -> - if (isChecked) { - unifiedPushHelper.register(requireActivity()) { - // Update the summary - if (unifiedPushHelper.isEmbeddedDistributor()) { - fcmHelper.ensureFcmTokenIsRetrieved( - requireActivity(), - pushersManager, - vectorPreferences.areNotificationEnabledForDevice() - ) - } findPreference(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY) ?.summary = unifiedPushHelper.getCurrentDistributorName() - lifecycleScope.launch { - val result = runCatching { - pushersManager.togglePusherForCurrentSession(true) - } - result.exceptionOrNull()?.let { _ -> - Toast.makeText(context, R.string.error_check_network, Toast.LENGTH_SHORT).show() - it.isChecked = false - } - } + notificationPermissionManager.eventuallyRequestPermission( + requireActivity(), + postPermissionLauncher, + showRationale = false, + ignorePreference = true + ) + } else { + disableNotificationsForCurrentSessionUseCase.execute() + notificationPermissionManager.eventuallyRevokePermission(requireActivity()) } - notificationPermissionManager.eventuallyRequestPermission( - requireActivity(), - postPermissionLauncher, - showRationale = false, - ignorePreference = true - ) - } else { - unifiedPushHelper.unregister(pushersManager) - session.pushersService().refreshPushers() - notificationPermissionManager.eventuallyRevokePermission(requireActivity()) } - } - } findPreference(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let { it.onPreferenceClickListener = Preference.OnPreferenceClickListener { diff --git a/vector/src/test/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCaseTest.kt new file mode 100644 index 0000000000..5cced75735 --- /dev/null +++ b/vector/src/test/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCaseTest.kt @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.notification + +import im.vector.app.features.settings.devices.v2.notification.NotificationsStatus +import im.vector.app.test.fakes.FakeGetNotificationsStatusUseCase +import im.vector.app.test.fakes.FakeSession +import im.vector.app.test.fakes.FakeVectorPreferences +import kotlinx.coroutines.test.runTest +import org.junit.Test + +private const val A_SESSION_ID = "session-id" + +class UpdateEnableNotificationsSettingOnChangeUseCaseTest { + + private val fakeSession = FakeSession().also { it.givenSessionId(A_SESSION_ID) } + private val fakeVectorPreferences = FakeVectorPreferences() + private val fakeGetNotificationsStatusUseCase = FakeGetNotificationsStatusUseCase() + + private val updateEnableNotificationsSettingOnChangeUseCase = UpdateEnableNotificationsSettingOnChangeUseCase( + vectorPreferences = fakeVectorPreferences.instance, + getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase.instance, + ) + + @Test + fun `given notifications are enabled when execute then setting is updated to true`() = runTest { + // Given + fakeGetNotificationsStatusUseCase.givenExecuteReturns( + fakeSession, + A_SESSION_ID, + NotificationsStatus.ENABLED, + ) + fakeVectorPreferences.givenSetNotificationEnabledForDevice() + + // When + updateEnableNotificationsSettingOnChangeUseCase.execute(fakeSession) + + // Then + fakeVectorPreferences.verifySetNotificationEnabledForDevice(true) + } + + @Test + fun `given notifications are disabled when execute then setting is updated to false`() = runTest { + // Given + fakeGetNotificationsStatusUseCase.givenExecuteReturns( + fakeSession, + A_SESSION_ID, + NotificationsStatus.DISABLED, + ) + fakeVectorPreferences.givenSetNotificationEnabledForDevice() + + // When + updateEnableNotificationsSettingOnChangeUseCase.execute(fakeSession) + + // Then + fakeVectorPreferences.verifySetNotificationEnabledForDevice(false) + } + + @Test + fun `given notifications toggle is not supported when execute then nothing is done`() = runTest { + // Given + fakeGetNotificationsStatusUseCase.givenExecuteReturns( + fakeSession, + A_SESSION_ID, + NotificationsStatus.NOT_SUPPORTED, + ) + fakeVectorPreferences.givenSetNotificationEnabledForDevice() + + // When + updateEnableNotificationsSettingOnChangeUseCase.execute(fakeSession) + + // Then + fakeVectorPreferences.verifySetNotificationEnabledForDevice(true, inverse = true) + fakeVectorPreferences.verifySetNotificationEnabledForDevice(false, inverse = true) + } +} diff --git a/vector/src/test/java/im/vector/app/core/pushers/PushersManagerTest.kt b/vector/src/test/java/im/vector/app/core/pushers/PushersManagerTest.kt index 113a810ac2..7a1833e057 100644 --- a/vector/src/test/java/im/vector/app/core/pushers/PushersManagerTest.kt +++ b/vector/src/test/java/im/vector/app/core/pushers/PushersManagerTest.kt @@ -29,7 +29,6 @@ import im.vector.app.test.fixtures.CryptoDeviceInfoFixture.aCryptoDeviceInfo import im.vector.app.test.fixtures.PusherFixture import im.vector.app.test.fixtures.SessionParamsFixture import io.mockk.mockk -import kotlinx.coroutines.test.runTest import org.amshove.kluent.shouldBeEqualTo import org.junit.Test import org.matrix.android.sdk.api.session.crypto.model.UnsignedDeviceInfo @@ -101,19 +100,4 @@ class PushersManagerTest { pusher shouldBeEqualTo expectedPusher } - - @Test - fun `when togglePusherForCurrentSession, then do service toggle pusher`() = runTest { - val deviceId = "device_id" - val sessionParams = SessionParamsFixture.aSessionParams( - credentials = CredentialsFixture.aCredentials(deviceId = deviceId) - ) - session.givenSessionParams(sessionParams) - val pusher = PusherFixture.aPusher(deviceId = deviceId) - pushersService.givenGetPushers(listOf(pusher)) - - pushersManager.togglePusherForCurrentSession(true) - - pushersService.verifyTogglePusherCalled(pusher, true) - } } diff --git a/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt index 8d4507e85d..861e59e0f1 100644 --- a/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/core/session/ConfigureAndStartSessionUseCaseTest.kt @@ -19,6 +19,7 @@ package im.vector.app.core.session import im.vector.app.core.extensions.startSyncing import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase import im.vector.app.test.fakes.FakeContext +import im.vector.app.test.fakes.FakeEnableNotificationsSettingUpdater import im.vector.app.test.fakes.FakeSession import im.vector.app.test.fakes.FakeVectorPreferences import im.vector.app.test.fakes.FakeWebRtcCallManager @@ -43,12 +44,14 @@ class ConfigureAndStartSessionUseCaseTest { private val fakeWebRtcCallManager = FakeWebRtcCallManager() private val fakeUpdateMatrixClientInfoUseCase = mockk() private val fakeVectorPreferences = FakeVectorPreferences() + private val fakeEnableNotificationsSettingUpdater = FakeEnableNotificationsSettingUpdater() private val configureAndStartSessionUseCase = ConfigureAndStartSessionUseCase( context = fakeContext.instance, webRtcCallManager = fakeWebRtcCallManager.instance, updateMatrixClientInfoUseCase = fakeUpdateMatrixClientInfoUseCase, vectorPreferences = fakeVectorPreferences.instance, + enableNotificationsSettingUpdater = fakeEnableNotificationsSettingUpdater.instance, ) @Before @@ -68,6 +71,7 @@ class ConfigureAndStartSessionUseCaseTest { fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) + fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) // When configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) @@ -87,6 +91,7 @@ class ConfigureAndStartSessionUseCaseTest { fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = false) + fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) // When configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) @@ -106,6 +111,7 @@ class ConfigureAndStartSessionUseCaseTest { fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) + fakeEnableNotificationsSettingUpdater.givenOnSessionsStarted(fakeSession) // When configureAndStartSessionUseCase.execute(fakeSession, startSyncing = false) diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCaseTest.kt new file mode 100644 index 0000000000..997fa827f5 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCaseTest.kt @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.devices.v2.notification + +import im.vector.app.test.fakes.FakeFlowLiveDataConversions +import im.vector.app.test.fakes.FakeSession +import im.vector.app.test.fakes.givenAsFlow +import im.vector.app.test.fixtures.aHomeServerCapabilities +import io.mockk.unmockkAll +import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.test.runTest +import org.amshove.kluent.shouldBeEqualTo +import org.junit.After +import org.junit.Before +import org.junit.Test + +private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyTogglePushNotificationsOfDevices = true) + +class CanTogglePushNotificationsViaPusherUseCaseTest { + + private val fakeSession = FakeSession() + private val fakeFlowLiveDataConversions = FakeFlowLiveDataConversions() + + private val canTogglePushNotificationsViaPusherUseCase = + CanTogglePushNotificationsViaPusherUseCase() + + @Before + fun setUp() { + fakeFlowLiveDataConversions.setup() + } + + @After + fun tearDown() { + unmockkAll() + } + + @Test + fun `given current session when execute then flow of the toggle capability is returned`() = runTest { + // Given + fakeSession + .fakeHomeServerCapabilitiesService + .givenCapabilitiesLiveReturns(A_HOMESERVER_CAPABILITIES) + .givenAsFlow() + + // When + val result = canTogglePushNotificationsViaPusherUseCase.execute(fakeSession).firstOrNull() + + // Then + result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest.kt index 0303444605..37433364e8 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest.kt @@ -16,7 +16,7 @@ package im.vector.app.features.settings.devices.v2.notification -import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeSession import io.mockk.mockk import org.amshove.kluent.shouldBeEqualTo import org.junit.Test @@ -26,18 +26,15 @@ private const val A_DEVICE_ID = "device-id" class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest { - private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeSession = FakeSession() private val checkIfCanTogglePushNotificationsViaAccountDataUseCase = - CheckIfCanTogglePushNotificationsViaAccountDataUseCase( - activeSessionHolder = fakeActiveSessionHolder.instance, - ) + CheckIfCanTogglePushNotificationsViaAccountDataUseCase() @Test fun `given current session and an account data for the device id when execute then result is true`() { // Given - fakeActiveSessionHolder - .fakeSession + fakeSession .accountDataService() .givenGetUserAccountDataEventReturns( type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID, @@ -45,7 +42,7 @@ class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest { ) // When - val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) + val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) // Then result shouldBeEqualTo true @@ -54,8 +51,7 @@ class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest { @Test fun `given current session and NO account data for the device id when execute then result is false`() { // Given - fakeActiveSessionHolder - .fakeSession + fakeSession .accountDataService() .givenGetUserAccountDataEventReturns( type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID, @@ -63,7 +59,7 @@ class CheckIfCanTogglePushNotificationsViaAccountDataUseCaseTest { ) // When - val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) + val result = checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) // Then result shouldBeEqualTo false diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCaseTest.kt index 51874be1bc..508a05acd6 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CheckIfCanTogglePushNotificationsViaPusherUseCaseTest.kt @@ -16,7 +16,7 @@ package im.vector.app.features.settings.devices.v2.notification -import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeSession import im.vector.app.test.fixtures.aHomeServerCapabilities import org.amshove.kluent.shouldBeEqualTo import org.junit.Test @@ -25,37 +25,22 @@ private val A_HOMESERVER_CAPABILITIES = aHomeServerCapabilities(canRemotelyToggl class CheckIfCanTogglePushNotificationsViaPusherUseCaseTest { - private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeSession = FakeSession() private val checkIfCanTogglePushNotificationsViaPusherUseCase = - CheckIfCanTogglePushNotificationsViaPusherUseCase( - activeSessionHolder = fakeActiveSessionHolder.instance, - ) + CheckIfCanTogglePushNotificationsViaPusherUseCase() @Test fun `given current session when execute then toggle capability is returned`() { // Given - fakeActiveSessionHolder - .fakeSession + fakeSession .fakeHomeServerCapabilitiesService .givenCapabilities(A_HOMESERVER_CAPABILITIES) // When - val result = checkIfCanTogglePushNotificationsViaPusherUseCase.execute() + val result = checkIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) // Then result shouldBeEqualTo A_HOMESERVER_CAPABILITIES.canRemotelyTogglePushNotificationsOfDevices } - - @Test - fun `given no current session when execute then false is returned`() { - // Given - fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null) - - // When - val result = checkIfCanTogglePushNotificationsViaPusherUseCase.execute() - - // Then - result shouldBeEqualTo false - } } diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCaseTest.kt index b13018a20d..b38367b098 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/GetNotificationsStatusUseCaseTest.kt @@ -17,7 +17,7 @@ package im.vector.app.features.settings.devices.v2.notification import androidx.arch.core.executor.testing.InstantTaskExecutorRule -import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeSession import im.vector.app.test.fixtures.PusherFixture import im.vector.app.test.testDispatcher import io.mockk.every @@ -25,6 +25,7 @@ import io.mockk.mockk import io.mockk.verifyOrder import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.firstOrNull +import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.test.resetMain import kotlinx.coroutines.test.runTest import kotlinx.coroutines.test.setMain @@ -44,17 +45,16 @@ class GetNotificationsStatusUseCaseTest { @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule() - private val fakeActiveSessionHolder = FakeActiveSessionHolder() - private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase = - mockk() + private val fakeSession = FakeSession() private val fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase = mockk() + private val fakeCanTogglePushNotificationsViaPusherUseCase = + mockk() private val getNotificationsStatusUseCase = GetNotificationsStatusUseCase( - activeSessionHolder = fakeActiveSessionHolder.instance, - checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase, checkIfCanTogglePushNotificationsViaAccountDataUseCase = fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase, + canTogglePushNotificationsViaPusherUseCase = fakeCanTogglePushNotificationsViaPusherUseCase, ) @Before @@ -67,33 +67,21 @@ class GetNotificationsStatusUseCaseTest { Dispatchers.resetMain() } - @Test - fun `given NO current session when execute then resulting flow contains NOT_SUPPORTED value`() = runTest { - // Given - fakeActiveSessionHolder.givenGetSafeActiveSessionReturns(null) - - // When - val result = getNotificationsStatusUseCase.execute(A_DEVICE_ID) - - // Then - result.firstOrNull() shouldBeEqualTo NotificationsStatus.NOT_SUPPORTED - } - @Test fun `given current session and toggle is not supported when execute then resulting flow contains NOT_SUPPORTED value`() = runTest { // Given - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns false - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) } returns false + every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false + every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false) // When - val result = getNotificationsStatusUseCase.execute(A_DEVICE_ID) + val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) // Then result.firstOrNull() shouldBeEqualTo NotificationsStatus.NOT_SUPPORTED verifyOrder { // we should first check account data - fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) - fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() + fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) + fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } } @@ -106,12 +94,12 @@ class GetNotificationsStatusUseCaseTest { enabled = true, ) ) - fakeActiveSessionHolder.fakeSession.pushersService().givenPushersLive(pushers) - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns true - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) } returns false + fakeSession.pushersService().givenPushersLive(pushers) + every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns false + every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(true) // When - val result = getNotificationsStatusUseCase.execute(A_DEVICE_ID) + val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) // Then result.firstOrNull() shouldBeEqualTo NotificationsStatus.ENABLED @@ -120,8 +108,7 @@ class GetNotificationsStatusUseCaseTest { @Test fun `given current session and toggle via account data is supported when execute then resulting flow contains status based on settings value`() = runTest { // Given - fakeActiveSessionHolder - .fakeSession + fakeSession .accountDataService() .givenGetUserAccountDataEventReturns( type = UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + A_DEVICE_ID, @@ -129,11 +116,11 @@ class GetNotificationsStatusUseCaseTest { isSilenced = false ).toContent(), ) - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns false - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(A_DEVICE_ID) } returns true + every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, A_DEVICE_ID) } returns true + every { fakeCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns flowOf(false) // When - val result = getNotificationsStatusUseCase.execute(A_DEVICE_ID) + val result = getNotificationsStatusUseCase.execute(fakeSession, A_DEVICE_ID) // Then result.firstOrNull() shouldBeEqualTo NotificationsStatus.ENABLED diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCaseTest.kt index 0a649354f9..35c5979e53 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCaseTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/TogglePushNotificationUseCaseTest.kt @@ -49,10 +49,11 @@ class TogglePushNotificationUseCaseTest { PusherFixture.aPusher(deviceId = sessionId, enabled = false), PusherFixture.aPusher(deviceId = "another id", enabled = false) ) - activeSessionHolder.fakeSession.pushersService().givenPushersLive(pushers) - activeSessionHolder.fakeSession.pushersService().givenGetPushers(pushers) - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns true - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(sessionId) } returns false + val fakeSession = activeSessionHolder.fakeSession + fakeSession.pushersService().givenPushersLive(pushers) + fakeSession.pushersService().givenGetPushers(pushers) + every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns true + every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, sessionId) } returns false // When togglePushNotificationUseCase.execute(sessionId, true) @@ -69,13 +70,14 @@ class TogglePushNotificationUseCaseTest { PusherFixture.aPusher(deviceId = sessionId, enabled = false), PusherFixture.aPusher(deviceId = "another id", enabled = false) ) - activeSessionHolder.fakeSession.pushersService().givenPushersLive(pushers) - activeSessionHolder.fakeSession.accountDataService().givenGetUserAccountDataEventReturns( + val fakeSession = activeSessionHolder.fakeSession + fakeSession.pushersService().givenPushersLive(pushers) + fakeSession.accountDataService().givenGetUserAccountDataEventReturns( UserAccountDataTypes.TYPE_LOCAL_NOTIFICATION_SETTINGS + sessionId, LocalNotificationSettingsContent(isSilenced = true).toContent() ) - every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute() } returns false - every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(sessionId) } returns true + every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns false + every { fakeCheckIfCanTogglePushNotificationsViaAccountDataUseCase.execute(fakeSession, sessionId) } returns true // When togglePushNotificationUseCase.execute(sessionId, true) diff --git a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index f26c818e1d..1a57b76020 100644 --- a/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt +++ b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt @@ -22,11 +22,11 @@ import com.airbnb.mvrx.Success import com.airbnb.mvrx.test.MavericksTestRule import im.vector.app.features.settings.devices.v2.DeviceFullInfo import im.vector.app.features.settings.devices.v2.RefreshDevicesUseCase -import im.vector.app.features.settings.devices.v2.notification.GetNotificationsStatusUseCase import im.vector.app.features.settings.devices.v2.notification.NotificationsStatus import im.vector.app.features.settings.devices.v2.signout.InterceptSignoutFlowResponseUseCase import im.vector.app.features.settings.devices.v2.verification.CheckIfCurrentSessionCanBeVerifiedUseCase import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeGetNotificationsStatusUseCase import im.vector.app.test.fakes.FakePendingAuthHandler import im.vector.app.test.fakes.FakeSignoutSessionsUseCase import im.vector.app.test.fakes.FakeTogglePushNotificationUseCase @@ -75,7 +75,7 @@ class SessionOverviewViewModelTest { private val fakePendingAuthHandler = FakePendingAuthHandler() private val refreshDevicesUseCase = mockk(relaxed = true) private val togglePushNotificationUseCase = FakeTogglePushNotificationUseCase() - private val fakeGetNotificationsStatusUseCase = mockk() + private val fakeGetNotificationsStatusUseCase = FakeGetNotificationsStatusUseCase() private val notificationsStatus = NotificationsStatus.ENABLED private fun createViewModel() = SessionOverviewViewModel( @@ -88,7 +88,7 @@ class SessionOverviewViewModelTest { activeSessionHolder = fakeActiveSessionHolder.instance, refreshDevicesUseCase = refreshDevicesUseCase, togglePushNotificationUseCase = togglePushNotificationUseCase.instance, - getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase, + getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase.instance, ) @Before @@ -98,7 +98,11 @@ class SessionOverviewViewModelTest { every { SystemClock.elapsedRealtime() } returns 1234 givenVerificationService() - every { fakeGetNotificationsStatusUseCase.execute(A_SESSION_ID_1) } returns flowOf(notificationsStatus) + fakeGetNotificationsStatusUseCase.givenExecuteReturns( + fakeActiveSessionHolder.fakeSession, + A_SESSION_ID_1, + notificationsStatus + ) } private fun givenVerificationService(): FakeVerificationService { @@ -412,13 +416,10 @@ class SessionOverviewViewModelTest { @Test fun `when viewModel init, then observe pushers and emit to state`() { - val notificationStatus = NotificationsStatus.ENABLED - every { fakeGetNotificationsStatusUseCase.execute(A_SESSION_ID_1) } returns flowOf(notificationStatus) - val viewModel = createViewModel() viewModel.test() - .assertLatestState { state -> state.notificationsStatus == notificationStatus } + .assertLatestState { state -> state.notificationsStatus == notificationsStatus } .finish() } diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt new file mode 100644 index 0000000000..e460413a39 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import im.vector.app.features.settings.devices.v2.notification.CheckIfCanTogglePushNotificationsViaPusherUseCase +import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakePushersManager +import im.vector.app.test.fakes.FakeUnifiedPushHelper +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.junit.Test + +private const val A_SESSION_ID = "session-id" + +class DisableNotificationsForCurrentSessionUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeUnifiedPushHelper = FakeUnifiedPushHelper() + private val fakePushersManager = FakePushersManager() + private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase = mockk() + private val fakeTogglePushNotificationUseCase = mockk() + + private val disableNotificationsForCurrentSessionUseCase = DisableNotificationsForCurrentSessionUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance, + unifiedPushHelper = fakeUnifiedPushHelper.instance, + pushersManager = fakePushersManager.instance, + checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase, + togglePushNotificationUseCase = fakeTogglePushNotificationUseCase, + ) + + @Test + fun `given toggle via pusher is possible when execute then disable notification via toggle of existing pusher`() = runTest { + // Given + val fakeSession = fakeActiveSessionHolder.fakeSession + fakeSession.givenSessionId(A_SESSION_ID) + every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns true + coJustRun { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, any()) } + + // When + disableNotificationsForCurrentSessionUseCase.execute() + + // Then + coVerify { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, false) } + } + + @Test + fun `given toggle via pusher is NOT possible when execute then disable notification by unregistering the pusher`() = runTest { + // Given + val fakeSession = fakeActiveSessionHolder.fakeSession + fakeSession.givenSessionId(A_SESSION_ID) + every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeSession) } returns false + fakeUnifiedPushHelper.givenUnregister(fakePushersManager.instance) + + // When + disableNotificationsForCurrentSessionUseCase.execute() + + // Then + fakeUnifiedPushHelper.verifyUnregister(fakePushersManager.instance) + } +} diff --git a/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt b/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt new file mode 100644 index 0000000000..eb6629cb13 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.notifications + +import androidx.fragment.app.FragmentActivity +import im.vector.app.features.settings.devices.v2.notification.CheckIfCanTogglePushNotificationsViaPusherUseCase +import im.vector.app.features.settings.devices.v2.notification.TogglePushNotificationUseCase +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.fakes.FakeFcmHelper +import im.vector.app.test.fakes.FakePushersManager +import im.vector.app.test.fakes.FakeUnifiedPushHelper +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.junit.Test + +private const val A_SESSION_ID = "session-id" + +class EnableNotificationsForCurrentSessionUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeUnifiedPushHelper = FakeUnifiedPushHelper() + private val fakePushersManager = FakePushersManager() + private val fakeFcmHelper = FakeFcmHelper() + private val fakeCheckIfCanTogglePushNotificationsViaPusherUseCase = mockk() + private val fakeTogglePushNotificationUseCase = mockk() + + private val enableNotificationsForCurrentSessionUseCase = EnableNotificationsForCurrentSessionUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance, + unifiedPushHelper = fakeUnifiedPushHelper.instance, + pushersManager = fakePushersManager.instance, + fcmHelper = fakeFcmHelper.instance, + checkIfCanTogglePushNotificationsViaPusherUseCase = fakeCheckIfCanTogglePushNotificationsViaPusherUseCase, + togglePushNotificationUseCase = fakeTogglePushNotificationUseCase, + ) + + @Test + fun `given no existing pusher for current session when execute then a new pusher is registered`() = runTest { + // Given + val fragmentActivity = mockk() + fakePushersManager.givenGetPusherForCurrentSessionReturns(null) + fakeUnifiedPushHelper.givenRegister(fragmentActivity) + fakeUnifiedPushHelper.givenIsEmbeddedDistributorReturns(true) + fakeFcmHelper.givenEnsureFcmTokenIsRetrieved(fragmentActivity, fakePushersManager.instance) + every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeActiveSessionHolder.fakeSession) } returns false + + // When + enableNotificationsForCurrentSessionUseCase.execute(fragmentActivity) + + // Then + fakeUnifiedPushHelper.verifyRegister(fragmentActivity) + fakeFcmHelper.verifyEnsureFcmTokenIsRetrieved(fragmentActivity, fakePushersManager.instance, registerPusher = true) + } + + @Test + fun `given toggle via Pusher is possible when execute then current pusher is toggled to true`() = runTest { + // Given + val fragmentActivity = mockk() + fakePushersManager.givenGetPusherForCurrentSessionReturns(mockk()) + val fakeSession = fakeActiveSessionHolder.fakeSession + fakeSession.givenSessionId(A_SESSION_ID) + every { fakeCheckIfCanTogglePushNotificationsViaPusherUseCase.execute(fakeActiveSessionHolder.fakeSession) } returns true + coJustRun { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, any()) } + + // When + enableNotificationsForCurrentSessionUseCase.execute(fragmentActivity) + + // Then + coVerify { fakeTogglePushNotificationUseCase.execute(A_SESSION_ID, true) } + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeEnableNotificationsSettingUpdater.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeEnableNotificationsSettingUpdater.kt new file mode 100644 index 0000000000..a78dd1a34b --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeEnableNotificationsSettingUpdater.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.test.fakes + +import im.vector.app.core.notification.EnableNotificationsSettingUpdater +import io.mockk.justRun +import io.mockk.mockk +import org.matrix.android.sdk.api.session.Session + +class FakeEnableNotificationsSettingUpdater { + + val instance = mockk() + + fun givenOnSessionsStarted(session: Session) { + justRun { instance.onSessionsStarted(session) } + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeFcmHelper.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeFcmHelper.kt new file mode 100644 index 0000000000..11abf18794 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeFcmHelper.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.test.fakes + +import androidx.fragment.app.FragmentActivity +import im.vector.app.core.pushers.FcmHelper +import im.vector.app.core.pushers.PushersManager +import io.mockk.justRun +import io.mockk.mockk +import io.mockk.verify + +class FakeFcmHelper { + + val instance = mockk() + + fun givenEnsureFcmTokenIsRetrieved( + fragmentActivity: FragmentActivity, + pushersManager: PushersManager, + ) { + justRun { instance.ensureFcmTokenIsRetrieved(fragmentActivity, pushersManager, any()) } + } + + fun verifyEnsureFcmTokenIsRetrieved( + fragmentActivity: FragmentActivity, + pushersManager: PushersManager, + registerPusher: Boolean, + ) { + verify { instance.ensureFcmTokenIsRetrieved(fragmentActivity, pushersManager, registerPusher) } + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeGetNotificationsStatusUseCase.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeGetNotificationsStatusUseCase.kt new file mode 100644 index 0000000000..a9c1b37d69 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeGetNotificationsStatusUseCase.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.test.fakes + +import im.vector.app.features.settings.devices.v2.notification.GetNotificationsStatusUseCase +import im.vector.app.features.settings.devices.v2.notification.NotificationsStatus +import io.mockk.every +import io.mockk.mockk +import kotlinx.coroutines.flow.flowOf +import org.matrix.android.sdk.api.session.Session + +class FakeGetNotificationsStatusUseCase { + + val instance = mockk() + + fun givenExecuteReturns( + session: Session, + sessionId: String, + notificationsStatus: NotificationsStatus + ) { + every { instance.execute(session, sessionId) } returns flowOf(notificationsStatus) + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeHomeServerCapabilitiesService.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeHomeServerCapabilitiesService.kt index 006789f62b..c816c51c0f 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeHomeServerCapabilitiesService.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeHomeServerCapabilitiesService.kt @@ -16,14 +16,24 @@ package im.vector.app.test.fakes +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData import io.mockk.every import io.mockk.mockk import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilitiesService +import org.matrix.android.sdk.api.util.Optional +import org.matrix.android.sdk.api.util.toOptional class FakeHomeServerCapabilitiesService : HomeServerCapabilitiesService by mockk() { fun givenCapabilities(homeServerCapabilities: HomeServerCapabilities) { every { getHomeServerCapabilities() } returns homeServerCapabilities } + + fun givenCapabilitiesLiveReturns(homeServerCapabilities: HomeServerCapabilities): LiveData> { + return MutableLiveData(homeServerCapabilities.toOptional()).also { + every { getHomeServerCapabilitiesLive() } returns it + } + } } diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt b/vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt new file mode 100644 index 0000000000..46d852f4f8 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.test.fakes + +import im.vector.app.core.pushers.PushersManager +import io.mockk.every +import io.mockk.mockk +import org.matrix.android.sdk.api.session.pushers.Pusher + +class FakePushersManager { + + val instance = mockk() + + fun givenGetPusherForCurrentSessionReturns(pusher: Pusher?) { + every { instance.getPusherForCurrentSession() } returns pusher + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt new file mode 100644 index 0000000000..1f2cc8a1ce --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.test.fakes + +import androidx.fragment.app.FragmentActivity +import im.vector.app.core.pushers.PushersManager +import im.vector.app.core.pushers.UnifiedPushHelper +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify + +class FakeUnifiedPushHelper { + + val instance = mockk() + + fun givenRegister(fragmentActivity: FragmentActivity) { + every { instance.register(fragmentActivity, any()) } answers { + secondArg().run() + } + } + + fun verifyRegister(fragmentActivity: FragmentActivity) { + verify { instance.register(fragmentActivity, any()) } + } + + fun givenUnregister(pushersManager: PushersManager) { + coJustRun { instance.unregister(pushersManager) } + } + + fun verifyUnregister(pushersManager: PushersManager) { + coVerify { instance.unregister(pushersManager) } + } + + fun givenIsEmbeddedDistributorReturns(isEmbedded: Boolean) { + every { instance.isEmbeddedDistributor() } returns isEmbedded + } +} diff --git a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt index cd4f70bf63..4baa7e2b90 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeVectorPreferences.kt @@ -18,6 +18,7 @@ package im.vector.app.test.fakes import im.vector.app.features.settings.VectorPreferences import io.mockk.every +import io.mockk.justRun import io.mockk.mockk import io.mockk.verify @@ -42,5 +43,13 @@ class FakeVectorPreferences { } fun givenTextFormatting(isEnabled: Boolean) = - every { instance.isTextFormattingEnabled() } returns isEnabled + every { instance.isTextFormattingEnabled() } returns isEnabled + + fun givenSetNotificationEnabledForDevice() { + justRun { instance.setNotificationEnabledForDevice(any()) } + } + + fun verifySetNotificationEnabledForDevice(enabled: Boolean, inverse: Boolean = false) { + verify(inverse = inverse) { instance.setNotificationEnabledForDevice(enabled) } + } }