From 41ab29d4c008c7abd61db0f6cdc860cf01e894e9 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 2 Nov 2022 17:17:44 +0100 Subject: [PATCH 01/13] Adding changelog entry --- changelog.d/7512.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7512.feature 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 From 2941cfa329519de3248e437f7e92de3c5d7ab802 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 3 Nov 2022 11:39:56 +0100 Subject: [PATCH 02/13] Adding use cases to handle toggle of push notifications for current session --- .../src/main/res/values/strings.xml | 3 +- .../vector/app/core/pushers/PushersManager.kt | 6 -- ...leNotificationsForCurrentSessionUseCase.kt | 44 ++++++++++++ ...leNotificationsForCurrentSessionUseCase.kt | 72 +++++++++++++++++++ ...rSettingsNotificationPreferenceFragment.kt | 32 +++------ 5 files changed, 126 insertions(+), 31 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt 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/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/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.kt new file mode 100644 index 0000000000..8962e8d67d --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCase.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.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, +) { + + // TODO add unit tests + suspend fun execute() { + val session = activeSessionHolder.getSafeActiveSession() ?: return + val deviceId = session.sessionParams.deviceId ?: return + if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute()) { + 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..ef37f67bef --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCase.kt @@ -0,0 +1,72 @@ +/* + * 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, +) { + + // TODO add unit tests + suspend fun execute(fragmentActivity: FragmentActivity) { + val pusherForCurrentSession = pushersManager.getPusherForCurrentSession() + if (pusherForCurrentSession == null) { + registerPusher(fragmentActivity) + } + + if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute()) { + val session = activeSessionHolder.getSafeActiveSession() ?: return + 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..4a43a20de3 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 @@ -126,28 +127,12 @@ class VectorSettingsNotificationPreferenceFragment : 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) - } + enableNotificationsForCurrentSessionUseCase.execute(requireActivity()) - result.exceptionOrNull()?.let { _ -> - Toast.makeText(context, R.string.error_check_network, Toast.LENGTH_SHORT).show() - it.isChecked = false - } - } - } + findPreference(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY) + ?.summary = unifiedPushHelper.getCurrentDistributorName() + + // TODO test with API 33 notificationPermissionManager.eventuallyRequestPermission( requireActivity(), postPermissionLauncher, @@ -155,8 +140,7 @@ class VectorSettingsNotificationPreferenceFragment : ignorePreference = true ) } else { - unifiedPushHelper.unregister(pushersManager) - session.pushersService().refreshPushers() + disableNotificationsForCurrentSessionUseCase.execute() notificationPermissionManager.eventuallyRevokePermission(requireActivity()) } } From 67d2a6faab0979c48e1b9d9f43de8565d06e0635 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 3 Nov 2022 16:31:41 +0100 Subject: [PATCH 03/13] Use the preference value to render the push notifications toggle --- ...rSettingsNotificationPreferenceFragment.kt | 38 ++++++++----------- 1 file changed, 16 insertions(+), 22 deletions(-) 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 4a43a20de3..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 @@ -120,31 +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) { - enableNotificationsForCurrentSessionUseCase.execute(requireActivity()) + findPreference(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY) + ?.summary = unifiedPushHelper.getCurrentDistributorName() - findPreference(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY) - ?.summary = unifiedPushHelper.getCurrentDistributorName() - - // TODO test with API 33 - notificationPermissionManager.eventuallyRequestPermission( - requireActivity(), - postPermissionLauncher, - showRationale = false, - ignorePreference = true - ) - } else { - disableNotificationsForCurrentSessionUseCase.execute() - notificationPermissionManager.eventuallyRevokePermission(requireActivity()) + notificationPermissionManager.eventuallyRequestPermission( + requireActivity(), + postPermissionLauncher, + showRationale = false, + ignorePreference = true + ) + } else { + disableNotificationsForCurrentSessionUseCase.execute() + notificationPermissionManager.eventuallyRevokePermission(requireActivity()) + } } - } - } findPreference(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let { it.onPreferenceClickListener = Preference.OnPreferenceClickListener { From 24a5cfa9e54fed6b9d9aaebd5f9471222e883786 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 3 Nov 2022 16:33:16 +0100 Subject: [PATCH 04/13] Listen for pusher or account data changes to update the local setting --- .../HomeServerCapabilitiesService.kt | 8 +++ .../DefaultHomeServerCapabilitiesService.kt | 6 +++ .../HomeServerCapabilitiesDataSource.kt | 17 +++++- .../vector/app/core/di/ActiveSessionHolder.kt | 1 + .../EnableNotificationsSettingUpdater.kt | 41 ++++++++++++++ ...ableNotificationsSettingOnChangeUseCase.kt | 53 +++++++++++++++++++ .../ConfigureAndStartSessionUseCase.kt | 4 ++ ...TogglePushNotificationsViaPusherUseCase.kt | 36 +++++++++++++ ...ePushNotificationsViaAccountDataUseCase.kt | 15 +++--- ...TogglePushNotificationsViaPusherUseCase.kt | 19 +++---- .../GetNotificationsStatusUseCase.kt | 34 ++++++------ .../TogglePushNotificationUseCase.kt | 4 +- .../v2/overview/SessionOverviewViewModel.kt | 8 +-- ...leNotificationsForCurrentSessionUseCase.kt | 2 +- ...leNotificationsForCurrentSessionUseCase.kt | 4 +- 15 files changed, 206 insertions(+), 46 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt create mode 100644 vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCase.kt 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/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt index 7e4f73e7a5..1e9f080303 100644 --- a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt +++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt @@ -19,6 +19,7 @@ package im.vector.app.core.di import android.content.Context import im.vector.app.ActiveSessionDataSource import im.vector.app.core.extensions.startSyncing +import im.vector.app.core.notification.EnableNotificationsSettingUpdater import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.session.ConfigureAndStartSessionUseCase 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..21febaee9d --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt @@ -0,0 +1,41 @@ +/* + * 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.flow.launchIn +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) + .launchIn(this) + } + } +} 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..a6bcf17b5c --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.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.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.Flow +import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.onEach +import org.matrix.android.sdk.api.session.Session +import timber.log.Timber +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, +) { + + // TODO add unit tests + fun execute(session: Session): Flow { + val deviceId = session.sessionParams.deviceId ?: return emptyFlow() + return getNotificationsStatusUseCase.execute(session, deviceId) + .onEach(::updatePreference) + } + + private fun updatePreference(notificationStatus: NotificationsStatus) { + Timber.d("updatePreference with status=$notificationStatus") + 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/session/ConfigureAndStartSessionUseCase.kt b/vector/src/main/java/im/vector/app/core/session/ConfigureAndStartSessionUseCase.kt index a5e1fe68bd..00dc1ab5f9 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,8 +33,10 @@ class ConfigureAndStartSessionUseCase @Inject constructor( private val webRtcCallManager: WebRtcCallManager, private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase, private val vectorPreferences: VectorPreferences, + private val enableNotificationsSettingUpdater: EnableNotificationsSettingUpdater, ) { + // TODO update unit tests suspend fun execute(session: Session, startSyncing: Boolean = true) { Timber.i("Configure and start session for ${session.myUserId}. startSyncing: $startSyncing") session.open() @@ -46,5 +49,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..963768ca04 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCase.kt @@ -0,0 +1,36 @@ +/* + * 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.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 } + } +} 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 index 8962e8d67d..d66bf8b789 100644 --- 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 @@ -35,7 +35,7 @@ class DisableNotificationsForCurrentSessionUseCase @Inject constructor( suspend fun execute() { val session = activeSessionHolder.getSafeActiveSession() ?: return val deviceId = session.sessionParams.deviceId ?: return - if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute()) { + 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 index ef37f67bef..cee653380a 100644 --- 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 @@ -44,8 +44,8 @@ class EnableNotificationsForCurrentSessionUseCase @Inject constructor( registerPusher(fragmentActivity) } - if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute()) { - val session = activeSessionHolder.getSafeActiveSession() ?: return + val session = activeSessionHolder.getSafeActiveSession() ?: return + if (checkIfCanTogglePushNotificationsViaPusherUseCase.execute(session)) { val deviceId = session.sessionParams.deviceId ?: return togglePushNotificationUseCase.execute(deviceId, enabled = true) } From 6239b3e68618cbbdc9cf18f6afa8cbdda483ec30 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 3 Nov 2022 17:48:49 +0100 Subject: [PATCH 05/13] Adding some TODOs --- .../notification/CanTogglePushNotificationsViaPusherUseCase.kt | 1 + .../CheckIfCanTogglePushNotificationsViaAccountDataUseCase.kt | 1 + .../CheckIfCanTogglePushNotificationsViaPusherUseCase.kt | 1 + .../devices/v2/notification/GetNotificationsStatusUseCase.kt | 1 + .../devices/v2/notification/TogglePushNotificationUseCase.kt | 1 + 5 files changed, 5 insertions(+) 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 index 963768ca04..af15e2f349 100644 --- 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 @@ -25,6 +25,7 @@ import javax.inject.Inject class CanTogglePushNotificationsViaPusherUseCase @Inject constructor() { + // TODO add unit tests fun execute(session: Session): Flow { return session .homeServerCapabilitiesService() 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 194a2aebbf..85abd7cd35 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 @@ -22,6 +22,7 @@ import javax.inject.Inject class CheckIfCanTogglePushNotificationsViaAccountDataUseCase @Inject constructor() { + // TODO update unit tests fun execute(session: Session, deviceId: String): Boolean { return session .accountDataService() 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 ca314bf145..9c2a471120 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 @@ -21,6 +21,7 @@ import javax.inject.Inject class CheckIfCanTogglePushNotificationsViaPusherUseCase @Inject constructor() { + // TODO update unit tests fun execute(session: Session): Boolean { return session .homeServerCapabilitiesService() 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 03e4e31f2e..ed1d54e118 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 @@ -34,6 +34,7 @@ class GetNotificationsStatusUseCase @Inject constructor( private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, ) { + // TODO update unit tests fun execute(session: Session, deviceId: String): Flow { return when { checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId) -> { 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 7969bbbe9b..28018f9687 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 @@ -28,6 +28,7 @@ class TogglePushNotificationUseCase @Inject constructor( private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, ) { + // TODO update unit tests suspend fun execute(deviceId: String, enabled: Boolean) { val session = activeSessionHolder.getSafeActiveSession() ?: return From 18929324fee53d6fc81a4c252a65534c073c25b4 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 4 Nov 2022 10:28:24 +0100 Subject: [PATCH 06/13] Updating existing unit tests --- .../vector/app/core/di/ActiveSessionHolder.kt | 1 - .../ConfigureAndStartSessionUseCase.kt | 1 - ...ePushNotificationsViaAccountDataUseCase.kt | 1 - ...TogglePushNotificationsViaPusherUseCase.kt | 1 - .../GetNotificationsStatusUseCase.kt | 1 - .../TogglePushNotificationUseCase.kt | 1 - .../app/core/pushers/PushersManagerTest.kt | 16 ------ .../ConfigureAndStartSessionUseCaseTest.kt | 6 +++ ...hNotificationsViaAccountDataUseCaseTest.kt | 18 +++---- ...lePushNotificationsViaPusherUseCaseTest.kt | 25 ++------- .../GetNotificationsStatusUseCaseTest.kt | 51 +++++++------------ .../TogglePushNotificationUseCaseTest.kt | 18 ++++--- .../overview/SessionOverviewViewModelTest.kt | 9 ++-- .../FakeEnableNotificationsSettingUpdater.kt | 31 +++++++++++ 14 files changed, 82 insertions(+), 98 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeEnableNotificationsSettingUpdater.kt diff --git a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt index 1e9f080303..7e4f73e7a5 100644 --- a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt +++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt @@ -19,7 +19,6 @@ package im.vector.app.core.di import android.content.Context import im.vector.app.ActiveSessionDataSource import im.vector.app.core.extensions.startSyncing -import im.vector.app.core.notification.EnableNotificationsSettingUpdater import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.session.ConfigureAndStartSessionUseCase 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 00dc1ab5f9..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 @@ -36,7 +36,6 @@ class ConfigureAndStartSessionUseCase @Inject constructor( private val enableNotificationsSettingUpdater: EnableNotificationsSettingUpdater, ) { - // TODO update unit tests suspend fun execute(session: Session, startSyncing: Boolean = true) { Timber.i("Configure and start session for ${session.myUserId}. startSyncing: $startSyncing") session.open() 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 85abd7cd35..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 @@ -22,7 +22,6 @@ import javax.inject.Inject class CheckIfCanTogglePushNotificationsViaAccountDataUseCase @Inject constructor() { - // TODO update unit tests fun execute(session: Session, deviceId: String): Boolean { return session .accountDataService() 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 9c2a471120..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 @@ -21,7 +21,6 @@ import javax.inject.Inject class CheckIfCanTogglePushNotificationsViaPusherUseCase @Inject constructor() { - // TODO update unit tests fun execute(session: Session): Boolean { return session .homeServerCapabilitiesService() 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 ed1d54e118..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 @@ -34,7 +34,6 @@ class GetNotificationsStatusUseCase @Inject constructor( private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, ) { - // TODO update unit tests fun execute(session: Session, deviceId: String): Flow { return when { checkIfCanTogglePushNotificationsViaAccountDataUseCase.execute(session, deviceId) -> { 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 28018f9687..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 @@ -28,7 +28,6 @@ class TogglePushNotificationUseCase @Inject constructor( private val checkIfCanTogglePushNotificationsViaAccountDataUseCase: CheckIfCanTogglePushNotificationsViaAccountDataUseCase, ) { - // TODO update unit tests suspend fun execute(deviceId: String, enabled: Boolean) { val session = activeSessionHolder.getSafeActiveSession() ?: return 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/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..444e14ec0e 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 @@ -37,6 +37,8 @@ import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every import io.mockk.just +import io.mockk.justRun +import io.mockk.justRun import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.runs @@ -98,7 +100,7 @@ class SessionOverviewViewModelTest { every { SystemClock.elapsedRealtime() } returns 1234 givenVerificationService() - every { fakeGetNotificationsStatusUseCase.execute(A_SESSION_ID_1) } returns flowOf(notificationsStatus) + every { fakeGetNotificationsStatusUseCase.execute(fakeActiveSessionHolder.fakeSession, A_SESSION_ID_1) } returns flowOf(notificationsStatus) } private fun givenVerificationService(): FakeVerificationService { @@ -412,13 +414,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/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) } + } +} From e5e971683b6faa9a85049080f743177b944cfe67 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 4 Nov 2022 11:47:23 +0100 Subject: [PATCH 07/13] Adding unit tests on CanTogglePushNotificationsViaPusherUseCase --- ...TogglePushNotificationsViaPusherUseCase.kt | 1 - ...lePushNotificationsViaPusherUseCaseTest.kt | 65 +++++++++++++++++++ .../FakeHomeServerCapabilitiesService.kt | 10 +++ 3 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/devices/v2/notification/CanTogglePushNotificationsViaPusherUseCaseTest.kt 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 index af15e2f349..963768ca04 100644 --- 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 @@ -25,7 +25,6 @@ import javax.inject.Inject class CanTogglePushNotificationsViaPusherUseCase @Inject constructor() { - // TODO add unit tests fun execute(session: Session): Flow { return session .homeServerCapabilitiesService() 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/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 + } + } } From 2eeb04426b49ab5496e5e5fce8a493795fd8505c Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 4 Nov 2022 14:22:50 +0100 Subject: [PATCH 08/13] Adding unit tests on DisableNotificationsForCurrentSessionUseCase --- ...leNotificationsForCurrentSessionUseCase.kt | 1 - ...tificationsForCurrentSessionUseCaseTest.kt | 78 +++++++++++++++++++ .../app/test/fakes/FakePushersManager.kt | 25 ++++++ .../app/test/fakes/FakeUnifiedPushHelper.kt | 36 +++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/notifications/DisableNotificationsForCurrentSessionUseCaseTest.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt 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 index d66bf8b789..61c884f0bc 100644 --- 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 @@ -31,7 +31,6 @@ class DisableNotificationsForCurrentSessionUseCase @Inject constructor( private val togglePushNotificationUseCase: TogglePushNotificationUseCase, ) { - // TODO add unit tests suspend fun execute() { val session = activeSessionHolder.getSafeActiveSession() ?: return val deviceId = session.sessionParams.deviceId ?: return 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/test/fakes/FakePushersManager.kt b/vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt new file mode 100644 index 0000000000..245662b0c6 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt @@ -0,0 +1,25 @@ +/* + * 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.mockk + +class FakePushersManager { + + val instance = mockk() +} 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..d7985d9757 --- /dev/null +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt @@ -0,0 +1,36 @@ +/* + * 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 im.vector.app.core.pushers.UnifiedPushHelper +import io.mockk.coJustRun +import io.mockk.coVerify +import io.mockk.mockk + +class FakeUnifiedPushHelper { + + val instance = mockk() + + fun givenUnregister(pushersManager: PushersManager) { + coJustRun { instance.unregister(pushersManager) } + } + + fun verifyUnregister(pushersManager: PushersManager) { + coVerify { instance.unregister(pushersManager) } + } +} From b43c3a8502e6a18df0f2198cbb9ebacb3f487ac6 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 4 Nov 2022 14:42:52 +0100 Subject: [PATCH 09/13] Adding unit tests on UpdateEnableNotificationsSettingOnChangeUseCase --- .../EnableNotificationsSettingUpdater.kt | 2 - ...ableNotificationsSettingOnChangeUseCase.kt | 11 ++- ...NotificationsSettingOnChangeUseCaseTest.kt | 90 +++++++++++++++++++ .../overview/SessionOverviewViewModelTest.kt | 12 ++- .../FakeGetNotificationsStatusUseCase.kt | 37 ++++++++ .../app/test/fakes/FakeVectorPreferences.kt | 11 ++- 6 files changed, 150 insertions(+), 13 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCaseTest.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeGetNotificationsStatusUseCase.kt 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 index 21febaee9d..81b524cde9 100644 --- a/vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt +++ b/vector/src/main/java/im/vector/app/core/notification/EnableNotificationsSettingUpdater.kt @@ -18,7 +18,6 @@ package im.vector.app.core.notification import im.vector.app.features.session.coroutineScope import kotlinx.coroutines.Job -import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import javax.inject.Inject @@ -35,7 +34,6 @@ class EnableNotificationsSettingUpdater @Inject constructor( job?.cancel() job = session.coroutineScope.launch { updateEnableNotificationsSettingOnChangeUseCase.execute(session) - .launchIn(this) } } } 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 index a6bcf17b5c..55a2cfdc64 100644 --- a/vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.kt +++ b/vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.kt @@ -19,8 +19,7 @@ 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.Flow -import kotlinx.coroutines.flow.emptyFlow +import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.Session import timber.log.Timber @@ -35,11 +34,11 @@ class UpdateEnableNotificationsSettingOnChangeUseCase @Inject constructor( private val getNotificationsStatusUseCase: GetNotificationsStatusUseCase, ) { - // TODO add unit tests - fun execute(session: Session): Flow { - val deviceId = session.sessionParams.deviceId ?: return emptyFlow() - return getNotificationsStatusUseCase.execute(session, deviceId) + suspend fun execute(session: Session) { + val deviceId = session.sessionParams.deviceId ?: return + getNotificationsStatusUseCase.execute(session, deviceId) .onEach(::updatePreference) + .collect() } private fun updatePreference(notificationStatus: NotificationsStatus) { 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/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/devices/v2/overview/SessionOverviewViewModelTest.kt index 444e14ec0e..86a9969a6a 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 @@ -77,7 +77,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( @@ -90,7 +90,7 @@ class SessionOverviewViewModelTest { activeSessionHolder = fakeActiveSessionHolder.instance, refreshDevicesUseCase = refreshDevicesUseCase, togglePushNotificationUseCase = togglePushNotificationUseCase.instance, - getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase, + getNotificationsStatusUseCase = fakeGetNotificationsStatusUseCase.instance, ) @Before @@ -100,7 +100,11 @@ class SessionOverviewViewModelTest { every { SystemClock.elapsedRealtime() } returns 1234 givenVerificationService() - every { fakeGetNotificationsStatusUseCase.execute(fakeActiveSessionHolder.fakeSession, A_SESSION_ID_1) } returns flowOf(notificationsStatus) + fakeGetNotificationsStatusUseCase.givenExecuteReturns( + fakeActiveSessionHolder.fakeSession, + A_SESSION_ID_1, + notificationsStatus + ) } private fun givenVerificationService(): FakeVerificationService { 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/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) } + } } From ced4bf3573a51b13ac5211980415978c686ed770 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 4 Nov 2022 15:10:19 +0100 Subject: [PATCH 10/13] Adding unit tests on EnableNotificationsForCurrentSessionUseCase --- ...leNotificationsForCurrentSessionUseCase.kt | 1 - ...tificationsForCurrentSessionUseCaseTest.kt | 87 +++++++++++++++++++ .../im/vector/app/test/fakes/FakeFcmHelper.kt | 44 ++++++++++ .../app/test/fakes/FakePushersManager.kt | 6 ++ .../app/test/fakes/FakeUnifiedPushHelper.kt | 17 ++++ 5 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/notifications/EnableNotificationsForCurrentSessionUseCaseTest.kt create mode 100644 vector/src/test/java/im/vector/app/test/fakes/FakeFcmHelper.kt 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 index cee653380a..180627a15f 100644 --- 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 @@ -37,7 +37,6 @@ class EnableNotificationsForCurrentSessionUseCase @Inject constructor( private val togglePushNotificationUseCase: TogglePushNotificationUseCase, ) { - // TODO add unit tests suspend fun execute(fragmentActivity: FragmentActivity) { val pusherForCurrentSession = pushersManager.getPusherForCurrentSession() if (pusherForCurrentSession == null) { 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/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/FakePushersManager.kt b/vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt index 245662b0c6..46d852f4f8 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakePushersManager.kt @@ -17,9 +17,15 @@ 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 index d7985d9757..1f2cc8a1ce 100644 --- a/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt +++ b/vector/src/test/java/im/vector/app/test/fakes/FakeUnifiedPushHelper.kt @@ -16,16 +16,29 @@ 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) } } @@ -33,4 +46,8 @@ class FakeUnifiedPushHelper { fun verifyUnregister(pushersManager: PushersManager) { coVerify { instance.unregister(pushersManager) } } + + fun givenIsEmbeddedDistributorReturns(isEmbedded: Boolean) { + every { instance.isEmbeddedDistributor() } returns isEmbedded + } } From 163bf57fdaf001bd7f8366b850acad8e43fb0f4b Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 8 Nov 2022 17:14:57 +0100 Subject: [PATCH 11/13] Removing non necessary debug log --- .../UpdateEnableNotificationsSettingOnChangeUseCase.kt | 2 -- 1 file changed, 2 deletions(-) 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 index 55a2cfdc64..36df939bad 100644 --- a/vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.kt +++ b/vector/src/main/java/im/vector/app/core/notification/UpdateEnableNotificationsSettingOnChangeUseCase.kt @@ -22,7 +22,6 @@ import im.vector.app.features.settings.devices.v2.notification.NotificationsStat import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.Session -import timber.log.Timber import javax.inject.Inject /** @@ -42,7 +41,6 @@ class UpdateEnableNotificationsSettingOnChangeUseCase @Inject constructor( } private fun updatePreference(notificationStatus: NotificationsStatus) { - Timber.d("updatePreference with status=$notificationStatus") when (notificationStatus) { NotificationsStatus.ENABLED -> vectorPreferences.setNotificationEnabledForDevice(true) NotificationsStatus.DISABLED -> vectorPreferences.setNotificationEnabledForDevice(false) From ba5a433cafc8b6ed6cdace2a526bead13c08bf34 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Tue, 8 Nov 2022 17:19:06 +0100 Subject: [PATCH 12/13] Adding distinctUntilChanged for flow of remote toggle via Pusher capability --- .../notification/CanTogglePushNotificationsViaPusherUseCase.kt | 2 ++ 1 file changed, 2 insertions(+) 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 index 963768ca04..0125d92ba6 100644 --- 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 @@ -18,6 +18,7 @@ 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 @@ -32,5 +33,6 @@ class CanTogglePushNotificationsViaPusherUseCase @Inject constructor() { .asFlow() .unwrap() .map { it.canRemotelyTogglePushNotificationsOfDevices } + .distinctUntilChanged() } } From 6ec33f1264ecc59b26a8db8844dafacaa9f83a18 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 9 Nov 2022 09:33:39 +0100 Subject: [PATCH 13/13] Removing unused imports --- .../devices/v2/overview/SessionOverviewViewModelTest.kt | 2 -- 1 file changed, 2 deletions(-) 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 86a9969a6a..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 @@ -37,8 +37,6 @@ import io.mockk.coEvery import io.mockk.coVerify import io.mockk.every import io.mockk.just -import io.mockk.justRun -import io.mockk.justRun import io.mockk.mockk import io.mockk.mockkStatic import io.mockk.runs