From e416f1024ad2c6719e31206c659624028009a01d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 10:46:59 +0100 Subject: [PATCH 01/25] Reformat code using AS --- .../app/features/analytics/plan/CallEnded.kt | 32 +++++++++---------- .../app/features/analytics/plan/CallError.kt | 24 +++++++------- .../features/analytics/plan/CallStarted.kt | 24 +++++++------- .../app/features/analytics/plan/Click.kt | 16 +++++----- .../features/analytics/plan/CreatedRoom.kt | 8 ++--- .../app/features/analytics/plan/Error.kt | 12 +++---- .../app/features/analytics/plan/JoinedRoom.kt | 16 +++++----- .../analytics/plan/PerformanceTimer.kt | 32 +++++++++---------- .../app/features/analytics/plan/Screen.kt | 10 +++--- 9 files changed, 87 insertions(+), 87 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/CallEnded.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/CallEnded.kt index cd813325f1d..3bf16a6c97d 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/CallEnded.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/CallEnded.kt @@ -25,22 +25,22 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent * Triggered when a call has ended. */ data class CallEnded( - /** - * The duration of the call in milliseconds. - */ - val durationMs: Int, - /** - * Whether its a video call or not. - */ - val isVideo: Boolean, - /** - * Number of participants in the call. - */ - val numParticipants: Int, - /** - * Whether this user placed it. - */ - val placed: Boolean, + /** + * The duration of the call in milliseconds. + */ + val durationMs: Int, + /** + * Whether its a video call or not. + */ + val isVideo: Boolean, + /** + * Number of participants in the call. + */ + val numParticipants: Int, + /** + * Whether this user placed it. + */ + val placed: Boolean, ) : VectorAnalyticsEvent { override fun getName() = "CallEnded" diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/CallError.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/CallError.kt index 18e77f9f1c3..1c3a57e971f 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/CallError.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/CallError.kt @@ -25,18 +25,18 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent * Triggered when an error occurred in a call. */ data class CallError( - /** - * Whether its a video call or not. - */ - val isVideo: Boolean, - /** - * Number of participants in the call. - */ - val numParticipants: Int, - /** - * Whether this user placed it. - */ - val placed: Boolean, + /** + * Whether its a video call or not. + */ + val isVideo: Boolean, + /** + * Number of participants in the call. + */ + val numParticipants: Int, + /** + * Whether this user placed it. + */ + val placed: Boolean, ) : VectorAnalyticsEvent { override fun getName() = "CallError" diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/CallStarted.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/CallStarted.kt index 81f4b6c194b..e74d07d38c6 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/CallStarted.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/CallStarted.kt @@ -25,18 +25,18 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent * Triggered when a call is started. */ data class CallStarted( - /** - * Whether its a video call or not. - */ - val isVideo: Boolean, - /** - * Number of participants in the call. - */ - val numParticipants: Int, - /** - * Whether this user placed it. - */ - val placed: Boolean, + /** + * Whether its a video call or not. + */ + val isVideo: Boolean, + /** + * Number of participants in the call. + */ + val numParticipants: Int, + /** + * Whether this user placed it. + */ + val placed: Boolean, ) : VectorAnalyticsEvent { override fun getName() = "CallStarted" diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Click.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Click.kt index fbc36a11955..fbc847165da 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Click.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Click.kt @@ -25,14 +25,14 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent * Triggered when the user clicks/taps on a UI element. */ data class Click( - /** - * The index of the element, if its in a list of elements. - */ - val index: Int? = null, - /** - * The unique name of this element. - */ - val name: Name, + /** + * The index of the element, if its in a list of elements. + */ + val index: Int? = null, + /** + * The unique name of this element. + */ + val name: Name, ) : VectorAnalyticsEvent { enum class Name { diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/CreatedRoom.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/CreatedRoom.kt index 9562a6e735c..598cc6ac280 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/CreatedRoom.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/CreatedRoom.kt @@ -25,10 +25,10 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent * Triggered when the user creates a room. */ data class CreatedRoom( - /** - * Whether the room is a DM. - */ - val isDM: Boolean, + /** + * Whether the room is a DM. + */ + val isDM: Boolean, ) : VectorAnalyticsEvent { override fun getName() = "CreatedRoom" diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Error.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Error.kt index 988ad309b9a..a9267766805 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Error.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Error.kt @@ -25,12 +25,12 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent * Triggered when an error occurred */ data class Error( - /** - * Context - client defined, can be used for debugging - */ - val context: String? = null, - val domain: Domain, - val name: Name, + /** + * Context - client defined, can be used for debugging + */ + val context: String? = null, + val domain: Domain, + val name: Name, ) : VectorAnalyticsEvent { enum class Domain { diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/JoinedRoom.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/JoinedRoom.kt index fc5f29bff18..97ac19ec936 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/JoinedRoom.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/JoinedRoom.kt @@ -25,14 +25,14 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent * Triggered when the user joins a room. */ data class JoinedRoom( - /** - * Whether the room is a DM. - */ - val isDM: Boolean, - /** - * The size of the room. - */ - val roomSize: RoomSize, + /** + * Whether the room is a DM. + */ + val isDM: Boolean, + /** + * The size of the room. + */ + val roomSize: RoomSize, ) : VectorAnalyticsEvent { enum class RoomSize { diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt index 34d0297f2d9..8c25534ece9 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt @@ -25,22 +25,22 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent * Triggered after timing an operation in the app. */ data class PerformanceTimer( - /** - * Client defined, can be used for debugging. - */ - val context: String? = null, - /** - * Client defined, an optional value to indicate how many items were handled during the operation. - */ - val itemCount: Int? = null, - /** - * The timer that is being reported. - */ - val name: Name, - /** - * The time reported by the timer in milliseconds. - */ - val timeMs: Int, + /** + * Client defined, can be used for debugging. + */ + val context: String? = null, + /** + * Client defined, an optional value to indicate how many items were handled during the operation. + */ + val itemCount: Int? = null, + /** + * The timer that is being reported. + */ + val name: Name, + /** + * The time reported by the timer in milliseconds. + */ + val timeMs: Int, ) : VectorAnalyticsEvent { enum class Name { diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt index 1f18ceee004..9b578d8c825 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt @@ -25,11 +25,11 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsScreen * Triggered when the user changed screen */ data class Screen( - /** - * How long the screen was displayed for in milliseconds. - */ - val durationMs: Int? = null, - val screenName: ScreenName, + /** + * How long the screen was displayed for in milliseconds. + */ + val durationMs: Int? = null, + val screenName: ScreenName, ) : VectorAnalyticsScreen { enum class ScreenName { From e487621075947ce19a3d4303e023b4a16b2b63a5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 14:00:49 +0100 Subject: [PATCH 02/25] Analytics: create AnalyticsTracker interface --- .../im/vector/app/core/di/SingletonModule.kt | 4 +++ .../features/analytics/AnalyticsTracker.kt | 32 +++++++++++++++++++ .../app/features/analytics/VectorAnalytics.kt | 14 +------- 3 files changed, 37 insertions(+), 13 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/analytics/AnalyticsTracker.kt diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt index d83bb5cb574..0e19cd43881 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonModule.kt @@ -33,6 +33,7 @@ import im.vector.app.core.error.DefaultErrorFormatter import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.time.Clock import im.vector.app.core.time.DefaultClock +import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.VectorAnalytics import im.vector.app.features.analytics.impl.DefaultVectorAnalytics import im.vector.app.features.invite.AutoAcceptInvites @@ -64,6 +65,9 @@ abstract class VectorBindModule { @Binds abstract fun bindVectorAnalytics(analytics: DefaultVectorAnalytics): VectorAnalytics + @Binds + abstract fun bindAnalyticsTracker(analytics: DefaultVectorAnalytics): AnalyticsTracker + @Binds abstract fun bindErrorFormatter(formatter: DefaultErrorFormatter): ErrorFormatter diff --git a/vector/src/main/java/im/vector/app/features/analytics/AnalyticsTracker.kt b/vector/src/main/java/im/vector/app/features/analytics/AnalyticsTracker.kt new file mode 100644 index 00000000000..e1da0f44344 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/AnalyticsTracker.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 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.analytics + +import im.vector.app.features.analytics.itf.VectorAnalyticsEvent +import im.vector.app.features.analytics.itf.VectorAnalyticsScreen + +interface AnalyticsTracker { + /** + * Capture an Event + */ + fun capture(event: VectorAnalyticsEvent) + + /** + * Track a displayed screen + */ + fun screen(screen: VectorAnalyticsScreen) +} diff --git a/vector/src/main/java/im/vector/app/features/analytics/VectorAnalytics.kt b/vector/src/main/java/im/vector/app/features/analytics/VectorAnalytics.kt index 476f5ade564..95322412bda 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/VectorAnalytics.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/VectorAnalytics.kt @@ -16,11 +16,9 @@ package im.vector.app.features.analytics -import im.vector.app.features.analytics.itf.VectorAnalyticsEvent -import im.vector.app.features.analytics.itf.VectorAnalyticsScreen import kotlinx.coroutines.flow.Flow -interface VectorAnalytics { +interface VectorAnalytics : AnalyticsTracker { /** * Return a Flow of Boolean, true if the user has given their consent */ @@ -60,14 +58,4 @@ interface VectorAnalytics { * To be called when application is started */ fun init() - - /** - * Capture an Event - */ - fun capture(event: VectorAnalyticsEvent) - - /** - * Track a displayed screen - */ - fun screen(screen: VectorAnalyticsScreen) } From 7a6f3cbcf768a7e8c39713cda2ec06db6e08b079 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 14:01:15 +0100 Subject: [PATCH 03/25] Analytics: Send the Event `Click(name = Click.Name.SendMessageButton)` (#4717) --- .../app/features/home/room/detail/RoomDetailFragment.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index deaa56776e9..6838d83182c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -116,6 +116,8 @@ import im.vector.app.core.utils.startInstallFromSourceIntent import im.vector.app.core.utils.toast import im.vector.app.databinding.DialogReportContentBinding import im.vector.app.databinding.FragmentRoomDetailBinding +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.Click import im.vector.app.features.attachments.AttachmentTypeSelectorView import im.vector.app.features.attachments.AttachmentsHelper import im.vector.app.features.attachments.ContactAttachment @@ -257,6 +259,7 @@ class RoomDetailFragment @Inject constructor( private val roomDetailPendingActionStore: RoomDetailPendingActionStore, private val pillsPostProcessorFactory: PillsPostProcessor.Factory, private val callManager: WebRtcCallManager, + private val analyticsTracker: AnalyticsTracker, private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker, private val clock: Clock ) : @@ -1395,6 +1398,7 @@ class RoomDetailFragment @Inject constructor( return } if (text.isNotBlank()) { + analyticsTracker.capture(Click(name = Click.Name.SendMessageButton)) // We collapse ASAP, if not there will be a slight annoying delay views.composerLayout.collapse(true) lockSendButton = true From 3e125bcccfa6e26439a42eebab3e006eb144f285 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 14:09:42 +0100 Subject: [PATCH 04/25] Analytics: Send the Event `CreatedRoom()` (#4716) --- .../createroom/CreateRoomViewModel.kt | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt index 698d3153375..3b2e9de2d1f 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomViewModel.kt @@ -30,6 +30,8 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.CreatedRoom import im.vector.app.features.raw.wellknown.getElementWellknown import im.vector.app.features.raw.wellknown.isE2EByDefault import kotlinx.coroutines.Dispatchers @@ -52,10 +54,12 @@ import org.matrix.android.sdk.api.session.room.model.create.CreateRoomPreset import org.matrix.android.sdk.api.session.room.model.create.RestrictedRoomPreset import timber.log.Timber -class CreateRoomViewModel @AssistedInject constructor(@Assisted private val initialState: CreateRoomViewState, - private val session: Session, - private val rawService: RawService, - appStateHandler: AppStateHandler +class CreateRoomViewModel @AssistedInject constructor( + @Assisted private val initialState: CreateRoomViewState, + private val session: Session, + private val rawService: RawService, + appStateHandler: AppStateHandler, + private val analyticsTracker: AnalyticsTracker ) : VectorViewModel(initialState) { @AssistedFactory @@ -296,7 +300,7 @@ class CreateRoomViewModel @AssistedInject constructor(@Assisted private val init viewModelScope.launch { runCatching { session.createRoom(createRoomParams) }.fold( { roomId -> - + analyticsTracker.capture(CreatedRoom(isDM = createRoomParams.isDirect.orFalse())) if (state.parentSpaceId != null) { // add it as a child try { From 11f176e0798c96633400b9433542c8fcc269c52f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 14:13:42 +0100 Subject: [PATCH 05/25] Analytics: Create extension to compute JoinedRoom.RoomSize (#4716) --- .../extensions/AnalyticsExtensions.kt | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt diff --git a/vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt b/vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt new file mode 100644 index 00000000000..5cf53afa08c --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2021 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.analytics.extensions + +import im.vector.app.features.analytics.plan.JoinedRoom + +fun Int.toAnalyticsRoomSize(): JoinedRoom.RoomSize { + return when (this) { + 2 -> JoinedRoom.RoomSize.Two + in 3..10 -> JoinedRoom.RoomSize.ThreeToTen + in 11..100 -> JoinedRoom.RoomSize.ElevenToOneHundred + in 101..1000 -> JoinedRoom.RoomSize.OneHundredAndOneToAThousand + else -> JoinedRoom.RoomSize.MoreThanAThousand + } +} From 55a6257cee4edb6596e334ba08c19616fafa6424 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 15:15:38 +0100 Subject: [PATCH 06/25] Analytics: Send JoinedRoom event (#4716) --- .../extensions/AnalyticsExtensions.kt | 20 ++++++++++++++++++- .../home/room/detail/RoomDetailViewModel.kt | 8 +++++++- .../composer/MessageComposerViewModel.kt | 4 ++++ .../home/room/list/RoomListViewModel.kt | 6 +++++- .../NotificationBroadcastReceiver.kt | 8 +++++++- .../roomdirectory/PublicRoomsFragment.kt | 2 +- .../roomdirectory/RoomDirectoryAction.kt | 3 ++- .../roomdirectory/RoomDirectoryViewModel.kt | 8 ++++++-- 8 files changed, 51 insertions(+), 8 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt b/vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt index 5cf53afa08c..ff23fd9a64a 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt @@ -17,9 +17,13 @@ package im.vector.app.features.analytics.extensions import im.vector.app.features.analytics.plan.JoinedRoom +import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.session.room.model.RoomSummary +import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom -fun Int.toAnalyticsRoomSize(): JoinedRoom.RoomSize { +fun Int?.toAnalyticsRoomSize(): JoinedRoom.RoomSize { return when (this) { + null, 2 -> JoinedRoom.RoomSize.Two in 3..10 -> JoinedRoom.RoomSize.ThreeToTen in 11..100 -> JoinedRoom.RoomSize.ElevenToOneHundred @@ -27,3 +31,17 @@ fun Int.toAnalyticsRoomSize(): JoinedRoom.RoomSize { else -> JoinedRoom.RoomSize.MoreThanAThousand } } + +fun RoomSummary?.toAnalyticsJoinedRoom(): JoinedRoom { + return JoinedRoom( + isDM = this?.isDirect.orFalse(), + roomSize = this?.joinedMembersCount?.toAnalyticsRoomSize() ?: JoinedRoom.RoomSize.Two + ) +} + +fun PublicRoom.toAnalyticsJoinedRoom(): JoinedRoom { + return JoinedRoom( + isDM = false, + roomSize = numJoinedMembers.toAnalyticsRoomSize() + ) +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt index c1ff67d5d99..adb211ec835 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailViewModel.kt @@ -37,7 +37,9 @@ import im.vector.app.core.mvrx.runCatchingToAsync import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider import im.vector.app.core.utils.BehaviorDataSource +import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.DecryptionFailureTracker +import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom import im.vector.app.features.call.conference.ConferenceEvent import im.vector.app.features.call.conference.JitsiActiveConferenceHolder import im.vector.app.features.call.conference.JitsiService @@ -112,6 +114,7 @@ class RoomDetailViewModel @AssistedInject constructor( private val chatEffectManager: ChatEffectManager, private val directRoomHelper: DirectRoomHelper, private val jitsiService: JitsiService, + private val analyticsTracker: AnalyticsTracker, private val activeConferenceHolder: JitsiActiveConferenceHolder, private val decryptionFailureTracker: DecryptionFailureTracker, timelineFactory: TimelineFactory @@ -709,7 +712,10 @@ class RoomDetailViewModel @AssistedInject constructor( private fun handleAcceptInvite() { viewModelScope.launch { - tryOrNull { room.join() } + tryOrNull { + room.join() + analyticsTracker.capture(room.roomSummary().toAnalyticsJoinedRoom()) + } } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt index 0f3fb973f6e..7137fd3dc68 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/composer/MessageComposerViewModel.kt @@ -26,6 +26,8 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom import im.vector.app.features.attachments.toContentAttachmentData import im.vector.app.features.command.CommandParser import im.vector.app.features.command.ParsedCommand @@ -68,6 +70,7 @@ class MessageComposerViewModel @AssistedInject constructor( private val vectorPreferences: VectorPreferences, private val rainbowGenerator: RainbowGenerator, private val voiceMessageHelper: VoiceMessageHelper, + private val analyticsTracker: AnalyticsTracker, private val voicePlayerHelper: VoicePlayerHelper ) : VectorViewModel(initialState) { @@ -520,6 +523,7 @@ class MessageComposerViewModel @AssistedInject constructor( return@launch } session.getRoomSummary(command.roomAlias) + ?.also { analyticsTracker.capture(it.toAnalyticsJoinedRoom()) } ?.roomId ?.let { _viewEvents.post(MessageComposerViewEvents.JoinRoomCommandSuccess(it)) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index 46a91e2c72f..42c800ab9d2 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -32,6 +32,8 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.VectorViewModel import im.vector.app.core.resources.StringProvider +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom import im.vector.app.features.displayname.getBestName import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.settings.VectorPreferences @@ -56,7 +58,8 @@ class RoomListViewModel @AssistedInject constructor( stringProvider: StringProvider, appStateHandler: AppStateHandler, vectorPreferences: VectorPreferences, - autoAcceptInvites: AutoAcceptInvites + autoAcceptInvites: AutoAcceptInvites, + private val analyticsTracker: AnalyticsTracker ) : VectorViewModel(initialState) { @AssistedFactory @@ -223,6 +226,7 @@ class RoomListViewModel @AssistedInject constructor( viewModelScope.launch { try { room.join() + analyticsTracker.capture(action.roomSummary.toAnalyticsJoinedRoom()) // We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data. // Instead, we wait for the room to be joined } catch (failure: Throwable) { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt index b1905059a1f..ac2ec064745 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationBroadcastReceiver.kt @@ -23,6 +23,8 @@ import androidx.core.app.RemoteInput import dagger.hilt.android.AndroidEntryPoint import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom import im.vector.app.features.session.coroutineScope import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull @@ -41,6 +43,7 @@ class NotificationBroadcastReceiver : BroadcastReceiver() { @Inject lateinit var notificationDrawerManager: NotificationDrawerManager @Inject lateinit var activeSessionHolder: ActiveSessionHolder + @Inject lateinit var analyticsTracker: AnalyticsTracker override fun onReceive(context: Context?, intent: Intent?) { if (intent == null || context == null) return @@ -79,7 +82,10 @@ class NotificationBroadcastReceiver : BroadcastReceiver() { val room = session.getRoom(roomId) if (room != null) { session.coroutineScope.launch { - tryOrNull { room.join() } + tryOrNull { + room.join() + analyticsTracker.capture(room.roomSummary().toAnalyticsJoinedRoom()) + } } } } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt index be1523f4ab4..aa29495b948 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/PublicRoomsFragment.kt @@ -160,7 +160,7 @@ class PublicRoomsFragment @Inject constructor( override fun onPublicRoomJoin(publicRoom: PublicRoom) { Timber.v("PublicRoomJoinClicked: $publicRoom") - viewModel.handle(RoomDirectoryAction.JoinRoom(publicRoom.roomId)) + viewModel.handle(RoomDirectoryAction.JoinRoom(publicRoom)) } override fun loadMore() { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryAction.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryAction.kt index 77eec57ab31..d95a4cf7927 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryAction.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryAction.kt @@ -17,10 +17,11 @@ package im.vector.app.features.roomdirectory import im.vector.app.core.platform.VectorViewModelAction +import org.matrix.android.sdk.api.session.room.model.roomdirectory.PublicRoom sealed class RoomDirectoryAction : VectorViewModelAction { data class SetRoomDirectoryData(val roomDirectoryData: RoomDirectoryData) : RoomDirectoryAction() data class FilterWith(val filter: String) : RoomDirectoryAction() object LoadMore : RoomDirectoryAction() - data class JoinRoom(val roomId: String) : RoomDirectoryAction() + data class JoinRoom(val publicRoom: PublicRoom) : RoomDirectoryAction() } diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt index 431dba21cf5..710d4d5b5f6 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryViewModel.kt @@ -27,6 +27,8 @@ import dagger.assisted.AssistedInject import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.extensions.toAnalyticsJoinedRoom import im.vector.app.features.settings.VectorPreferences import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Job @@ -45,6 +47,7 @@ class RoomDirectoryViewModel @AssistedInject constructor( @Assisted initialState: PublicRoomsViewState, vectorPreferences: VectorPreferences, private val session: Session, + private val analyticsTracker: AnalyticsTracker, private val explicitTermFilter: ExplicitTermFilter ) : VectorViewModel(initialState) { @@ -213,7 +216,7 @@ class RoomDirectoryViewModel @AssistedInject constructor( } private fun joinRoom(action: RoomDirectoryAction.JoinRoom) = withState { state -> - val roomMembershipChange = state.changeMembershipStates[action.roomId] + val roomMembershipChange = state.changeMembershipStates[action.publicRoom.roomId] if (roomMembershipChange?.isInProgress().orFalse()) { // Request already sent, should not happen Timber.w("Try to join an already joining room. Should not happen") @@ -222,7 +225,8 @@ class RoomDirectoryViewModel @AssistedInject constructor( val viaServers = listOfNotNull(state.roomDirectoryData.homeServer) viewModelScope.launch { try { - session.joinRoom(action.roomId, viaServers = viaServers) + session.joinRoom(action.publicRoom.roomId, viaServers = viaServers) + analyticsTracker.capture(action.publicRoom.toAnalyticsJoinedRoom()) // We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data. // Instead, we wait for the room to be joined } catch (failure: Throwable) { From a8c29f55f5a65cbf404dfe710cd9a6a3e976b6da Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 15:25:07 +0100 Subject: [PATCH 07/25] Analytics: Send JoinedRoom event - room preview (#4716) --- .../{AnalyticsExtensions.kt => JoinedRoomExt.kt} | 0 .../roompreview/RoomPreviewActivity.kt | 2 ++ .../roompreview/RoomPreviewViewModel.kt | 16 +++++++++++++--- .../roompreview/RoomPreviewViewState.kt | 4 +++- 4 files changed, 18 insertions(+), 4 deletions(-) rename vector/src/main/java/im/vector/app/features/analytics/extensions/{AnalyticsExtensions.kt => JoinedRoomExt.kt} (100%) diff --git a/vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt b/vector/src/main/java/im/vector/app/features/analytics/extensions/JoinedRoomExt.kt similarity index 100% rename from vector/src/main/java/im/vector/app/features/analytics/extensions/AnalyticsExtensions.kt rename to vector/src/main/java/im/vector/app/features/analytics/extensions/JoinedRoomExt.kt diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt index 394d738b268..a317019d492 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt @@ -40,6 +40,7 @@ data class RoomPreviewData( val roomAlias: String? = null, val roomType: String? = null, val topic: String? = null, + val numJoinedMembers: Int? = null, val worldReadable: Boolean = false, val avatarUrl: String? = null, val homeServers: List = emptyList(), @@ -69,6 +70,7 @@ class RoomPreviewActivity : VectorBaseActivity(), Toolbar roomName = publicRoom.name, roomAlias = publicRoom.getPrimaryAlias(), topic = publicRoom.topic, + numJoinedMembers = publicRoom.numJoinedMembers, worldReadable = publicRoom.worldReadable, avatarUrl = publicRoom.avatarUrl, homeServers = listOfNotNull(roomDirectoryData.homeServer) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt index bdb0a96e9e8..b1fa0e974a3 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewModel.kt @@ -27,6 +27,9 @@ import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.EmptyViewEvents import im.vector.app.core.platform.VectorViewModel +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.extensions.toAnalyticsRoomSize +import im.vector.app.features.analytics.plan.JoinedRoom import im.vector.app.features.roomdirectory.JoinState import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.launchIn @@ -44,9 +47,11 @@ import org.matrix.android.sdk.api.session.room.roomSummaryQueryParams import org.matrix.android.sdk.flow.flow import timber.log.Timber -class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val initialState: RoomPreviewViewState, - private val session: Session) : - VectorViewModel(initialState) { +class RoomPreviewViewModel @AssistedInject constructor( + @Assisted private val initialState: RoomPreviewViewState, + private val analyticsTracker: AnalyticsTracker, + private val session: Session +) : VectorViewModel(initialState) { @AssistedFactory interface Factory : MavericksAssistedViewModelFactory { @@ -243,6 +248,11 @@ class RoomPreviewViewModel @AssistedInject constructor(@Assisted private val ini viewModelScope.launch { try { session.joinRoom(state.roomId, viaServers = state.homeServers) + analyticsTracker.capture(JoinedRoom( + // Always false in this case (?) + isDM = false, + roomSize = state.numJoinMembers.toAnalyticsRoomSize() + )) // We do not update the joiningRoomsIds here, because, the room is not joined yet regarding the sync data. // Instead, we wait for the room to be joined } catch (failure: Throwable) { diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt index 8488dd7267a..b2cb43115db 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewViewState.kt @@ -33,6 +33,7 @@ data class RoomPreviewViewState( val roomName: String? = null, val roomTopic: String? = null, + val numJoinMembers: Int? = null, val avatarUrl: String? = null, val shouldPeekFromServer: Boolean = false, @@ -56,6 +57,7 @@ data class RoomPreviewViewState( homeServers = args.homeServers, roomName = args.roomName, roomTopic = args.topic, + numJoinMembers = args.numJoinedMembers, avatarUrl = args.avatarUrl, shouldPeekFromServer = args.peekFromServer, fromEmailInvite = args.fromEmailInvite, @@ -64,6 +66,6 @@ data class RoomPreviewViewState( fun matrixItem(): MatrixItem { return if (roomType == RoomType.SPACE) MatrixItem.SpaceItem(roomId, roomName ?: roomAlias, avatarUrl) - else MatrixItem.RoomItem(roomId, roomName ?: roomAlias, avatarUrl) + else MatrixItem.RoomItem(roomId, roomName ?: roomAlias, avatarUrl) } } From 0a08a50e110dcdc35eadee91036af0383022384f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 15:47:53 +0100 Subject: [PATCH 08/25] Analytics: Framework to send screen event --- .../vector/app/core/di/SingletonEntryPoint.kt | 4 +- .../app/core/platform/VectorBaseActivity.kt | 19 ++++++-- .../VectorBaseBottomSheetDialogFragment.kt | 22 +++++++-- .../app/core/platform/VectorBaseFragment.kt | 21 +++++++-- .../features/analytics/screen/ScreenEvent.kt | 46 +++++++++++++++++++ .../home/room/detail/RoomDetailFragment.kt | 2 - .../settings/VectorSettingsBaseFragment.kt | 25 ++++++++-- 7 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/features/analytics/screen/ScreenEvent.kt diff --git a/vector/src/main/java/im/vector/app/core/di/SingletonEntryPoint.kt b/vector/src/main/java/im/vector/app/core/di/SingletonEntryPoint.kt index 0b9855ef56f..283437c6793 100644 --- a/vector/src/main/java/im/vector/app/core/di/SingletonEntryPoint.kt +++ b/vector/src/main/java/im/vector/app/core/di/SingletonEntryPoint.kt @@ -21,7 +21,7 @@ import dagger.hilt.InstallIn import dagger.hilt.components.SingletonComponent import im.vector.app.core.dialogs.UnrecognizedCertificateDialog import im.vector.app.core.error.ErrorFormatter -import im.vector.app.features.analytics.VectorAnalytics +import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.navigation.Navigator @@ -56,7 +56,7 @@ interface SingletonEntryPoint { fun pinLocker(): PinLocker - fun analytics(): VectorAnalytics + fun analyticsTracker(): AnalyticsTracker fun webRtcCallManager(): WebRtcCallManager diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 21419d55cfa..1d1f76e21b6 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -65,7 +65,9 @@ import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.core.utils.toast import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs -import im.vector.app.features.analytics.VectorAnalytics +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.Screen +import im.vector.app.features.analytics.screen.ScreenEvent import im.vector.app.features.configuration.VectorConfiguration import im.vector.app.features.consent.ConsentNotGivenHelper import im.vector.app.features.navigation.Navigator @@ -90,6 +92,15 @@ import timber.log.Timber import javax.inject.Inject abstract class VectorBaseActivity : AppCompatActivity(), MavericksView { + /* ========================================================================================== + * Analytics + * ========================================================================================== */ + + protected var analyticsScreenName: Screen.ScreenName? = null + private var screenEvent: ScreenEvent? = null + + protected lateinit var analyticsTracker: AnalyticsTracker + /* ========================================================================================== * View * ========================================================================================== */ @@ -133,7 +144,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver private lateinit var sessionListener: SessionListener protected lateinit var bugReporter: BugReporter private lateinit var pinLocker: PinLocker - protected lateinit var analytics: VectorAnalytics @Inject lateinit var rageShake: RageShake @@ -189,7 +199,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver configurationViewModel = viewModelProvider.get(ConfigurationViewModel::class.java) bugReporter = singletonEntryPoint.bugReporter() pinLocker = singletonEntryPoint.pinLocker() - analytics = singletonEntryPoint.analytics() + analyticsTracker = singletonEntryPoint.analyticsTracker() navigator = singletonEntryPoint.navigator() activeSessionHolder = singletonEntryPoint.activeSessionHolder() vectorPreferences = singletonEntryPoint.vectorPreferences() @@ -324,7 +334,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver override fun onResume() { super.onResume() Timber.i("onResume Activity ${javaClass.simpleName}") - + screenEvent = analyticsScreenName?.let { ScreenEvent(it) } configurationViewModel.onActivityResumed() if (this !is BugReportActivity && vectorPreferences.useRageshake()) { @@ -363,6 +373,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver override fun onPause() { super.onPause() + screenEvent?.send(analyticsTracker) Timber.i("onPause Activity ${javaClass.simpleName}") rageShake.stop() diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt index 69c525dbdea..7e6a4292740 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseBottomSheetDialogFragment.kt @@ -37,7 +37,9 @@ import im.vector.app.core.di.ActivityEntryPoint import im.vector.app.core.extensions.singletonEntryPoint import im.vector.app.core.extensions.toMvRxBundle import im.vector.app.core.utils.DimensionConverter -import im.vector.app.features.analytics.VectorAnalytics +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.Screen +import im.vector.app.features.analytics.screen.ScreenEvent import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import reactivecircus.flowbinding.android.view.clicks @@ -47,6 +49,14 @@ import timber.log.Timber * Add Mavericks capabilities, handle DI and bindings. */ abstract class VectorBaseBottomSheetDialogFragment : BottomSheetDialogFragment(), MavericksView { + /* ========================================================================================== + * Analytics + * ========================================================================================== */ + + protected var analyticsScreenName: Screen.ScreenName? = null + private var screenEvent: ScreenEvent? = null + + protected lateinit var analyticsTracker: AnalyticsTracker /* ========================================================================================== * View @@ -84,8 +94,6 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomShe open val showExpanded = false - protected lateinit var analytics: VectorAnalytics - interface ResultListener { fun onBottomSheetResult(resultCode: Int, data: Any?) @@ -124,13 +132,19 @@ abstract class VectorBaseBottomSheetDialogFragment : BottomShe val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java) viewModelFactory = activityEntryPoint.viewModelFactory() val singletonEntryPoint = context.singletonEntryPoint() - analytics = singletonEntryPoint.analytics() + analyticsTracker = singletonEntryPoint.analyticsTracker() super.onAttach(context) } override fun onResume() { super.onResume() Timber.i("onResume BottomSheet ${javaClass.simpleName}") + screenEvent = analyticsScreenName?.let { ScreenEvent(it) } + } + + override fun onPause() { + super.onPause() + screenEvent?.send(analyticsTracker) } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt index 64443139f1c..f73002ff8d2 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseFragment.kt @@ -42,7 +42,9 @@ import im.vector.app.core.dialogs.UnrecognizedCertificateDialog import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.extensions.singletonEntryPoint import im.vector.app.core.extensions.toMvRxBundle -import im.vector.app.features.analytics.VectorAnalytics +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.Screen +import im.vector.app.features.analytics.screen.ScreenEvent import im.vector.app.features.navigation.Navigator import im.vector.lib.ui.styles.dialogs.MaterialProgressDialog import kotlinx.coroutines.flow.launchIn @@ -51,6 +53,18 @@ import reactivecircus.flowbinding.android.view.clicks import timber.log.Timber abstract class VectorBaseFragment : Fragment(), MavericksView { + /* ========================================================================================== + * Analytics + * ========================================================================================== */ + + protected var analyticsScreenName: Screen.ScreenName? = null + private var screenEvent: ScreenEvent? = null + + protected lateinit var analyticsTracker: AnalyticsTracker + + /* ========================================================================================== + * Activity + * ========================================================================================== */ protected val vectorBaseActivity: VectorBaseActivity<*> by lazy { activity as VectorBaseActivity<*> @@ -61,7 +75,6 @@ abstract class VectorBaseFragment : Fragment(), MavericksView * ========================================================================================== */ protected lateinit var navigator: Navigator - protected lateinit var analytics: VectorAnalytics protected lateinit var errorFormatter: ErrorFormatter protected lateinit var unrecognizedCertificateDialog: UnrecognizedCertificateDialog @@ -98,7 +111,7 @@ abstract class VectorBaseFragment : Fragment(), MavericksView val activityEntryPoint = EntryPointAccessors.fromActivity(vectorBaseActivity, ActivityEntryPoint::class.java) navigator = singletonEntryPoint.navigator() errorFormatter = singletonEntryPoint.errorFormatter() - analytics = singletonEntryPoint.analytics() + analyticsTracker = singletonEntryPoint.analyticsTracker() unrecognizedCertificateDialog = singletonEntryPoint.unrecognizedCertificateDialog() viewModelFactory = activityEntryPoint.viewModelFactory() childFragmentManager.fragmentFactory = activityEntryPoint.fragmentFactory() @@ -125,12 +138,14 @@ abstract class VectorBaseFragment : Fragment(), MavericksView override fun onResume() { super.onResume() Timber.i("onResume Fragment ${javaClass.simpleName}") + screenEvent = analyticsScreenName?.let { ScreenEvent(it) } } @CallSuper override fun onPause() { super.onPause() Timber.i("onPause Fragment ${javaClass.simpleName}") + screenEvent?.send(analyticsTracker) } @CallSuper diff --git a/vector/src/main/java/im/vector/app/features/analytics/screen/ScreenEvent.kt b/vector/src/main/java/im/vector/app/features/analytics/screen/ScreenEvent.kt new file mode 100644 index 00000000000..50008ce543a --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/screen/ScreenEvent.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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.analytics.screen + +import android.os.SystemClock +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.Screen +import timber.log.Timber + +/** + * Track a screen display. Unique usage. + */ +class ScreenEvent(val screenName: Screen.ScreenName) { + private val startTime = SystemClock.elapsedRealtime() + + // Protection to avoid multiple sending + private var isSent = false + + fun send(analyticsTracker: AnalyticsTracker) { + if (isSent) { + Timber.w("Event $screenName Already sent!") + return + } + isSent = true + analyticsTracker.screen( + Screen( + screenName = screenName, + durationMs = (SystemClock.elapsedRealtime() - startTime).toInt() + ) + ) + } +} diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 6838d83182c..9ed5d56d9ae 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -116,7 +116,6 @@ import im.vector.app.core.utils.startInstallFromSourceIntent import im.vector.app.core.utils.toast import im.vector.app.databinding.DialogReportContentBinding import im.vector.app.databinding.FragmentRoomDetailBinding -import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.plan.Click import im.vector.app.features.attachments.AttachmentTypeSelectorView import im.vector.app.features.attachments.AttachmentsHelper @@ -259,7 +258,6 @@ class RoomDetailFragment @Inject constructor( private val roomDetailPendingActionStore: RoomDetailPendingActionStore, private val pillsPostProcessorFactory: PillsPostProcessor.Factory, private val callManager: WebRtcCallManager, - private val analyticsTracker: AnalyticsTracker, private val voiceMessagePlaybackTracker: VoiceMessagePlaybackTracker, private val clock: Clock ) : diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt index 08d67067ec2..7cefd202694 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsBaseFragment.kt @@ -29,7 +29,9 @@ import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.extensions.singletonEntryPoint import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.utils.toast -import im.vector.app.features.analytics.VectorAnalytics +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.Screen +import im.vector.app.features.analytics.screen.ScreenEvent import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import org.matrix.android.sdk.api.session.Session @@ -37,6 +39,18 @@ import reactivecircus.flowbinding.android.view.clicks import timber.log.Timber abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), MavericksView { + /* ========================================================================================== + * Analytics + * ========================================================================================== */ + + protected var analyticsScreenName: Screen.ScreenName? = null + private var screenEvent: ScreenEvent? = null + + protected lateinit var analyticsTracker: AnalyticsTracker + + /* ========================================================================================== + * Activity + * ========================================================================================== */ val vectorActivity: VectorBaseActivity<*> by lazy { activity as VectorBaseActivity<*> @@ -47,7 +61,6 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), Maverick // members protected lateinit var session: Session protected lateinit var errorFormatter: ErrorFormatter - protected lateinit var analytics: VectorAnalytics /* ========================================================================================== * Views @@ -72,17 +85,23 @@ abstract class VectorSettingsBaseFragment : PreferenceFragmentCompat(), Maverick super.onAttach(context) session = singletonEntryPoint.activeSessionHolder().getActiveSession() errorFormatter = singletonEntryPoint.errorFormatter() - analytics = singletonEntryPoint.analytics() + analyticsTracker = singletonEntryPoint.analyticsTracker() } override fun onResume() { super.onResume() Timber.i("onResume Fragment ${javaClass.simpleName}") + screenEvent = analyticsScreenName?.let { ScreenEvent(it) } vectorActivity.supportActionBar?.setTitle(titleRes) // find the view from parent activity mLoadingView = vectorActivity.findViewById(R.id.vector_settings_spinner_views) } + override fun onPause() { + super.onPause() + screenEvent?.send(analyticsTracker) + } + abstract fun bindPref() abstract var titleRes: Int From dfb807506b68f039eb1fc57a8977d290b2cd9f41 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 16:00:59 +0100 Subject: [PATCH 09/25] Analytics: Track some screen (#4715) --- .../main/java/im/vector/app/features/home/HomeActivity.kt | 3 +++ .../app/features/home/room/detail/RoomDetailFragment.kt | 2 ++ .../app/features/roomdirectory/RoomDirectoryActivity.kt | 2 ++ .../features/roommemberprofile/RoomMemberProfileFragment.kt | 6 ++++++ 4 files changed, 13 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 031802995de..d3a3454673a 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -49,6 +49,7 @@ import im.vector.app.databinding.ActivityHomeBinding import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.disclaimer.showDisclaimerDialog import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.navigation.Navigator @@ -104,6 +105,7 @@ class HomeActivity : private lateinit var sharedActionViewModel: HomeSharedActionViewModel private val homeActivityViewModel: HomeActivityViewModel by viewModel() + @Suppress("UNUSED") private val analyticsAccountDataViewModel: AnalyticsAccountDataViewModel by viewModel() @Suppress("UNUSED") @@ -175,6 +177,7 @@ class HomeActivity : override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.Home supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice()) sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index 9ed5d56d9ae..bb9f3905f3b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -117,6 +117,7 @@ import im.vector.app.core.utils.toast import im.vector.app.databinding.DialogReportContentBinding import im.vector.app.databinding.FragmentRoomDetailBinding import im.vector.app.features.analytics.plan.Click +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.attachments.AttachmentTypeSelectorView import im.vector.app.features.attachments.AttachmentsHelper import im.vector.app.features.attachments.ContactAttachment @@ -336,6 +337,7 @@ class RoomDetailFragment @Inject constructor( override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.Room setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle -> bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId -> roomDetailViewModel.handle(RoomDetailAction.RoomUpgradeSuccess(replacementRoomId)) diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt index a52732d790d..3cd9955e74e 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt @@ -28,6 +28,7 @@ import im.vector.app.core.extensions.addFragmentToBackstack import im.vector.app.core.extensions.popBackstack import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivitySimpleBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.navigation.Navigator import im.vector.app.features.roomdirectory.createroom.CreateRoomArgs @@ -50,6 +51,7 @@ class RoomDirectoryActivity : VectorBaseActivity(), Matri override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.RoomDirectory sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java) if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt index 0243b44a8c8..91d13b39eda 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileFragment.kt @@ -47,6 +47,7 @@ import im.vector.app.databinding.DialogBaseEditTextBinding import im.vector.app.databinding.DialogShareQrCodeBinding import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.ViewStubRoomMemberProfileHeaderBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.crypto.verification.VerificationBottomSheet import im.vector.app.features.displayname.getBestName import im.vector.app.features.home.AvatarRenderer @@ -88,6 +89,11 @@ class RoomMemberProfileFragment @Inject constructor( override fun getMenuRes() = R.menu.vector_room_member_profile + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.User + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setupToolbar(views.matrixProfileToolbar) From ebd4dc0c5e875e3eb4f24e501d9355741cf099be Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 16:16:30 +0100 Subject: [PATCH 10/25] Analytics: Import the plan again --- .../app/features/analytics/plan/Screen.kt | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt index 9b578d8c825..39f9b93b05c 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt @@ -33,19 +33,189 @@ data class Screen( ) : VectorAnalyticsScreen { enum class ScreenName { + /** + * The screen shown to create a new (non-direct) room. + */ + CreateRoom, + + /** + * The confirmation screen shown before deactivating an account. + */ + DeactivateAccount, + + /** + * Legacy: The screen that shows information about a specific group. + */ Group, + + /** + * The Home tab on iOS | possibly the same on Android? | The Home space on Web? + */ Home, + + /** + * The Favourites tab on mobile that lists your favourite people/rooms. + */ + MobileFavourites, + + /** + * The screen shown to share a link to download the app. + */ + MobileInviteFriends, + + /** + * The People tab on mobile that lists all the DM rooms you have joined. + */ + MobilePeople, + + /** + * The Rooms tab on mobile that lists all the (non-direct) rooms you've joined. + */ + MobileRooms, + + /** + * The Files tab shown in the global search screen on Mobile. + */ + MobileSearchFiles, + + /** + * The Messages tab shown in the global search screen on Mobile. + */ + MobileSearchMessages, + + /** + * The People tab shown in the global search screen on Mobile. + */ + MobileSearchPeople, + + /** + * The Rooms tab shown in the global search screen on Mobile. + */ + MobileSearchRooms, + + /** + * The sidebar shown on mobile with spaces, settings etc. + */ + MobileSidebar, + + /** + * The screen shown to select which room directory you'd like to use. + */ + MobileSwitchDirectory, + + /** + * Legacy: The screen that shows all groups/communities you have joined. + */ MyGroups, + + /** + * The screen that displays the messages and events received in a room. + */ Room, + + /** + * The screen shown when tapping the name of a room from the Room screen. + */ + RoomDetails, + + /** + * The screen that lists public rooms for you to discover. + */ RoomDirectory, + + /** + * The screen that displays the list of members that are part of a room. + */ + RoomMembers, + + /** + * The notifications settings screen shown from the Room Details screen. + */ + RoomNotifications, + + /** + * The screen that allows you to search for messages/files in a specific room. + */ + RoomSearch, + + /** + * The settings screen shown from the Room Details screen. + */ + RoomSettings, + + /** + * The screen that allows you to see all of the files sent in a specific room. + */ + RoomUploads, + + /** + * The global settings screen shown in the app. + */ + Settings, + + /** + * The settings screen to change the default notification options. + */ + SettingsDefaultNotifications, + + /** + * The settings screen to manage notification mentions and keywords. + */ + SettingsMentionsAndKeywords, + + /** + * The global security settings screen. + */ + SettingsSecurity, + + /** + * The screen shown to create a new (non-direct) room. + */ + StartChat, + + /** + * A screen that shows information about a room member. + */ User, + + /** + * ? + */ WebCompleteSecurity, + + /** + * ? + */ WebE2ESetup, + + /** + * ? + */ WebForgotPassword, + + /** + * ? + */ WebLoading, + + /** + * ? + */ WebLogin, + + /** + * ? + */ WebRegister, + + /** + * ? + */ WebSoftLogout, + + /** + * ? + */ WebWelcome, } From f307c48dd4cd9d446d491e0fd20b87cf0fd4b319 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 16:34:40 +0100 Subject: [PATCH 11/25] Analytics: Track some screen (#4715) --- .../createdirect/CreateDirectRoomActivity.kt | 2 ++ .../app/features/home/HomeDrawerFragment.kt | 7 +++++++ .../home/room/list/RoomListFragment.kt | 10 ++++++++++ .../createroom/CreateRoomActivity.kt | 2 ++ .../picker/RoomDirectoryPickerFragment.kt | 6 ++++++ .../roomprofile/RoomProfileFragment.kt | 2 ++ .../uploads/RoomUploadsFragment.kt | 6 ++++++ .../settings/VectorSettingsRootFragment.kt | 7 +++++++ .../VectorSettingsSecurityPrivacyFragment.kt | 6 ++++++ .../deactivation/DeactivateAccountFragment.kt | 8 +++++++- ...gsDefaultNotificationPreferenceFragment.kt | 7 +++++++ ...dMentionsNotificationPreferenceFragment.kt | 20 ++++++++++++------- 12 files changed, 75 insertions(+), 8 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt index f73799d0e9c..0df9426852c 100644 --- a/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/createdirect/CreateDirectRoomActivity.kt @@ -42,6 +42,7 @@ import im.vector.app.core.utils.PERMISSIONS_FOR_TAKING_PHOTO import im.vector.app.core.utils.checkPermissions import im.vector.app.core.utils.onPermissionDeniedSnackbar import im.vector.app.core.utils.registerForPermissionsResult +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.contactsbook.ContactsBookFragment import im.vector.app.features.userdirectory.UserListFragment import im.vector.app.features.userdirectory.UserListFragmentArgs @@ -63,6 +64,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.StartChat views.toolbar.visibility = View.GONE sharedActionViewModel = viewModelProvider.get(UserListSharedActionViewModel::class.java) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt index 3accc247401..f506dc60538 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt @@ -30,6 +30,7 @@ import im.vector.app.core.extensions.replaceChildFragment import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.databinding.FragmentHomeDrawerBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorSettingsActivity import im.vector.app.features.spaces.SpaceListFragment @@ -51,6 +52,11 @@ class HomeDrawerFragment @Inject constructor( return FragmentHomeDrawerBinding.inflate(inflater, container, false) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.MobileSidebar + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -97,6 +103,7 @@ class HomeDrawerFragment @Inject constructor( views.homeDrawerInviteFriendButton.debouncedClicks { session.permalinkService().createPermalink(sharedActionViewModel.session.myUserId)?.let { permalink -> + analyticsTracker.screen(Screen(screenName = Screen.ScreenName.MobileInviteFriends)) val text = getString(R.string.invite_friends_text, permalink) startSharePlainTextIntent( diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt index 5171319a41e..b6481c9cbb0 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListFragment.kt @@ -42,6 +42,7 @@ import im.vector.app.core.platform.StateView import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.resources.UserPreferencesProvider import im.vector.app.databinding.FragmentRoomListBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.room.filtered.FilteredRoomFooterItem import im.vector.app.features.home.room.list.actions.RoomListQuickActionsBottomSheet @@ -100,6 +101,15 @@ class RoomListFragment @Inject constructor( private val adapterInfosList = mutableListOf() private var concatAdapter: ConcatAdapter? = null + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + analyticsScreenName = when (roomListParams.displayMode) { + RoomListDisplayMode.PEOPLE -> Screen.ScreenName.MobilePeople + RoomListDisplayMode.ROOMS -> Screen.ScreenName.MobileRooms + else -> null + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) views.stateView.contentView = views.roomListView diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt index 88bead52446..a98d1c2aa63 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt @@ -28,6 +28,7 @@ import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivitySimpleBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.roomdirectory.RoomDirectorySharedAction import im.vector.app.features.roomdirectory.RoomDirectorySharedActionViewModel import kotlinx.coroutines.flow.launchIn @@ -62,6 +63,7 @@ class CreateRoomActivity : VectorBaseActivity(), ToolbarC override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.CreateRoom sharedActionViewModel = viewModelProvider.get(RoomDirectorySharedActionViewModel::class.java) sharedActionViewModel .stream() diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt index 2707b87c1f1..9eb08bf4929 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/picker/RoomDirectoryPickerFragment.kt @@ -30,6 +30,7 @@ import im.vector.app.core.extensions.configureWith import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentRoomDirectoryPickerBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.roomdirectory.RoomDirectoryAction import im.vector.app.features.roomdirectory.RoomDirectoryData import im.vector.app.features.roomdirectory.RoomDirectoryServer @@ -52,6 +53,11 @@ class RoomDirectoryPickerFragment @Inject constructor(private val roomDirectoryP return FragmentRoomDirectoryPickerBinding.inflate(inflater, container, false) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.MobileSwitchDirectory + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt index d82b853fe3b..eb27811f40d 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileFragment.kt @@ -44,6 +44,7 @@ import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.startSharePlainTextIntent import im.vector.app.databinding.FragmentMatrixProfileBinding import im.vector.app.databinding.ViewStubRoomProfileHeaderBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.room.detail.RoomDetailPendingAction import im.vector.app.features.home.room.detail.RoomDetailPendingActionStore @@ -88,6 +89,7 @@ class RoomProfileFragment @Inject constructor( override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.RoomSettings setFragmentResultListener(MigrateRoomBottomSheet.REQUEST_KEY) { _, bundle -> bundle.getString(MigrateRoomBottomSheet.BUNDLE_KEY_REPLACEMENT_ROOM)?.let { replacementRoomId -> roomDetailPendingActionStore.data = RoomDetailPendingAction.OpenRoom(replacementRoomId, closeCurrentRoom = true) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt index 3716d9682ce..52368594df5 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/RoomUploadsFragment.kt @@ -34,6 +34,7 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.utils.saveMedia import im.vector.app.core.utils.shareMedia import im.vector.app.databinding.FragmentRoomUploadsBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.roomprofile.RoomProfileArgs @@ -54,6 +55,11 @@ class RoomUploadsFragment @Inject constructor( return FragmentRoomUploadsBinding.inflate(inflater, container, false) } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.RoomUploads + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt index 79eb0216ee7..fb5d83239bd 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsRootFragment.kt @@ -16,8 +16,10 @@ package im.vector.app.features.settings +import android.os.Bundle import im.vector.app.R import im.vector.app.core.preference.VectorPreference +import im.vector.app.features.analytics.plan.Screen import javax.inject.Inject class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragment() { @@ -25,6 +27,11 @@ class VectorSettingsRootFragment @Inject constructor() : VectorSettingsBaseFragm override var titleRes: Int = R.string.title_activity_settings override val preferenceXmlRes = R.xml.vector_settings_root + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.Settings + } + override fun bindPref() { tintIcons() } diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt index 279499b7e9f..31fce00f3cb 100644 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsSecurityPrivacyFragment.kt @@ -51,6 +51,7 @@ import im.vector.app.core.utils.copyToClipboard import im.vector.app.core.utils.openFileSelection import im.vector.app.core.utils.toast import im.vector.app.databinding.DialogImportE2eKeysBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewActions import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewModel import im.vector.app.features.analytics.ui.consent.AnalyticsConsentViewState @@ -91,6 +92,11 @@ class VectorSettingsSecurityPrivacyFragment @Inject constructor( private val analyticsConsentViewModel: AnalyticsConsentViewModel by fragmentViewModel() + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.SettingsSecurity + } + // cryptography private val mCryptographyCategory by lazy { findPreference(VectorPreferences.SETTINGS_CRYPTOGRAPHY_PREFERENCE_KEY)!! diff --git a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt index 5729e773b7e..867526c0091 100644 --- a/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/account/deactivation/DeactivateAccountFragment.kt @@ -31,6 +31,7 @@ import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.databinding.FragmentDeactivateAccountBinding import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.auth.ReAuthActivity import im.vector.app.features.settings.VectorSettingsActivity import org.matrix.android.sdk.api.auth.data.LoginFlowTypes @@ -47,7 +48,7 @@ class DeactivateAccountFragment @Inject constructor() : VectorBaseFragment if (activityResult.resultCode == Activity.RESULT_OK) { when (activityResult.data?.extras?.getString(ReAuthActivity.RESULT_FLOW_TYPE)) { - LoginFlowTypes.SSO -> { + LoginFlowTypes.SSO -> { viewModel.handle(DeactivateAccountAction.SsoAuthDone) } LoginFlowTypes.PASSWORD -> { @@ -63,6 +64,11 @@ class DeactivateAccountFragment @Inject constructor() : VectorBaseFragment("SETTINGS_DEFAULT")!! diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsKeywordAndMentionsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsKeywordAndMentionsNotificationPreferenceFragment.kt index fb1a357c303..b7cf7f6bbe9 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsKeywordAndMentionsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsKeywordAndMentionsNotificationPreferenceFragment.kt @@ -25,6 +25,7 @@ import im.vector.app.core.preference.KeywordPreference import im.vector.app.core.preference.VectorCheckboxPreference import im.vector.app.core.preference.VectorPreference import im.vector.app.core.preference.VectorPreferenceCategory +import im.vector.app.features.analytics.plan.Screen import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -34,7 +35,7 @@ import org.matrix.android.sdk.api.pushrules.rest.PushRule import org.matrix.android.sdk.api.pushrules.toJson class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment : - VectorSettingsPushRuleNotificationPreferenceFragment() { + VectorSettingsPushRuleNotificationPreferenceFragment() { override var titleRes: Int = R.string.settings_notification_mentions_and_keywords @@ -42,6 +43,11 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment : private var keywordsHasFocus = false + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.SettingsMentionsAndKeywords + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) session.getKeywords().observe(viewLifecycleOwner, this::updateWithKeywords) @@ -71,7 +77,7 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment : val keywords = editKeywordPreference.keywords val newChecked = newValue as Boolean displayLoadingView() - updateKeywordPushRules(keywords, newChecked) { result -> + updateKeywordPushRules(keywords, newChecked) { result -> hideLoadingView() if (!isAdded) { return@updateKeywordPushRules @@ -88,7 +94,7 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment : false } - editKeywordPreference.listener = object : KeywordPreference.Listener { + editKeywordPreference.listener = object : KeywordPreference.Listener { override fun onFocusDidChange(hasFocus: Boolean) { keywordsHasFocus = true } @@ -174,8 +180,8 @@ class VectorSettingsKeywordAndMentionsNotificationPreferenceFragment : } override val prefKeyToPushRuleId = mapOf( - "SETTINGS_PUSH_RULE_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_DISPLAY_NAME, - "SETTINGS_PUSH_RULE_CONTAINING_MY_USER_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_USER_NAME, - "SETTINGS_PUSH_RULE_MESSAGES_CONTAINING_AT_ROOM_PREFERENCE_KEY" to RuleIds.RULE_ID_ROOM_NOTIF - ) + "SETTINGS_PUSH_RULE_CONTAINING_MY_DISPLAY_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_DISPLAY_NAME, + "SETTINGS_PUSH_RULE_CONTAINING_MY_USER_NAME_PREFERENCE_KEY" to RuleIds.RULE_ID_CONTAIN_USER_NAME, + "SETTINGS_PUSH_RULE_MESSAGES_CONTAINING_AT_ROOM_PREFERENCE_KEY" to RuleIds.RULE_ID_ROOM_NOTIF + ) } From 67f43550acc5e765bea71b454fdb91c2ef449511 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 16:42:33 +0100 Subject: [PATCH 12/25] Analytics: Fix issue with the drawer --- .../java/im/vector/app/features/home/HomeActivity.kt | 12 ++++++++++++ .../vector/app/features/home/HomeDrawerFragment.kt | 5 ----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index d3a3454673a..59f20b8b0d5 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -24,6 +24,7 @@ import android.os.Bundle import android.os.Parcelable import android.view.Menu import android.view.MenuItem +import android.view.View import androidx.core.view.GravityCompat import androidx.core.view.isVisible import androidx.drawerlayout.widget.DrawerLayout @@ -50,6 +51,7 @@ import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs import im.vector.app.features.analytics.accountdata.AnalyticsAccountDataViewModel import im.vector.app.features.analytics.plan.Screen +import im.vector.app.features.analytics.screen.ScreenEvent import im.vector.app.features.disclaimer.showDisclaimerDialog import im.vector.app.features.matrixto.MatrixToBottomSheet import im.vector.app.features.navigation.Navigator @@ -166,6 +168,16 @@ class HomeActivity : } private val drawerListener = object : DrawerLayout.SimpleDrawerListener() { + private var drawerScreenEvent: ScreenEvent? = null + override fun onDrawerOpened(drawerView: View) { + drawerScreenEvent = ScreenEvent(Screen.ScreenName.MobileSidebar) + } + + override fun onDrawerClosed(drawerView: View) { + drawerScreenEvent?.send(analyticsTracker) + drawerScreenEvent = null + } + override fun onDrawerStateChanged(newState: Int) { hideKeyboard() } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt index f506dc60538..9af06ef8010 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeDrawerFragment.kt @@ -52,11 +52,6 @@ class HomeDrawerFragment @Inject constructor( return FragmentHomeDrawerBinding.inflate(inflater, container, false) } - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - analyticsScreenName = Screen.ScreenName.MobileSidebar - } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) From 13b4a58eafa6cef9b0458be4a004f25b9ec4feda Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 16:51:48 +0100 Subject: [PATCH 13/25] Analytics: Add more screen https://github.com/matrix-org/matrix-analytics-events/pull/11 --- .../app/features/analytics/plan/Screen.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt index 39f9b93b05c..52c2fc76fcc 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt @@ -53,6 +53,16 @@ data class Screen( */ Home, + /** + * The screen that displays the user's breadcrumbs. + */ + MobileBreadcrumbs, + + /** + * The tab on mobile that displays the dialpad. + */ + MobileDialpad, + /** * The Favourites tab on mobile that lists your favourite people/rooms. */ @@ -63,6 +73,11 @@ data class Screen( */ MobileInviteFriends, + /** + * The screen that displays the login flow. + */ + MobileLogin, + /** * The People tab on mobile that lists all the DM rooms you have joined. */ @@ -123,6 +138,11 @@ data class Screen( */ RoomDirectory, + /** + * The screen that lists all the user's rooms and let them filter the rooms. + */ + RoomFilter, + /** * The screen that displays the list of members that are part of a room. */ @@ -169,7 +189,7 @@ data class Screen( SettingsSecurity, /** - * The screen shown to create a new (non-direct) room. + * The screen shown to create a new direct room. */ StartChat, From db3353feb5d915fcee54631300821319f6bb7973 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 16:53:13 +0100 Subject: [PATCH 14/25] Analytics: Track some screen (#4715) --- .../features/home/room/detail/RoomDetailActivity.kt | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt index 05dbd724d12..9565f9ca620 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt @@ -19,6 +19,7 @@ package im.vector.app.features.home.room.detail import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import android.widget.Toast import androidx.core.view.GravityCompat import androidx.drawerlayout.widget.DrawerLayout @@ -36,6 +37,8 @@ import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivityRoomDetailBinding +import im.vector.app.features.analytics.plan.Screen +import im.vector.app.features.analytics.screen.ScreenEvent import im.vector.app.features.home.room.breadcrumbs.BreadcrumbsFragment import im.vector.app.features.home.room.detail.timeline.helper.VoiceMessagePlaybackTracker import im.vector.app.features.matrixto.MatrixToBottomSheet @@ -161,6 +164,16 @@ class RoomDetailActivity : } private val drawerListener = object : DrawerLayout.SimpleDrawerListener() { + private var drawerScreenEvent: ScreenEvent? = null + override fun onDrawerOpened(drawerView: View) { + drawerScreenEvent = ScreenEvent(Screen.ScreenName.MobileBreadcrumbs) + } + + override fun onDrawerClosed(drawerView: View) { + drawerScreenEvent?.send(analyticsTracker) + drawerScreenEvent = null + } + override fun onDrawerStateChanged(newState: Int) { hideKeyboard() From 54108b8f8dd2fcd01fd1ba6baa43fc8962bbe57a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 15 Dec 2021 16:59:05 +0100 Subject: [PATCH 15/25] Analytics: Track some screen (#4715) --- .../features/call/dialpad/DialPadFragment.kt | 24 +++++++++++++++++++ .../room/filtered/FilteredRoomsActivity.kt | 2 ++ .../app/features/login/LoginActivity.kt | 3 +++ 3 files changed, 29 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadFragment.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadFragment.kt index 16e7c01b5c5..5fc866a4dd3 100644 --- a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadFragment.kt +++ b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadFragment.kt @@ -17,6 +17,7 @@ package im.vector.app.features.call.dialpad import android.content.ClipboardManager +import android.content.Context import android.content.res.ColorStateList import android.os.Bundle import android.telephony.PhoneNumberFormattingTextWatcher @@ -37,6 +38,10 @@ import androidx.fragment.app.Fragment import com.android.dialer.dialpadview.DialpadView import com.android.dialer.dialpadview.DigitsEditText import im.vector.app.R +import im.vector.app.core.extensions.singletonEntryPoint +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.Screen +import im.vector.app.features.analytics.screen.ScreenEvent import im.vector.app.features.themes.ThemeUtils class DialPadFragment : Fragment(), TextWatcher { @@ -53,6 +58,25 @@ class DialPadFragment : Fragment(), TextWatcher { private var enableDelete = true private var enableFabOk = true + private lateinit var analyticsTracker: AnalyticsTracker + + override fun onAttach(context: Context) { + super.onAttach(context) + val singletonEntryPoint = context.singletonEntryPoint() + analyticsTracker = singletonEntryPoint.analyticsTracker() + } + + private var screenEvent: ScreenEvent? = null + override fun onResume() { + super.onResume() + screenEvent = ScreenEvent(Screen.ScreenName.MobileDialpad) + } + + override fun onPause() { + super.onPause() + screenEvent?.send(analyticsTracker) + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, diff --git a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt index 5f8ccc794ae..dbfa319b86e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt @@ -24,6 +24,7 @@ import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivityFilteredRoomsBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.home.room.list.RoomListFragment import im.vector.app.features.home.room.list.RoomListParams @@ -42,6 +43,7 @@ class FilteredRoomsActivity : VectorBaseActivity() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + analyticsScreenName = Screen.ScreenName.RoomFilter configureToolbar(views.filteredRoomsToolbar) if (isFirstCreation()) { val params = RoomListParams(RoomListDisplayMode.FILTERED) diff --git a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt index 5ab08ffff79..df0ab4623e4 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt @@ -40,6 +40,7 @@ import im.vector.app.core.extensions.exhaustive import im.vector.app.core.platform.ToolbarConfigurable import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivityLoginBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.home.HomeActivity import im.vector.app.features.login.terms.LoginTermsFragment import im.vector.app.features.login.terms.LoginTermsFragmentArgument @@ -82,6 +83,8 @@ open class LoginActivity : VectorBaseActivity(), ToolbarCo override fun getCoordinatorLayout() = views.coordinatorLayout override fun initUiAndData() { + analyticsScreenName = Screen.ScreenName.MobileLogin + if (isFirstCreation()) { addFirstFragment() } From 1e3733fe8e69486f2bb857908f745331c9458f3a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 30 Dec 2021 18:03:04 +0100 Subject: [PATCH 16/25] Analytics: login/register screens --- .../app/core/platform/VectorBaseActivity.kt | 2 +- .../app/features/analytics/plan/Screen.kt | 39 ++++++++----------- .../features/analytics/screen/ScreenEvent.kt | 8 +++- .../app/features/login/LoginActivity.kt | 6 ++- 4 files changed, 29 insertions(+), 26 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 1d1f76e21b6..3dc17718c69 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -373,7 +373,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver override fun onPause() { super.onPause() - screenEvent?.send(analyticsTracker) + screenEvent?.send(analyticsTracker, analyticsScreenName) Timber.i("onPause Activity ${javaClass.simpleName}") rageShake.stop() diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt index 52c2fc76fcc..bf44dfd2f92 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt @@ -43,6 +43,11 @@ data class Screen( */ DeactivateAccount, + /** + * The form for the forgot password use case + */ + ForgotPassword, + /** * Legacy: The screen that shows information about a specific group. */ @@ -53,6 +58,11 @@ data class Screen( */ Home, + /** + * The screen that displays the login flow (when the user already has an account). + */ + Login, + /** * The screen that displays the user's breadcrumbs. */ @@ -73,11 +83,6 @@ data class Screen( */ MobileInviteFriends, - /** - * The screen that displays the login flow. - */ - MobileLogin, - /** * The People tab on mobile that lists all the DM rooms you have joined. */ @@ -123,6 +128,11 @@ data class Screen( */ MyGroups, + /** + * The screen that displays the registration flow (when the user wants to create an account) + */ + Register, + /** * The screen that displays the messages and events received in a room. */ @@ -208,35 +218,20 @@ data class Screen( */ WebE2ESetup, - /** - * ? - */ - WebForgotPassword, - /** * ? */ WebLoading, - /** - * ? - */ - WebLogin, - - /** - * ? - */ - WebRegister, - /** * ? */ WebSoftLogout, /** - * ? + * The splash screen. */ - WebWelcome, + Welcome, } override fun getName() = screenName.name diff --git a/vector/src/main/java/im/vector/app/features/analytics/screen/ScreenEvent.kt b/vector/src/main/java/im/vector/app/features/analytics/screen/ScreenEvent.kt index 50008ce543a..8e0513f25ae 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/screen/ScreenEvent.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/screen/ScreenEvent.kt @@ -30,7 +30,11 @@ class ScreenEvent(val screenName: Screen.ScreenName) { // Protection to avoid multiple sending private var isSent = false - fun send(analyticsTracker: AnalyticsTracker) { + /** + * @param screenNameOverride can be used to override the screen name passed in constructor parameter + */ + fun send(analyticsTracker: AnalyticsTracker, + screenNameOverride: Screen.ScreenName? = null) { if (isSent) { Timber.w("Event $screenName Already sent!") return @@ -38,7 +42,7 @@ class ScreenEvent(val screenName: Screen.ScreenName) { isSent = true analyticsTracker.screen( Screen( - screenName = screenName, + screenName = screenNameOverride ?: screenName, durationMs = (SystemClock.elapsedRealtime() - startTime).toInt() ) ) diff --git a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt index df0ab4623e4..f1bf8ab4a91 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt @@ -83,7 +83,7 @@ open class LoginActivity : VectorBaseActivity(), ToolbarCo override fun getCoordinatorLayout() = views.coordinatorLayout override fun initUiAndData() { - analyticsScreenName = Screen.ScreenName.MobileLogin + analyticsScreenName = Screen.ScreenName.Login if (isFirstCreation()) { addFirstFragment() @@ -203,6 +203,10 @@ open class LoginActivity : VectorBaseActivity(), ToolbarCo private fun updateWithState(loginViewState: LoginViewState) { if (loginViewState.isUserLogged()) { + if (loginViewState.signMode == SignMode.SignUp) { + // change the screen name + analyticsScreenName = Screen.ScreenName.Register + } val intent = HomeActivity.newIntent( this, accountCreation = loginViewState.signMode == SignMode.SignUp From e3c70d1bb155f406b141d4a35bd5bacdf0c4ad5c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 30 Dec 2021 18:04:53 +0100 Subject: [PATCH 17/25] Analytics: splashscreen --- .../im/vector/app/features/login/LoginSplashFragment.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt index 2fab1751689..b6090a88c70 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginSplashFragment.kt @@ -26,6 +26,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.databinding.FragmentLoginSplashBinding +import im.vector.app.features.analytics.plan.Screen import im.vector.app.features.settings.VectorPreferences import org.matrix.android.sdk.api.failure.Failure import java.net.UnknownHostException @@ -42,6 +43,11 @@ class LoginSplashFragment @Inject constructor( return FragmentLoginSplashBinding.inflate(inflater, container, false) } + override fun onCreate(savedInstanceState: Bundle?) { + analyticsScreenName = Screen.ScreenName.Welcome + super.onCreate(savedInstanceState) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) From 69a96438944f4643241228cc804d865c38b753b8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 30 Dec 2021 18:05:54 +0100 Subject: [PATCH 18/25] Analytics: forgot password screen --- .../vector/app/features/login/LoginResetPasswordFragment.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt index 52bd80a16ff..0328d09427c 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginResetPasswordFragment.kt @@ -31,6 +31,7 @@ import im.vector.app.core.extensions.hidePassword import im.vector.app.core.extensions.isEmail import im.vector.app.core.extensions.toReducedUrl import im.vector.app.databinding.FragmentLoginResetPasswordBinding +import im.vector.app.features.analytics.plan.Screen import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.map @@ -46,6 +47,11 @@ class LoginResetPasswordFragment @Inject constructor() : AbstractLoginFragment Date: Fri, 31 Dec 2021 10:11:47 +0100 Subject: [PATCH 19/25] Analytics: track call start and call end --- .../app/features/call/webrtc/WebRtcCall.kt | 4 +++ .../features/call/webrtc/WebRtcCallManager.kt | 32 ++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 786e1655d6a..90088c84750 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -270,6 +270,10 @@ class WebRtcCall( } } + fun durationMillis(): Int { + return timer.elapsedTime().toInt() + } + fun formattedDuration(): String { return formatDuration( Duration.ofMillis(timer.elapsedTime()) diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index 80390a7dfbe..fe12bf1ec7f 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -22,6 +22,9 @@ import androidx.lifecycle.LifecycleOwner import im.vector.app.ActiveSessionDataSource import im.vector.app.BuildConfig import im.vector.app.core.services.CallService +import im.vector.app.features.analytics.AnalyticsTracker +import im.vector.app.features.analytics.plan.CallEnded +import im.vector.app.features.analytics.plan.CallStarted import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.audio.CallAudioManager import im.vector.app.features.call.lookup.CallProtocolsChecker @@ -68,7 +71,8 @@ private val loggerTag = LoggerTag("WebRtcCallManager", LoggerTag.VOIP) @Singleton class WebRtcCallManager @Inject constructor( private val context: Context, - private val activeSessionDataSource: ActiveSessionDataSource + private val activeSessionDataSource: ActiveSessionDataSource, + private val analyticsTracker: AnalyticsTracker ) : CallListener, DefaultLifecycleObserver { @@ -237,6 +241,7 @@ class WebRtcCallManager @Inject constructor( val currentCall = getCurrentCall().takeIf { it != call } currentCall?.updateRemoteOnHold(onHold = true) audioManager.setMode(if (call.mxCall.isVideoCall) CallAudioManager.Mode.VIDEO_CALL else CallAudioManager.Mode.AUDIO_CALL) + call.trackCallStarted() this.currentCall.setAndNotify(call) } @@ -245,6 +250,7 @@ class WebRtcCallManager @Inject constructor( val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also { Timber.tag(loggerTag.value).v("On call ended for unknown call $callId") } + webRtcCall.trackCallEnded() CallService.onCallTerminated(context, callId, endCallReason, rejected) callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall) callsByRoomId[webRtcCall.nativeRoomId]?.remove(webRtcCall) @@ -443,4 +449,28 @@ class WebRtcCallManager @Inject constructor( } call.onCallAssertedIdentityReceived(callAssertedIdentityContent) } + + /** + * Analytics + */ + private fun WebRtcCall.trackCallStarted() { + analyticsTracker.capture( + CallStarted( + isVideo = mxCall.isVideoCall, + numParticipants = 2, + placed = mxCall.isOutgoing + ) + ) + } + + private fun WebRtcCall.trackCallEnded() { + analyticsTracker.capture( + CallEnded( + durationMs = durationMillis(), + isVideo = mxCall.isVideoCall, + numParticipants = 2, + placed = mxCall.isOutgoing + ) + ) + } } From 880b97cc5c9ea6888e933c38eebc3ffaf0797e25 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Jan 2022 15:21:25 +0100 Subject: [PATCH 20/25] Analytics: import latest plan --- .../analytics/plan/UnauthenticatedError.kt | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/analytics/plan/UnauthenticatedError.kt diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/UnauthenticatedError.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/UnauthenticatedError.kt new file mode 100644 index 00000000000..9c7e0812bd7 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/UnauthenticatedError.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 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.analytics.plan + +import im.vector.app.features.analytics.itf.VectorAnalyticsEvent + +// GENERATED FILE, DO NOT EDIT. FOR MORE INFORMATION VISIT +// https://github.com/matrix-org/matrix-analytics-events/ + +/** + * Triggered when the user becomes unauthenticated without actually clicking sign out(E.g. Due to expiry of an access token without a way to refresh). + */ +data class UnauthenticatedError( + /** + * The error code as defined in matrix spec. The source of this error is from the homeserver. + */ + val errorCode: ErrorCode, + /** + * The reason for the error. The source of this error is from the homeserver, the reason can vary and is subject to change so there is no enum of possible values. + */ + val errorReason: String, + /** + * Whether the auth mechanism is refresh-token-based. + */ + val refreshTokenAuth: Boolean, + /** + * Whether a soft logout or hard logout was triggered. + */ + val softLogout: Boolean, +) : VectorAnalyticsEvent { + + enum class ErrorCode { + M_FORBIDDEN, + M_UNKNOWN, + M_UNKNOWN_TOKEN, + } + + override fun getName() = "UnauthenticatedError" + + override fun getProperties(): Map? { + return mutableMapOf().apply { + put("errorCode", errorCode.name) + put("errorReason", errorReason) + put("refreshTokenAuth", refreshTokenAuth) + put("softLogout", softLogout) + }.takeIf { it.isNotEmpty() } + } +} From c0aa0cef62dff08865b29e44d833c06550ffc262 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Jan 2022 15:24:25 +0100 Subject: [PATCH 21/25] Analytics: inject analyticsTracker, it has a better scope --- .../vector/app/features/analytics/DecryptionFailureTracker.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/analytics/DecryptionFailureTracker.kt b/vector/src/main/java/im/vector/app/features/analytics/DecryptionFailureTracker.kt index 8b9dcc348bc..6b2ceb1444f 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/DecryptionFailureTracker.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/DecryptionFailureTracker.kt @@ -49,7 +49,7 @@ private const val CHECK_INTERVAL = 2_000L */ @Singleton class DecryptionFailureTracker @Inject constructor( - private val vectorAnalytics: VectorAnalytics, + private val analyticsTracker: AnalyticsTracker, private val clock: Clock ) { @@ -136,7 +136,7 @@ class DecryptionFailureTracker @Inject constructor( // for now we ignore events already reported even if displayed again? .filter { alreadyReported.contains(it).not() } .forEach { failedEventId -> - vectorAnalytics.capture(Error(failedEventId, Error.Domain.E2EE, aggregation.key)) + analyticsTracker.capture(Error(failedEventId, Error.Domain.E2EE, aggregation.key)) alreadyReported.add(failedEventId) } } From 9e57263fb679d8f967da8331131d5e94689aa7fd Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 19 Jan 2022 15:45:59 +0100 Subject: [PATCH 22/25] Changelog --- changelog.d/4734.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/4734.misc diff --git a/changelog.d/4734.misc b/changelog.d/4734.misc new file mode 100644 index 00000000000..46748df141c --- /dev/null +++ b/changelog.d/4734.misc @@ -0,0 +1 @@ +Analytics: send more Events \ No newline at end of file From 81b8260eb2b0922fffb5831dd08855f54a5628f7 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Jan 2022 14:42:10 +0100 Subject: [PATCH 23/25] Add new class in analytics plan --- .../app/features/analytics/plan/Identity.kt | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 vector/src/main/java/im/vector/app/features/analytics/plan/Identity.kt diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Identity.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Identity.kt new file mode 100644 index 00000000000..1cc433aa7e5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Identity.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021 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.analytics.plan + +import im.vector.app.features.analytics.itf.VectorAnalyticsEvent + +// GENERATED FILE, DO NOT EDIT. FOR MORE INFORMATION VISIT +// https://github.com/matrix-org/matrix-analytics-events/ + +/** + * The user properties to apply when identifying + */ +data class Identity( + /** + * The selected messaging use case during the onboarding flow. + */ + val ftueUseCaseSelection: FtueUseCaseSelection? = null, +) : VectorAnalyticsEvent { + + enum class FtueUseCaseSelection { + /** + * The third option, Communities. + */ + CommunityMessaging, + + /** + * The first option, Friends and family. + */ + PersonalMessaging, + + /** + * The footer option to skip the question. + */ + Skip, + + /** + * The second option, Teams. + */ + WorkMessaging, + } + + override fun getName() = "Identity" + + override fun getProperties(): Map? { + return mutableMapOf().apply { + ftueUseCaseSelection?.let { put("ftueUseCaseSelection", it.name) } + }.takeIf { it.isNotEmpty() } + } +} From 000806550ab9515bf8e66d5741577a4ca9705b1b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Jan 2022 15:36:16 +0100 Subject: [PATCH 24/25] Split long lines Done by https://github.com/matrix-org/matrix-analytics-events/pull/16 --- .../analytics/plan/PerformanceTimer.kt | 12 ++++++---- .../app/features/analytics/plan/Screen.kt | 24 ++++++++++++------- .../analytics/plan/UnauthenticatedError.kt | 10 +++++--- 3 files changed, 31 insertions(+), 15 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt index 8c25534ece9..2cfc366cd33 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/PerformanceTimer.kt @@ -30,7 +30,8 @@ data class PerformanceTimer( */ val context: String? = null, /** - * Client defined, an optional value to indicate how many items were handled during the operation. + * Client defined, an optional value to indicate how many items were + * handled during the operation. */ val itemCount: Int? = null, /** @@ -55,7 +56,8 @@ data class PerformanceTimer( InitialSyncRequest, /** - * The time taken to display an event in the timeline that was opened from a notification. + * The time taken to display an event in the timeline that was opened + * from a notification. */ NotificationsOpenEvent, @@ -65,7 +67,8 @@ data class PerformanceTimer( StartupIncrementalSync, /** - * The duration of an initial /sync request during startup (if the store has been wiped). + * The duration of an initial /sync request during startup (if the store + * has been wiped). */ StartupInitialSync, @@ -80,7 +83,8 @@ data class PerformanceTimer( StartupStorePreload, /** - * The time to load all data from the store (including StartupStorePreload time). + * The time to load all data from the store (including + * StartupStorePreload time). */ StartupStoreReady, } diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt index bf44dfd2f92..db4dcd0fac7 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/Screen.kt @@ -54,12 +54,14 @@ data class Screen( Group, /** - * The Home tab on iOS | possibly the same on Android? | The Home space on Web? + * The Home tab on iOS | possibly the same on Android? | The Home space + * on Web? */ Home, /** - * The screen that displays the login flow (when the user already has an account). + * The screen that displays the login flow (when the user already has an + * account). */ Login, @@ -89,7 +91,8 @@ data class Screen( MobilePeople, /** - * The Rooms tab on mobile that lists all the (non-direct) rooms you've joined. + * The Rooms tab on mobile that lists all the (non-direct) rooms you've + * joined. */ MobileRooms, @@ -129,7 +132,8 @@ data class Screen( MyGroups, /** - * The screen that displays the registration flow (when the user wants to create an account) + * The screen that displays the registration flow (when the user wants + * to create an account) */ Register, @@ -139,7 +143,8 @@ data class Screen( Room, /** - * The screen shown when tapping the name of a room from the Room screen. + * The screen shown when tapping the name of a room from the Room + * screen. */ RoomDetails, @@ -149,7 +154,8 @@ data class Screen( RoomDirectory, /** - * The screen that lists all the user's rooms and let them filter the rooms. + * The screen that lists all the user's rooms and let them filter the + * rooms. */ RoomFilter, @@ -164,7 +170,8 @@ data class Screen( RoomNotifications, /** - * The screen that allows you to search for messages/files in a specific room. + * The screen that allows you to search for messages/files in a specific + * room. */ RoomSearch, @@ -174,7 +181,8 @@ data class Screen( RoomSettings, /** - * The screen that allows you to see all of the files sent in a specific room. + * The screen that allows you to see all of the files sent in a specific + * room. */ RoomUploads, diff --git a/vector/src/main/java/im/vector/app/features/analytics/plan/UnauthenticatedError.kt b/vector/src/main/java/im/vector/app/features/analytics/plan/UnauthenticatedError.kt index 9c7e0812bd7..56ef4af4be8 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/plan/UnauthenticatedError.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/plan/UnauthenticatedError.kt @@ -22,15 +22,19 @@ import im.vector.app.features.analytics.itf.VectorAnalyticsEvent // https://github.com/matrix-org/matrix-analytics-events/ /** - * Triggered when the user becomes unauthenticated without actually clicking sign out(E.g. Due to expiry of an access token without a way to refresh). + * Triggered when the user becomes unauthenticated without actually clicking + * sign out(E.g. Due to expiry of an access token without a way to refresh). */ data class UnauthenticatedError( /** - * The error code as defined in matrix spec. The source of this error is from the homeserver. + * The error code as defined in matrix spec. The source of this error is + * from the homeserver. */ val errorCode: ErrorCode, /** - * The reason for the error. The source of this error is from the homeserver, the reason can vary and is subject to change so there is no enum of possible values. + * The reason for the error. The source of this error is from the + * homeserver, the reason can vary and is subject to change so there is + * no enum of possible values. */ val errorReason: String, /** From 58197b8853a82bc368eb1181ac37c806aa0926d1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 20 Jan 2022 15:37:57 +0100 Subject: [PATCH 25/25] Fix enum class warning --- tools/check/forbidden_strings_in_code.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/check/forbidden_strings_in_code.txt b/tools/check/forbidden_strings_in_code.txt index 293e0b2a583..4cbb2955db6 100644 --- a/tools/check/forbidden_strings_in_code.txt +++ b/tools/check/forbidden_strings_in_code.txt @@ -160,7 +160,7 @@ Formatter\.formatShortFileSize===1 # android\.text\.TextUtils ### This is not a rule, but a warning: the number of "enum class" has changed. For Json classes, it is mandatory that they have `@JsonClass(generateAdapter = false)`. If the enum is not used as a Json class, change the value in file forbidden_strings_in_code.txt -enum class===119 +enum class===121 ### Do not import temporary legacy classes import org.matrix.android.sdk.internal.legacy.riot===3