From 1ede6b32a5c708f5b2636130ce37843fcc311b46 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 12 Oct 2022 13:41:58 +0200 Subject: [PATCH 01/11] Adding changelog entry --- changelog.d/7344.feature | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/7344.feature diff --git a/changelog.d/7344.feature b/changelog.d/7344.feature new file mode 100644 index 0000000000..a6deb4a23a --- /dev/null +++ b/changelog.d/7344.feature @@ -0,0 +1 @@ +[Device management] Add lab flag for matrix client info account data event From 4fced5bd3eaafae1baa8e47c609554307d4b1e3c Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 12 Oct 2022 13:58:20 +0200 Subject: [PATCH 02/11] Adding nex entry in labs settings --- library/ui-strings/src/main/res/values/strings.xml | 2 ++ vector-config/src/main/res/values/config-settings.xml | 1 + .../im/vector/app/features/settings/VectorPreferences.kt | 8 ++++++++ vector/src/main/res/xml/vector_settings_labs.xml | 6 ++++++ 4 files changed, 17 insertions(+) diff --git a/library/ui-strings/src/main/res/values/strings.xml b/library/ui-strings/src/main/res/values/strings.xml index c997fb5639..f21d7c68d3 100644 --- a/library/ui-strings/src/main/res/values/strings.xml +++ b/library/ui-strings/src/main/res/values/strings.xml @@ -3336,6 +3336,8 @@ Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here. Enable new session manager Have greater visibility and control over all your sessions. + Enable client info recording + Record the client name, version, and url to recognise sessions more easily in session manager. %s\nis looking a little empty. diff --git a/vector-config/src/main/res/values/config-settings.xml b/vector-config/src/main/res/values/config-settings.xml index 9c7eee5c0c..ced678fb98 100755 --- a/vector-config/src/main/res/values/config-settings.xml +++ b/vector-config/src/main/res/values/config-settings.xml @@ -42,6 +42,7 @@ false true false + false true false true diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index aaf328e9c7..89fcda142a 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -73,6 +73,7 @@ class VectorPreferences @Inject constructor( const val SETTINGS_LABS_DEFERRED_DM_KEY = "SETTINGS_LABS_DEFERRED_DM_KEY" const val SETTINGS_LABS_RICH_TEXT_EDITOR_KEY = "SETTINGS_LABS_RICH_TEXT_EDITOR_KEY" const val SETTINGS_LABS_NEW_SESSION_MANAGER_KEY = "SETTINGS_LABS_NEW_SESSION_MANAGER_KEY" + const val SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY = "SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY" const val SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY" const val SETTINGS_CRYPTOGRAPHY_DIVIDER_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_DIVIDER_PREFERENCE_KEY" const val SETTINGS_CRYPTOGRAPHY_MANAGE_PREFERENCE_KEY = "SETTINGS_CRYPTOGRAPHY_MANAGE_PREFERENCE_KEY" @@ -1188,6 +1189,13 @@ class VectorPreferences @Inject constructor( return defaultPrefs.getBoolean(SETTINGS_LABS_NEW_SESSION_MANAGER_KEY, getDefault(R.bool.settings_labs_new_session_manager_default)) } + /** + * Indicates whether or not client info recording is enabled. + */ + fun isClientInfoRecordingEnabled(): Boolean { + return defaultPrefs.getBoolean(SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY, getDefault(R.bool.settings_labs_client_info_recording_default)) + } + fun showLiveSenderInfo(): Boolean { return defaultPrefs.getBoolean(SETTINGS_TIMELINE_SHOW_LIVE_SENDER_INFO, getDefault(R.bool.settings_timeline_show_live_sender_info_default)) } diff --git a/vector/src/main/res/xml/vector_settings_labs.xml b/vector/src/main/res/xml/vector_settings_labs.xml index 51c78d278a..ea4d39aa47 100644 --- a/vector/src/main/res/xml/vector_settings_labs.xml +++ b/vector/src/main/res/xml/vector_settings_labs.xml @@ -109,4 +109,10 @@ android:summary="@string/labs_enable_session_manager_summary" android:title="@string/labs_enable_session_manager_title" /> + + From 89e14c915d30b4aec58e7019860b6f83a334db1e Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 12 Oct 2022 14:23:23 +0200 Subject: [PATCH 03/11] Moving labs fragment into dedicated package --- .../settings/{ => labs}/VectorSettingsLabsFragment.kt | 6 ++++-- vector/src/main/res/xml/vector_settings_root.xml | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) rename vector/src/main/java/im/vector/app/features/settings/{ => labs}/VectorSettingsLabsFragment.kt (96%) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsLabsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt similarity index 96% rename from vector/src/main/java/im/vector/app/features/settings/VectorSettingsLabsFragment.kt rename to vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt index 18bc35f72a..541811a650 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsLabsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt @@ -1,5 +1,5 @@ /* - * Copyright 2019 New Vector Ltd + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -package im.vector.app.features.settings +package im.vector.app.features.settings.labs import android.os.Bundle import android.text.method.LinkMovementMethod @@ -30,6 +30,8 @@ import im.vector.app.features.MainActivityArgs import im.vector.app.features.VectorFeatures import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.home.room.threads.ThreadsManager +import im.vector.app.features.settings.VectorPreferences +import im.vector.app.features.settings.VectorSettingsBaseFragment import org.matrix.android.sdk.api.settings.LightweightSettingsStorage import javax.inject.Inject diff --git a/vector/src/main/res/xml/vector_settings_root.xml b/vector/src/main/res/xml/vector_settings_root.xml index 02dc36bf39..ffa8688cbd 100644 --- a/vector/src/main/res/xml/vector_settings_root.xml +++ b/vector/src/main/res/xml/vector_settings_root.xml @@ -35,7 +35,7 @@ Date: Wed, 12 Oct 2022 15:38:36 +0200 Subject: [PATCH 04/11] Deleting/Updating the client Info when changing the lab flag --- .../app/core/di/MavericksViewModelModule.kt | 6 ++ .../DeleteMatrixClientInfoUseCase.kt | 42 ++++++++++++ .../settings/labs/VectorSettingsLabsAction.kt | 24 +++++++ .../labs/VectorSettingsLabsFragment.kt | 17 +++++ .../labs/VectorSettingsLabsViewModel.kt | 68 +++++++++++++++++++ .../labs/VectorSettingsLabsViewState.kt | 21 ++++++ 6 files changed, 178 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCase.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsAction.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModel.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewState.kt diff --git a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt index 38b62e1511..d2afdb65e8 100644 --- a/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/MavericksViewModelModule.kt @@ -100,6 +100,7 @@ import im.vector.app.features.settings.devtools.KeyRequestViewModel import im.vector.app.features.settings.font.FontScaleSettingViewModel import im.vector.app.features.settings.homeserver.HomeserverSettingsViewModel import im.vector.app.features.settings.ignored.IgnoredUsersViewModel +import im.vector.app.features.settings.labs.VectorSettingsLabsViewModel import im.vector.app.features.settings.legals.LegalsViewModel import im.vector.app.features.settings.locale.LocalePickerViewModel import im.vector.app.features.settings.push.PushGatewaysViewModel @@ -665,4 +666,9 @@ interface MavericksViewModelModule { @IntoMap @MavericksViewModelKey(SessionLearnMoreViewModel::class) fun sessionLearnMoreViewModelFactory(factory: SessionLearnMoreViewModel.Factory): MavericksAssistedViewModelFactory<*, *> + + @Binds + @IntoMap + @MavericksViewModelKey(VectorSettingsLabsViewModel::class) + fun vectorSettingsLabsViewModelFactory(factory: VectorSettingsLabsViewModel.Factory): MavericksAssistedViewModelFactory<*, *> } diff --git a/vector/src/main/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCase.kt b/vector/src/main/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCase.kt new file mode 100644 index 0000000000..3957c81997 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCase.kt @@ -0,0 +1,42 @@ +/* + * 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.session.clientinfo + +import im.vector.app.core.di.ActiveSessionHolder +import timber.log.Timber +import javax.inject.Inject + +/** + * This use case delete the account data event containing extended client info. + */ +class DeleteMatrixClientInfoUseCase @Inject constructor( + private val activeSessionHolder: ActiveSessionHolder, + private val setMatrixClientInfoUseCase: SetMatrixClientInfoUseCase, +) { + + // TODO add unit tests + suspend fun execute(): Result = runCatching { + Timber.d("deleting recorded client info") + val session = activeSessionHolder.getActiveSession() + val emptyClientInfo = MatrixClientInfoContent( + name = "", + version = "", + url = "", + ) + setMatrixClientInfoUseCase.execute(session, emptyClientInfo) + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsAction.kt b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsAction.kt new file mode 100644 index 0000000000..db48c3400b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsAction.kt @@ -0,0 +1,24 @@ +/* + * 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.labs + +import im.vector.app.core.platform.VectorViewModelAction + +sealed class VectorSettingsLabsAction : VectorViewModelAction { + object UpdateClientInfo : VectorSettingsLabsAction() + object DeleteRecordedClientInfo : VectorSettingsLabsAction() +} diff --git a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt index 541811a650..5840093bee 100644 --- a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt @@ -20,7 +20,9 @@ import android.os.Bundle import android.text.method.LinkMovementMethod import android.widget.TextView import androidx.preference.Preference +import androidx.preference.Preference.OnPreferenceChangeListener import androidx.preference.SwitchPreference +import com.airbnb.mvrx.fragmentViewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R @@ -39,6 +41,8 @@ import javax.inject.Inject class VectorSettingsLabsFragment : VectorSettingsBaseFragment() { + private val viewModel: VectorSettingsLabsViewModel by fragmentViewModel() + @Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var lightweightSettingsStorage: LightweightSettingsStorage @Inject lateinit var threadsManager: ThreadsManager @@ -87,6 +91,7 @@ class VectorSettingsLabsFragment : } configureUnreadNotificationsAsTabPreference() + configureEnableClientInfoRecordingPreference() } private fun configureUnreadNotificationsAsTabPreference() { @@ -142,4 +147,16 @@ class VectorSettingsLabsFragment : private fun onNewLayoutPreferenceClicked() { configureUnreadNotificationsAsTabPreference() } + + private fun configureEnableClientInfoRecordingPreference() { + findPreference(VectorPreferences.SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY)?.onPreferenceChangeListener = + OnPreferenceChangeListener { _, newValue -> + when { + (newValue as? Boolean) == false -> viewModel.handle(VectorSettingsLabsAction.DeleteRecordedClientInfo) + (newValue as? Boolean) == true -> viewModel.handle(VectorSettingsLabsAction.UpdateClientInfo) + else -> Unit + } + true + } + } } diff --git a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModel.kt new file mode 100644 index 0000000000..2f4cc0562b --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModel.kt @@ -0,0 +1,68 @@ +/* + * 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.labs + +import com.airbnb.mvrx.MavericksViewModelFactory +import dagger.assisted.Assisted +import dagger.assisted.AssistedFactory +import dagger.assisted.AssistedInject +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.di.MavericksAssistedViewModelFactory +import im.vector.app.core.di.hiltMavericksViewModelFactory +import im.vector.app.core.platform.EmptyViewEvents +import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.session.clientinfo.DeleteMatrixClientInfoUseCase +import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase +import kotlinx.coroutines.launch + +class VectorSettingsLabsViewModel @AssistedInject constructor( + @Assisted initialState: VectorSettingsLabsViewState, + private val activeSessionHolder: ActiveSessionHolder, + private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase, + private val deleteMatrixClientInfoUseCase: DeleteMatrixClientInfoUseCase, +) : VectorViewModel(initialState) { + + @AssistedFactory + interface Factory : MavericksAssistedViewModelFactory { + override fun create(initialState: VectorSettingsLabsViewState): VectorSettingsLabsViewModel + } + + companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() + + // TODO add unit tests + override fun handle(action: VectorSettingsLabsAction) { + when (action) { + VectorSettingsLabsAction.UpdateClientInfo -> handleUpdateClientInfo() + VectorSettingsLabsAction.DeleteRecordedClientInfo -> handleDeleteRecordedClientInfo() + } + } + + private fun handleUpdateClientInfo() { + viewModelScope.launch { + activeSessionHolder.getSafeActiveSession() + ?.let { session -> + updateMatrixClientInfoUseCase.execute(session) + } + } + } + + private fun handleDeleteRecordedClientInfo() { + viewModelScope.launch { + deleteMatrixClientInfoUseCase.execute() + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewState.kt b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewState.kt new file mode 100644 index 0000000000..c246d30994 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewState.kt @@ -0,0 +1,21 @@ +/* + * 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.labs + +import com.airbnb.mvrx.MavericksState + +class VectorSettingsLabsViewState : MavericksState From 8b30ab69c5aa4a90d14d195c19352881f773e0c6 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 12 Oct 2022 16:00:32 +0200 Subject: [PATCH 05/11] Checking lab flag before updating the client info --- .../ConfigureAndStartSessionUseCase.kt | 6 ++++- .../ConfigureAndStartSessionUseCaseTest.kt | 26 ++++++++++++++++++- .../app/test/fakes/FakeVectorPreferences.kt | 4 +++ 3 files changed, 34 insertions(+), 2 deletions(-) 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 dfcb92af24..a5e1fe68bd 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 @@ -21,6 +21,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext import im.vector.app.core.extensions.startSyncing import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase import im.vector.app.features.call.webrtc.WebRtcCallManager +import im.vector.app.features.settings.VectorPreferences import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.sync.FilterService import timber.log.Timber @@ -30,6 +31,7 @@ class ConfigureAndStartSessionUseCase @Inject constructor( @ApplicationContext private val context: Context, private val webRtcCallManager: WebRtcCallManager, private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase, + private val vectorPreferences: VectorPreferences, ) { suspend fun execute(session: Session, startSyncing: Boolean = true) { @@ -41,6 +43,8 @@ class ConfigureAndStartSessionUseCase @Inject constructor( } session.pushersService().refreshPushers() webRtcCallManager.checkForProtocolsSupportIfNeeded() - updateMatrixClientInfoUseCase.execute(session) + if (vectorPreferences.isClientInfoRecordingEnabled()) { + updateMatrixClientInfoUseCase.execute(session) + } } } 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 b879806930..5e1cba0b24 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 @@ -20,6 +20,7 @@ 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.FakeSession +import im.vector.app.test.fakes.FakeVectorPreferences import im.vector.app.test.fakes.FakeWebRtcCallManager import io.mockk.coJustRun import io.mockk.coVerify @@ -41,11 +42,13 @@ class ConfigureAndStartSessionUseCaseTest { private val fakeContext = FakeContext() private val fakeWebRtcCallManager = FakeWebRtcCallManager() private val fakeUpdateMatrixClientInfoUseCase = mockk() + private val fakeVectorPreferences = FakeVectorPreferences() private val configureAndStartSessionUseCase = ConfigureAndStartSessionUseCase( context = fakeContext.instance, webRtcCallManager = fakeWebRtcCallManager.instance, updateMatrixClientInfoUseCase = fakeUpdateMatrixClientInfoUseCase, + vectorPreferences = fakeVectorPreferences.instance, ) @Before @@ -59,11 +62,12 @@ class ConfigureAndStartSessionUseCaseTest { } @Test - fun `given a session and start sync needed when configuring and starting the session then it should be configured properly`() = runTest { + fun `given start sync needed and client info recording enabled when configuring and starting the session then it should be configured properly`() = runTest { // Given val fakeSession = givenASession() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } + fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) // When configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) @@ -76,12 +80,32 @@ class ConfigureAndStartSessionUseCaseTest { coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) } } + @Test + fun `given start sync needed and client info recording disabled when configuring and starting the session then it should be configured properly`() = runTest { + // Given + val fakeSession = givenASession() + fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() + coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } + fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = false) + + // When + configureAndStartSessionUseCase.execute(fakeSession, startSyncing = true) + + // Then + verify { fakeSession.startSyncing(fakeContext.instance) } + fakeSession.fakeFilterService.verifySetFilter(FilterService.FilterPreset.ElementFilter) + fakeSession.fakePushersService.verifyRefreshPushers() + fakeWebRtcCallManager.verifyCheckForProtocolsSupportIfNeeded() + coVerify(inverse = true) { fakeUpdateMatrixClientInfoUseCase.execute(fakeSession) } + } + @Test fun `given a session and no start sync needed when configuring and starting the session then it should be configured properly`() = runTest { // Given val fakeSession = givenASession() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() coJustRun { fakeUpdateMatrixClientInfoUseCase.execute(any()) } + fakeVectorPreferences.givenIsClientInfoRecordingEnabled(isEnabled = true) // When configureAndStartSessionUseCase.execute(fakeSession, startSyncing = false) 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 bc761d9016..8b0630c24f 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 @@ -36,4 +36,8 @@ class FakeVectorPreferences { fun verifySetSpaceBackstack(value: List, inverse: Boolean = false) { verify(inverse = inverse) { instance.setSpaceBackstack(value) } } + + fun givenIsClientInfoRecordingEnabled(isEnabled: Boolean) { + every { instance.isClientInfoRecordingEnabled() } returns isEnabled + } } From 5e87a6936dd83cf42ec57b154fd6ae404ed5761b Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 12 Oct 2022 16:13:04 +0200 Subject: [PATCH 06/11] Adding unit tests for new view model --- .../labs/VectorSettingsLabsViewModel.kt | 1 - .../labs/VectorSettingsLabsViewModelTest.kt | 86 +++++++++++++++++++ 2 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 vector/src/test/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModelTest.kt diff --git a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModel.kt b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModel.kt index 2f4cc0562b..38686b06be 100644 --- a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModel.kt @@ -43,7 +43,6 @@ class VectorSettingsLabsViewModel @AssistedInject constructor( companion object : MavericksViewModelFactory by hiltMavericksViewModelFactory() - // TODO add unit tests override fun handle(action: VectorSettingsLabsAction) { when (action) { VectorSettingsLabsAction.UpdateClientInfo -> handleUpdateClientInfo() diff --git a/vector/src/test/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModelTest.kt b/vector/src/test/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModelTest.kt new file mode 100644 index 0000000000..b3a4648263 --- /dev/null +++ b/vector/src/test/java/im/vector/app/features/settings/labs/VectorSettingsLabsViewModelTest.kt @@ -0,0 +1,86 @@ +/* + * 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.labs + +import com.airbnb.mvrx.test.MavericksTestRule +import im.vector.app.core.session.clientinfo.DeleteMatrixClientInfoUseCase +import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase +import im.vector.app.test.fakes.FakeActiveSessionHolder +import im.vector.app.test.test +import im.vector.app.test.testDispatcher +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import org.junit.Rule +import org.junit.Test + +class VectorSettingsLabsViewModelTest { + + @get:Rule + val mavericksTestRule = MavericksTestRule(testDispatcher = testDispatcher) + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeUpdateMatrixClientInfoUseCase = mockk() + private val fakeDeleteMatrixClientInfoUseCase = mockk() + + private fun createViewModel(): VectorSettingsLabsViewModel { + return VectorSettingsLabsViewModel( + initialState = VectorSettingsLabsViewState(), + activeSessionHolder = fakeActiveSessionHolder.instance, + updateMatrixClientInfoUseCase = fakeUpdateMatrixClientInfoUseCase, + deleteMatrixClientInfoUseCase = fakeDeleteMatrixClientInfoUseCase, + ) + } + + @Test + fun `given update client info action when handling this action then update client info use case is called`() { + // Given + givenUpdateClientInfoSucceeds() + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(VectorSettingsLabsAction.UpdateClientInfo) + + // Then + viewModelTest.finish() + coVerify { fakeUpdateMatrixClientInfoUseCase.execute(fakeActiveSessionHolder.fakeSession) } + } + + @Test + fun `given delete client info action when handling this action then delete client info use case is called`() { + // Given + givenDeleteClientInfoSucceeds() + + // When + val viewModel = createViewModel() + val viewModelTest = viewModel.test() + viewModel.handle(VectorSettingsLabsAction.DeleteRecordedClientInfo) + + // Then + viewModelTest.finish() + coVerify { fakeDeleteMatrixClientInfoUseCase.execute() } + } + + private fun givenUpdateClientInfoSucceeds() { + coEvery { fakeUpdateMatrixClientInfoUseCase.execute(any()) } returns Result.success(Unit) + } + + private fun givenDeleteClientInfoSucceeds() { + coEvery { fakeDeleteMatrixClientInfoUseCase.execute() } returns Result.success(Unit) + } +} From 0c7f04c4a1cf971b1abe6c53caeea3920ab2409c Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Wed, 12 Oct 2022 17:23:30 +0200 Subject: [PATCH 07/11] Adding unit tests for DeleteMatrixClientInfoUseCase --- .../DeleteMatrixClientInfoUseCase.kt | 3 +- .../DeleteMatrixClientInfoUseCaseTest.kt | 82 +++++++++++++++++++ 2 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 vector/src/test/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCaseTest.kt diff --git a/vector/src/main/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCase.kt b/vector/src/main/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCase.kt index 3957c81997..bab3af9af5 100644 --- a/vector/src/main/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCase.kt +++ b/vector/src/main/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCase.kt @@ -28,7 +28,6 @@ class DeleteMatrixClientInfoUseCase @Inject constructor( private val setMatrixClientInfoUseCase: SetMatrixClientInfoUseCase, ) { - // TODO add unit tests suspend fun execute(): Result = runCatching { Timber.d("deleting recorded client info") val session = activeSessionHolder.getActiveSession() @@ -37,6 +36,6 @@ class DeleteMatrixClientInfoUseCase @Inject constructor( version = "", url = "", ) - setMatrixClientInfoUseCase.execute(session, emptyClientInfo) + return setMatrixClientInfoUseCase.execute(session, emptyClientInfo) } } diff --git a/vector/src/test/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCaseTest.kt b/vector/src/test/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCaseTest.kt new file mode 100644 index 0000000000..c89bd73979 --- /dev/null +++ b/vector/src/test/java/im/vector/app/core/session/clientinfo/DeleteMatrixClientInfoUseCaseTest.kt @@ -0,0 +1,82 @@ +/* + * 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.session.clientinfo + +import im.vector.app.test.fakes.FakeActiveSessionHolder +import io.mockk.coEvery +import io.mockk.coVerify +import io.mockk.mockk +import kotlinx.coroutines.test.runTest +import org.amshove.kluent.shouldBe +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Test + +class DeleteMatrixClientInfoUseCaseTest { + + private val fakeActiveSessionHolder = FakeActiveSessionHolder() + private val fakeSetMatrixClientInfoUseCase = mockk() + + private val deleteMatrixClientInfoUseCase = DeleteMatrixClientInfoUseCase( + activeSessionHolder = fakeActiveSessionHolder.instance, + setMatrixClientInfoUseCase = fakeSetMatrixClientInfoUseCase + ) + + @Test + fun `given current session when calling use case then empty client info is set and result is success`() = runTest { + // Given + givenSetMatrixClientInfoSucceeds() + val expectedClientInfoToBeSet = MatrixClientInfoContent( + name = "", + version = "", + url = "", + ) + + // When + val result = deleteMatrixClientInfoUseCase.execute() + + // Then + result.isSuccess shouldBe true + coVerify { + fakeSetMatrixClientInfoUseCase.execute( + fakeActiveSessionHolder.fakeSession, + expectedClientInfoToBeSet + ) + } + } + + @Test + fun `given current session and error during the process when calling use case then result is failure`() = runTest { + // Given + val error = Exception() + givenSetMatrixClientInfoFails(error) + + // When + val result = deleteMatrixClientInfoUseCase.execute() + + // Then + result.isFailure shouldBe true + result.exceptionOrNull() shouldBeEqualTo error + } + + private fun givenSetMatrixClientInfoSucceeds() { + coEvery { fakeSetMatrixClientInfoUseCase.execute(any(), any()) } returns Result.success(Unit) + } + + private fun givenSetMatrixClientInfoFails(error: Exception) { + coEvery { fakeSetMatrixClientInfoUseCase.execute(any(), any()) } returns Result.failure(error) + } +} From b201ef8fbb9d2523aa10080b675c1c3bc0e7f4d8 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 13 Oct 2022 09:46:35 +0200 Subject: [PATCH 08/11] Fix code styling issues --- .../app/core/session/ConfigureAndStartSessionUseCaseTest.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 5e1cba0b24..8d4507e85d 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 @@ -62,7 +62,7 @@ class ConfigureAndStartSessionUseCaseTest { } @Test - fun `given start sync needed and client info recording enabled when configuring and starting the session then it should be configured properly`() = runTest { + fun `given start sync needed and client info recording enabled when execute then it should be configured properly`() = runTest { // Given val fakeSession = givenASession() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() @@ -81,7 +81,7 @@ class ConfigureAndStartSessionUseCaseTest { } @Test - fun `given start sync needed and client info recording disabled when configuring and starting the session then it should be configured properly`() = runTest { + fun `given start sync needed and client info recording disabled when execute then it should be configured properly`() = runTest { // Given val fakeSession = givenASession() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() @@ -100,7 +100,7 @@ class ConfigureAndStartSessionUseCaseTest { } @Test - fun `given a session and no start sync needed when configuring and starting the session then it should be configured properly`() = runTest { + fun `given a session and no start sync needed when execute then it should be configured properly`() = runTest { // Given val fakeSession = givenASession() fakeWebRtcCallManager.givenCheckForProtocolsSupportIfNeededSucceeds() From 1b41b8b538eed2a54a45cc31e6d4337a98168952 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Thu, 13 Oct 2022 09:56:37 +0200 Subject: [PATCH 09/11] Revert change of year for the Labs fragment --- .../app/features/settings/labs/VectorSettingsLabsFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt index 5840093bee..37998fa2a0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 New Vector Ltd + * Copyright (c) 2019 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. From 86132219d81f32f9329d2e1070455660a9878cc1 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 14 Oct 2022 13:45:23 +0200 Subject: [PATCH 10/11] Adding settings for visibility of labs flags --- vector-config/src/main/res/values/config-settings.xml | 2 ++ vector/src/main/res/xml/vector_settings_labs.xml | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/vector-config/src/main/res/values/config-settings.xml b/vector-config/src/main/res/values/config-settings.xml index ced678fb98..7b7aac8156 100755 --- a/vector-config/src/main/res/values/config-settings.xml +++ b/vector-config/src/main/res/values/config-settings.xml @@ -42,7 +42,9 @@ false true false + true false + true true false true diff --git a/vector/src/main/res/xml/vector_settings_labs.xml b/vector/src/main/res/xml/vector_settings_labs.xml index ea4d39aa47..5b519bdd91 100644 --- a/vector/src/main/res/xml/vector_settings_labs.xml +++ b/vector/src/main/res/xml/vector_settings_labs.xml @@ -107,12 +107,14 @@ android:defaultValue="@bool/settings_labs_new_session_manager_default" android:key="SETTINGS_LABS_NEW_SESSION_MANAGER_KEY" android:summary="@string/labs_enable_session_manager_summary" - android:title="@string/labs_enable_session_manager_title" /> + android:title="@string/labs_enable_session_manager_title" + app:isPreferenceVisible="@bool/settings_labs_new_session_manager_visible" /> + android:title="@string/labs_enable_client_info_recording_title" + app:isPreferenceVisible="@bool/settings_labs_client_info_recording_visible" /> From 189e77211e14b4e1e1eca8ae0dcce4753fe92ae7 Mon Sep 17 00:00:00 2001 From: Maxime NATUREL Date: Fri, 14 Oct 2022 13:46:33 +0200 Subject: [PATCH 11/11] Improving when structure --- .../features/settings/labs/VectorSettingsLabsFragment.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt index 37998fa2a0..6c31e32567 100644 --- a/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/labs/VectorSettingsLabsFragment.kt @@ -151,9 +151,9 @@ class VectorSettingsLabsFragment : private fun configureEnableClientInfoRecordingPreference() { findPreference(VectorPreferences.SETTINGS_LABS_CLIENT_INFO_RECORDING_KEY)?.onPreferenceChangeListener = OnPreferenceChangeListener { _, newValue -> - when { - (newValue as? Boolean) == false -> viewModel.handle(VectorSettingsLabsAction.DeleteRecordedClientInfo) - (newValue as? Boolean) == true -> viewModel.handle(VectorSettingsLabsAction.UpdateClientInfo) + when (newValue as? Boolean) { + false -> viewModel.handle(VectorSettingsLabsAction.DeleteRecordedClientInfo) + true -> viewModel.handle(VectorSettingsLabsAction.UpdateClientInfo) else -> Unit } true