Commit daded49b authored by Filipe de Lima Brito's avatar Filipe de Lima Brito

Add analytics.

parent c4f229fa
...@@ -165,10 +165,7 @@ dependencies { ...@@ -165,10 +165,7 @@ dependencies {
implementation libraries.glide implementation libraries.glide
implementation libraries.glideTransformations implementation libraries.glideTransformations
implementation(libraries.jitsi) { implementation(libraries.jitsi) { transitive = true }
transitive = true
exclude group: 'javax.servlet', module: 'http'
}
implementation 'com.google.code.findbugs:jsr305:3.0.2' implementation 'com.google.code.findbugs:jsr305:3.0.2'
......
...@@ -71,4 +71,13 @@ interface Analytics { ...@@ -71,4 +71,13 @@ interface Analytics {
* @param resetPasswordSucceeded True if successful reset password, false otherwise. * @param resetPasswordSucceeded True if successful reset password, false otherwise.
*/ */
fun logResetPassword(resetPasswordSucceeded: Boolean) {} fun logResetPassword(resetPasswordSucceeded: Boolean) {}
/**
* Logs the video conference event.
*
* @param event The [SubscriptionTypeEvent] to log.
* @param serverUrl The server URL to log.
*/
fun logVideoConference(event: SubscriptionTypeEvent, serverUrl: String) {}
} }
...@@ -76,4 +76,12 @@ class AnalyticsManager @Inject constructor( ...@@ -76,4 +76,12 @@ class AnalyticsManager @Inject constructor(
analytics.forEach { it.logResetPassword(resetPasswordSucceeded) } analytics.forEach { it.logResetPassword(resetPasswordSucceeded) }
} }
} }
fun logVideoConference(event: SubscriptionTypeEvent) {
if (analyticsTrackingInteractor.get() && serverUrl != null) {
analytics.forEach { it.logVideoConference(event, serverUrl) }
}
}
} }
...@@ -32,7 +32,6 @@ import chat.rocket.core.internal.rest.loginWithOauth ...@@ -32,7 +32,6 @@ import chat.rocket.core.internal.rest.loginWithOauth
import chat.rocket.core.internal.rest.loginWithSaml import chat.rocket.core.internal.rest.loginWithSaml
import chat.rocket.core.internal.rest.me import chat.rocket.core.internal.rest.me
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
private const val TYPE_LOGIN_OAUTH = 1 private const val TYPE_LOGIN_OAUTH = 1
......
...@@ -36,7 +36,10 @@ class ChatDetailsPresenter @Inject constructor( ...@@ -36,7 +36,10 @@ class ChatDetailsPresenter @Inject constructor(
} }
view.showFavoriteIcon(!isFavorite) view.showFavoriteIcon(!isFavorite)
} catch (e: RocketChatException) { } catch (e: RocketChatException) {
Timber.e(e, "Error while trying to favorite or removing the favorite of a chat room.") Timber.e(
e,
"Error while trying to favorite or removing the favorite of a chat room."
)
e.message?.let { e.message?.let {
view.showMessage(it) view.showMessage(it)
}.ifNull { }.ifNull {
...@@ -46,7 +49,8 @@ class ChatDetailsPresenter @Inject constructor( ...@@ -46,7 +49,8 @@ class ChatDetailsPresenter @Inject constructor(
} }
} }
fun toVideoConference(roomId: String) = navigator.toVideoConference(roomId) fun toVideoConference(roomId: String, chatRoomType: String) =
navigator.toVideoConference(roomId, chatRoomType)
fun getDetails(chatRoomId: String, chatRoomType: String) { fun getDetails(chatRoomId: String, chatRoomType: String) {
launchUI(strategy) { launchUI(strategy) {
...@@ -55,7 +59,7 @@ class ChatDetailsPresenter @Inject constructor( ...@@ -55,7 +59,7 @@ class ChatDetailsPresenter @Inject constructor(
client.getInfo(chatRoomId, null, roomTypeOf(chatRoomType)) client.getInfo(chatRoomId, null, roomTypeOf(chatRoomType))
} }
view.displayDetails(roomToChatDetails(room)) view.displayDetails(roomToChatDetails(room))
} catch(exception: Exception) { } catch (exception: Exception) {
Timber.e(exception) Timber.e(exception)
exception.message?.let { exception.message?.let {
view.showMessage(it) view.showMessage(it)
......
...@@ -47,6 +47,6 @@ internal fun ChatDetailsFragment.setOnMenuItemClickListener(item: MenuItem) { ...@@ -47,6 +47,6 @@ internal fun ChatDetailsFragment.setOnMenuItemClickListener(item: MenuItem) {
if (item.itemId == MENU_ACTION_FAVORITE_REMOVE_FAVORITE) { if (item.itemId == MENU_ACTION_FAVORITE_REMOVE_FAVORITE) {
presenter.toggleFavoriteChatRoom(chatRoomId, isFavorite) presenter.toggleFavoriteChatRoom(chatRoomId, isFavorite)
} else if (item.itemId == MENU_ACTION_VIDEO_CALL) { } else if (item.itemId == MENU_ACTION_VIDEO_CALL) {
presenter.toVideoConference(chatRoomId) presenter.toVideoConference(chatRoomId, chatRoomType)
} }
} }
...@@ -41,7 +41,11 @@ class ChatRoomAdapter( ...@@ -41,7 +41,11 @@ class ChatRoomAdapter(
actionsListener, actionsListener,
reactionListener, reactionListener,
{ userId -> navigator?.toUserDetails(userId) }, { userId -> navigator?.toUserDetails(userId) },
{ roomId?.let { navigator?.toVideoConference(it) } } {
if (roomId != null && roomType != null) {
navigator?.toVideoConference(roomId, roomType)
}
}
) )
} }
BaseUiModel.ViewType.URL_PREVIEW -> { BaseUiModel.ViewType.URL_PREVIEW -> {
......
...@@ -23,8 +23,8 @@ class ChatRoomNavigator(internal val activity: ChatRoomActivity) { ...@@ -23,8 +23,8 @@ class ChatRoomNavigator(internal val activity: ChatRoomActivity) {
} }
} }
fun toVideoConference(chatRoomId: String) { fun toVideoConference(chatRoomId: String, chatRoomType: String) {
activity.startActivity(activity.videoConferenceIntent(chatRoomId)) activity.startActivity(activity.videoConferenceIntent(chatRoomId, chatRoomType))
} }
fun toChatRoom( fun toChatRoom(
......
...@@ -131,7 +131,7 @@ class UserDetailsPresenter @Inject constructor( ...@@ -131,7 +131,7 @@ class UserDetailsPresenter @Inject constructor(
val directMessage = retryIO("createDirectMessage($username") { val directMessage = retryIO("createDirectMessage($username") {
client.createDirectMessage(username) client.createDirectMessage(username)
} }
navigator.toVideoConference(directMessage.id) navigator.toVideoConference(directMessage.id, RoomType.DIRECT_MESSAGE)
} }
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.e(ex) Timber.e(ex)
......
package chat.rocket.android.videoconference.presenter package chat.rocket.android.videoconference.presenter
import chat.rocket.android.analytics.AnalyticsManager
import chat.rocket.android.analytics.event.SubscriptionTypeEvent
import chat.rocket.android.core.lifecycle.CancelStrategy import chat.rocket.android.core.lifecycle.CancelStrategy
import chat.rocket.android.helper.JitsiHelper import chat.rocket.android.helper.JitsiHelper
import chat.rocket.android.helper.UserHelper import chat.rocket.android.helper.UserHelper
import chat.rocket.android.server.domain.* import chat.rocket.android.server.domain.*
import chat.rocket.android.server.infraestructure.ConnectionManagerFactory import chat.rocket.android.server.infraestructure.ConnectionManagerFactory
import chat.rocket.android.util.extension.launchUI import chat.rocket.android.util.extension.launchUI
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf
import chat.rocket.core.RocketChatClient import chat.rocket.core.RocketChatClient
import chat.rocket.core.internal.rest.updateJitsiTimeout import chat.rocket.core.internal.rest.updateJitsiTimeout
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
...@@ -22,19 +26,22 @@ class VideoConferencePresenter @Inject constructor( ...@@ -22,19 +26,22 @@ class VideoConferencePresenter @Inject constructor(
private val currentServerRepository: CurrentServerRepository, private val currentServerRepository: CurrentServerRepository,
private val connectionManagerFactory: ConnectionManagerFactory, private val connectionManagerFactory: ConnectionManagerFactory,
private val settings: GetSettingsInteractor, private val settings: GetSettingsInteractor,
private val userHelp: UserHelper private val userHelp: UserHelper,
private val analyticsManager: AnalyticsManager
) { ) {
private lateinit var client: RocketChatClient private lateinit var client: RocketChatClient
private lateinit var publicSettings: PublicSettings private lateinit var publicSettings: PublicSettings
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
private lateinit var chatRoomType: String
private lateinit var timer: Timer private lateinit var timer: Timer
fun setup(chatRoomId: String) { fun setup(chatRoomId: String, chatRoomType: String) {
currentServerRepository.get()?.let { currentServerRepository.get()?.let {
client = connectionManagerFactory.create(it).client client = connectionManagerFactory.create(it).client
publicSettings = settings.get(it) publicSettings = settings.get(it)
} }
this.chatRoomId = chatRoomId this.chatRoomId = chatRoomId
this.chatRoomType = chatRoomType
} }
fun initVideoConference() { fun initVideoConference() {
...@@ -53,6 +60,7 @@ class VideoConferencePresenter @Inject constructor( ...@@ -53,6 +60,7 @@ class VideoConferencePresenter @Inject constructor(
) )
updateJitsiTimeout() updateJitsiTimeout()
logVideoConferenceEvent()
} }
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.e(ex) Timber.e(ex)
...@@ -71,5 +79,13 @@ class VideoConferencePresenter @Inject constructor( ...@@ -71,5 +79,13 @@ class VideoConferencePresenter @Inject constructor(
} }
} }
} }
private fun logVideoConferenceEvent() = when {
roomTypeOf(chatRoomType) is RoomType.DirectMessage ->
analyticsManager.logVideoConference(SubscriptionTypeEvent.DirectMessage)
roomTypeOf(chatRoomType) is RoomType.Channel ->
analyticsManager.logVideoConference(SubscriptionTypeEvent.Channel)
else -> analyticsManager.logVideoConference(SubscriptionTypeEvent.Group)
}
} }
...@@ -13,16 +13,20 @@ import org.jitsi.meet.sdk.JitsiMeetViewListener ...@@ -13,16 +13,20 @@ import org.jitsi.meet.sdk.JitsiMeetViewListener
import timber.log.Timber import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
fun Context.videoConferenceIntent(chatRoomId: String): Intent = fun Context.videoConferenceIntent(chatRoomId: String, chatRoomType: String): Intent =
Intent(this, VideoConferenceActivity::class.java).putExtra(INTENT_CHAT_ROOM_ID, chatRoomId) Intent(this, VideoConferenceActivity::class.java)
.putExtra(INTENT_CHAT_ROOM_ID, chatRoomId)
.putExtra(INTENT_CHAT_ROOM_TYPE, chatRoomType)
private const val INTENT_CHAT_ROOM_ID = "chat_room_id" private const val INTENT_CHAT_ROOM_ID = "chat_room_id"
private const val INTENT_CHAT_ROOM_TYPE = "chat_room_type"
class VideoConferenceActivity : JitsiMeetActivity(), JitsiVideoConferenceView, class VideoConferenceActivity : JitsiMeetActivity(), JitsiVideoConferenceView,
JitsiMeetViewListener { JitsiMeetViewListener {
@Inject @Inject
lateinit var presenter: VideoConferencePresenter lateinit var presenter: VideoConferencePresenter
private lateinit var chatRoomId: String private lateinit var chatRoomId: String
private lateinit var chatRoomType: String
private var view: JitsiMeetView? = null private var view: JitsiMeetView? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
...@@ -31,12 +35,14 @@ class VideoConferenceActivity : JitsiMeetActivity(), JitsiVideoConferenceView, ...@@ -31,12 +35,14 @@ class VideoConferenceActivity : JitsiMeetActivity(), JitsiVideoConferenceView,
chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID) chatRoomId = intent.getStringExtra(INTENT_CHAT_ROOM_ID)
requireNotNull(chatRoomId) { "no chat_room_id provided in Intent extras" } requireNotNull(chatRoomId) { "no chat_room_id provided in Intent extras" }
chatRoomType = intent.getStringExtra(INTENT_CHAT_ROOM_TYPE)
requireNotNull(chatRoomType) { "no chat_room_type provided in Intent extras" }
view = JitsiMeetView(this) view = JitsiMeetView(this)
view?.listener = this view?.listener = this
setContentView(view) setContentView(view)
presenter.setup(chatRoomId) presenter.setup(chatRoomId, chatRoomType)
presenter.initVideoConference() presenter.initVideoConference()
} }
......
...@@ -74,4 +74,13 @@ class AnswersAnalytics : Analytics { ...@@ -74,4 +74,13 @@ class AnswersAnalytics : Analytics {
CustomEvent("reset_password") CustomEvent("reset_password")
.putCustomAttribute("resetPasswordSucceeded", resetPasswordSucceeded.toString()) .putCustomAttribute("resetPasswordSucceeded", resetPasswordSucceeded.toString())
) )
override fun logMessageSent(event: SubscriptionTypeEvent, serverUrl: String) =
Answers.getInstance()
.logCustom(
CustomEvent("video_conference")
.putCustomAttribute("subscription_type", event.subscriptionTypeName)
.putCustomAttribute("server", serverUrl)
)
} }
...@@ -13,14 +13,14 @@ class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) : ...@@ -13,14 +13,14 @@ class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) :
private val firebaseAnalytics = FirebaseAnalytics.getInstance(context) private val firebaseAnalytics = FirebaseAnalytics.getInstance(context)
override fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) { override fun logLogin(event: AuthenticationEvent, loginSucceeded: Boolean) {
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle(1).apply { firebaseAnalytics.logEvent(FirebaseAnalytics.Event.LOGIN, Bundle(2).apply {
putString(FirebaseAnalytics.Param.METHOD, event.methodName) putString(FirebaseAnalytics.Param.METHOD, event.methodName)
putLong(FirebaseAnalytics.Param.SUCCESS, if (loginSucceeded) 1 else 0) putLong(FirebaseAnalytics.Param.SUCCESS, if (loginSucceeded) 1 else 0)
}) })
} }
override fun logSignUp(event: AuthenticationEvent, signUpSucceeded: Boolean) { override fun logSignUp(event: AuthenticationEvent, signUpSucceeded: Boolean) {
firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SIGN_UP, Bundle(1).apply { firebaseAnalytics.logEvent(FirebaseAnalytics.Event.SIGN_UP, Bundle(2).apply {
putString(FirebaseAnalytics.Param.METHOD, event.methodName) putString(FirebaseAnalytics.Param.METHOD, event.methodName)
putLong(FirebaseAnalytics.Param.SUCCESS, if (signUpSucceeded) 1 else 0) putLong(FirebaseAnalytics.Param.SUCCESS, if (signUpSucceeded) 1 else 0)
}) })
...@@ -33,27 +33,27 @@ class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) : ...@@ -33,27 +33,27 @@ class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) :
} }
override fun logMessageSent(event: SubscriptionTypeEvent, serverUrl: String) { override fun logMessageSent(event: SubscriptionTypeEvent, serverUrl: String) {
firebaseAnalytics.logEvent("message_sent", Bundle(1).apply { firebaseAnalytics.logEvent("message_sent", Bundle(2).apply {
putString("subscription_type", event.subscriptionTypeName) putString("subscription_type", event.subscriptionTypeName)
putString("server", serverUrl) putString("server", serverUrl)
}) })
} }
override fun logMediaUploaded(event: SubscriptionTypeEvent, mimeType: String) { override fun logMediaUploaded(event: SubscriptionTypeEvent, mimeType: String) {
firebaseAnalytics.logEvent("media_upload", Bundle(1).apply { firebaseAnalytics.logEvent("media_upload", Bundle(2).apply {
putString("subscription_type", event.subscriptionTypeName) putString("subscription_type", event.subscriptionTypeName)
putString("media_type", mimeType) putString("media_type", mimeType)
}) })
} }
override fun logReaction(event: SubscriptionTypeEvent) { override fun logReaction(event: SubscriptionTypeEvent) {
firebaseAnalytics.logEvent("reaction", Bundle(1).apply { firebaseAnalytics.logEvent("reaction", Bundle(2).apply {
putString("subscription_type", event.subscriptionTypeName) putString("subscription_type", event.subscriptionTypeName)
}) })
} }
override fun logServerSwitch(serverUrl: String, serverCount: Int) { override fun logServerSwitch(serverUrl: String, serverCount: Int) {
firebaseAnalytics.logEvent("server_switch", Bundle(1).apply { firebaseAnalytics.logEvent("server_switch", Bundle(2).apply {
putString("server_url", serverUrl) putString("server_url", serverUrl)
putInt("server_count", serverCount) putInt("server_count", serverCount)
}) })
...@@ -62,7 +62,14 @@ class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) : ...@@ -62,7 +62,14 @@ class GoogleAnalyticsForFirebase @Inject constructor(val context: Context) :
override fun logOpenAdmin() = firebaseAnalytics.logEvent("open_admin", null) override fun logOpenAdmin() = firebaseAnalytics.logEvent("open_admin", null)
override fun logResetPassword(resetPasswordSucceeded: Boolean) = override fun logResetPassword(resetPasswordSucceeded: Boolean) =
firebaseAnalytics.logEvent("reset_password", Bundle(1).apply { firebaseAnalytics.logEvent("reset_password", Bundle(2).apply {
putBoolean("resetPasswordSucceeded", resetPasswordSucceeded) putBoolean("resetPasswordSucceeded", resetPasswordSucceeded)
}) })
override fun logVideoConference(event: SubscriptionTypeEvent, serverUrl: String) {
firebaseAnalytics.logEvent("video_conference", Bundle(2).apply {
putString("subscription_type", event.subscriptionTypeName)
putString("server", serverUrl)
})
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment