Skip to content

Commit

Permalink
finish analytics rework
Browse files Browse the repository at this point in the history
  • Loading branch information
phillipthelen committed Aug 4, 2023
1 parent 7de9a8f commit c630aa6
Show file tree
Hide file tree
Showing 24 changed files with 134 additions and 135 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import com.habitrpg.android.habitica.models.inventory.QuestContent
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
import com.habitrpg.common.habitica.api.HostConfig
import com.habitrpg.common.habitica.helpers.AnalyticsManager
import com.habitrpg.common.habitica.helpers.ExceptionHandler
import com.kaspersky.kaspresso.testcases.api.testcase.TestCase
import io.mockk.clearAllMocks
Expand Down Expand Up @@ -61,7 +60,6 @@ open class HabiticaTestCase : TestCase() {
val soundManager: SoundManager = mockk(relaxed = true)
val notificationsManager: NotificationsManager = mockk(relaxed = true)
val hostConfig: HostConfig = mockk(relaxed = true)
val analyticsManager: AnalyticsManager = mockk(relaxed = true)
val maintenanceService: MaintenanceApiService = mockk(relaxed = true)
val tagRepository: TagRepository = mockk(relaxed = true)
val hatchPetUseCase: HatchPetUseCase = mockk(relaxed = true)
Expand Down Expand Up @@ -126,7 +124,6 @@ open class HabiticaTestCase : TestCase() {
if (it.returnType == SharedPreferences::class.starProjectedType) assign(it, obj, sharedPreferences)
if (it.returnType == NotificationsManager::class.starProjectedType) assign(it, obj, notificationsManager)
if (it.returnType == HostConfig::class.starProjectedType) assign(it, obj, hostConfig)
if (it.returnType == AnalyticsManager::class.starProjectedType) assign(it, obj, analyticsManager)
if (it.returnType == MaintenanceApiService::class.starProjectedType) assign(it, obj, maintenanceService)
if (it.returnType == TagRepository::class.starProjectedType) assign(it, obj, tagRepository)
if (it.returnType == FeedPetUseCase::class.starProjectedType) assign(it, obj, feedPetUseCase)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,19 @@ import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.OnLifecycleEvent
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.preference.PreferenceManager
import com.google.android.gms.wearable.Wearable
import com.google.firebase.installations.FirebaseInstallations
import com.google.firebase.remoteconfig.FirebaseRemoteConfig
import com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings
import com.habitrpg.android.habitica.data.ApiClient
import com.habitrpg.android.habitica.extensions.DateUtils
import com.habitrpg.android.habitica.helpers.AdHandler
import com.habitrpg.android.habitica.helpers.Analytics
import com.habitrpg.android.habitica.helpers.notifications.PushNotificationManager
Expand All @@ -31,7 +38,6 @@ import com.habitrpg.android.habitica.ui.activities.BaseActivity
import com.habitrpg.android.habitica.ui.activities.LoginActivity
import com.habitrpg.android.habitica.ui.views.HabiticaIconsHelper
import com.habitrpg.common.habitica.extensions.setupCoil
import com.habitrpg.common.habitica.helpers.AnalyticsManager
import com.habitrpg.common.habitica.helpers.ExceptionHandler
import com.habitrpg.common.habitica.helpers.LanguageHelper
import com.habitrpg.common.habitica.helpers.MarkdownParser
Expand All @@ -41,8 +47,52 @@ import io.realm.Realm
import io.realm.RealmConfiguration
import kotlinx.coroutines.MainScope
import java.lang.ref.WeakReference
import java.util.Date
import javax.inject.Inject

class ApplicationLifecycleTracker(private val sharedPreferences: SharedPreferences): DefaultLifecycleObserver {
private var lastResumeTime = 0L
override fun onResume(owner : LifecycleOwner) {
super.onResume(owner)
lastResumeTime = Date().time
}

override fun onPause(owner : LifecycleOwner) {
super.onPause(owner)
val duration = Date().time - lastResumeTime
addDurationToDay(duration / 1000)
}

private fun addDurationToDay(duration: Long) {
var currentTotal = sharedPreferences.getLong("usage_time_total", 0L)
currentTotal += duration
var currentDay = Date()
if (sharedPreferences.contains("usage_time_day")) {
currentDay = Date(sharedPreferences.getLong("usage_time_day", 0L))
}
var current = sharedPreferences.getLong("usage_time_current", 0L)
if (!DateUtils.isSameDay(currentDay, Date())) {
var average = sharedPreferences.getLong("usage_time_daily_average", 0L)
var observedDays = sharedPreferences.getInt("usage_time_day_count", 0)
average = ((average * observedDays) + current) / (observedDays + 1)
sharedPreferences.edit {
putInt("usage_time_day_count", ++observedDays)
putLong("usage_time_daily_average", average)
}
Analytics.setUserProperty("usage_time_daily_average", average)
Analytics.setUserProperty("usage_time_total", currentTotal)
current = 0
currentDay = Date()
}
current += duration
sharedPreferences.edit {
putLong("usage_time_current", current)
putLong("usage_time_total", currentTotal)
putLong("usage_time_day", currentDay.time)
}
}
}

@HiltAndroidApp
abstract class HabiticaBaseApplication : Application(), Application.ActivityLifecycleCallbacks {
@Inject
Expand All @@ -51,22 +101,24 @@ abstract class HabiticaBaseApplication : Application(), Application.ActivityLife
@Inject
internal lateinit var sharedPrefs: SharedPreferences

@Inject
internal lateinit var analyticsManager: AnalyticsManager

@Inject
internal lateinit var pushNotificationManager: PushNotificationManager

@Inject
internal lateinit var authenticationHandler: AuthenticationHandler

private lateinit var lifecycleTracker: ApplicationLifecycleTracker

/**
* For better performance billing class should be used as singleton
*/
// endregion

override fun onCreate() {
super.onCreate()
lifecycleTracker = ApplicationLifecycleTracker(sharedPrefs)
ProcessLifecycleOwner.get().lifecycle.addObserver(lifecycleTracker);

if (!BuildConfig.DEBUG) {
try {
Analytics.initialize(this)
Expand Down Expand Up @@ -96,8 +148,9 @@ abstract class HabiticaBaseApplication : Application(), Application.ActivityLife
checkIfNewVersion()
}


private fun setupAdHandler() {
AdHandler.setup(sharedPrefs, analyticsManager)
AdHandler.setup(sharedPrefs)
}

private fun setLocale() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ import com.habitrpg.android.habitica.models.user.Stats
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.common.habitica.api.HostConfig
import com.habitrpg.common.habitica.api.Server
import com.habitrpg.common.habitica.helpers.AnalyticsManager
import com.habitrpg.common.habitica.models.HabitResponse
import com.habitrpg.common.habitica.models.PurchaseValidationRequest
import com.habitrpg.common.habitica.models.PurchaseValidationResult
Expand Down Expand Up @@ -73,7 +72,6 @@ import javax.net.ssl.SSLException
class ApiClientImpl(
private val converter: Converter.Factory,
override val hostConfig: HostConfig,
private val analyticsManager: AnalyticsManager,
private val notificationsManager: NotificationsManager,
private val context: Context
) : ApiClient {
Expand Down Expand Up @@ -104,7 +102,6 @@ class ApiClientImpl(
private var hadError = false

init {
Analytics.setUserID(this.hostConfig.userID)
buildRetrofit()
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.habitrpg.android.habitica.data.implementation

import androidx.core.os.bundleOf
import com.habitrpg.android.habitica.data.ApiClient
import com.habitrpg.android.habitica.data.TaskRepository
import com.habitrpg.android.habitica.data.local.TaskLocalRepository
import com.habitrpg.android.habitica.helpers.Analytics
import com.habitrpg.android.habitica.helpers.AppConfigManager
import com.habitrpg.android.habitica.helpers.EventCategory
import com.habitrpg.android.habitica.helpers.HitType
import com.habitrpg.android.habitica.interactors.ScoreTaskLocallyInteractor
import com.habitrpg.android.habitica.models.BaseMainObject
import com.habitrpg.android.habitica.models.responses.BulkTaskScoringData
Expand All @@ -15,7 +16,6 @@ import com.habitrpg.android.habitica.models.tasks.TaskList
import com.habitrpg.android.habitica.models.user.OwnedItem
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.modules.AuthenticationHandler
import com.habitrpg.common.habitica.helpers.AnalyticsManager
import com.habitrpg.common.habitica.helpers.launchCatching
import com.habitrpg.shared.habitica.models.responses.TaskDirection
import com.habitrpg.shared.habitica.models.responses.TaskDirectionData
Expand All @@ -39,7 +39,6 @@ class TaskRepositoryImpl(
apiClient: ApiClient,
authenticationHandler: AuthenticationHandler,
val appConfigManager: AppConfigManager,
val analyticsManager: AnalyticsManager
) : BaseRepositoryImpl<TaskLocalRepository>(localRepository, apiClient, authenticationHandler), TaskRepository {
private var lastTaskAction: Long = 0

Expand Down Expand Up @@ -102,12 +101,14 @@ class TaskRepositoryImpl(
val thisUser = user ?: localRepository.getUser(authenticationHandler.currentUserID ?: "").firstOrNull() ?: return null
// save local task changes

Analytics.logEvent(
Analytics.sendEvent(
"task_scored",
bundleOf(
Pair("type", task.type),
Pair("scored_up", up),
Pair("value", task.value)
EventCategory.BEHAVIOUR,
HitType.EVENT,
mapOf(
"type" to (task.type ?: ""),
"scored_up" to up,
"value" to task.value
)
)
if (res.lvl == 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import com.habitrpg.android.habitica.models.user.Stats
import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.models.user.UserQuestStatus
import com.habitrpg.android.habitica.modules.AuthenticationHandler
import com.habitrpg.common.habitica.helpers.AnalyticsManager
import com.habitrpg.common.habitica.models.Notification
import com.habitrpg.common.habitica.models.notifications.NewStuffData
import com.habitrpg.shared.habitica.models.responses.TaskDirection
Expand All @@ -41,7 +40,6 @@ class UserRepositoryImpl(
authenticationHandler: AuthenticationHandler,
private val taskRepository: TaskRepository,
private val appConfigManager: AppConfigManager,
private val analyticsManager: AnalyticsManager
) : BaseRepositoryImpl<UserLocalRepository>(localRepository, apiClient, authenticationHandler), UserRepository {

companion object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ class DateUtils {
cal.set(Calendar.MILLISECOND, 0)
return cal.time
}

fun isSameDay(date1 : Date, date2 : Date) : Boolean {
val cal1 = Calendar.getInstance()
val cal2 = Calendar.getInstance()
cal1.time = date1
cal2.time = date2
return cal1[Calendar.DAY_OF_YEAR] == cal2[Calendar.DAY_OF_YEAR] &&
cal1[Calendar.YEAR] == cal2[Calendar.YEAR]
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback
import com.google.firebase.analytics.FirebaseAnalytics
import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.habitrpg.android.habitica.BuildConfig
import com.habitrpg.common.habitica.helpers.AnalyticsManager
import java.io.UnsupportedEncodingException
import java.security.MessageDigest
import java.util.Date
Expand Down Expand Up @@ -75,7 +74,6 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo
DISABLED
}

private lateinit var analyticsManager: AnalyticsManager
private lateinit var sharedPreferences: SharedPreferences
const val TAG = "AdHandler"

Expand Down Expand Up @@ -144,9 +142,8 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo
}
}

fun setup(sharedPrefs: SharedPreferences, analyticsManager: AnalyticsManager) {
fun setup(sharedPrefs: SharedPreferences) {
this.sharedPreferences = sharedPrefs
this.analyticsManager = analyticsManager

for (type in AdType.values()) {
val time = sharedPrefs.getLong("nextAd${type.name}", 0)
Expand Down Expand Up @@ -228,10 +225,12 @@ class AdHandler(val activity: Activity, val type: AdType, val rewardAction: (Boo
}

override fun onUserEarnedReward(rewardItem: RewardItem) {
analyticsManager.logEvent(
Analytics.sendEvent(
"adRewardEarned",
bundleOf(
Pair("type", type.name)
EventCategory.BEHAVIOUR,
HitType.EVENT,
mapOf(
"type" to type.name
)
)
FirebaseAnalytics.getInstance(activity).logEvent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,15 @@ object Analytics {
data.putAll(additionalData)
}
if (eventAction != null) {
if (target == null || target == AnalyticsTarget.AMPLITUDE) {
amplitude.track(eventAction, data)
if (this::amplitude.isInitialized) {
if (target == null || target == AnalyticsTarget.AMPLITUDE) {
amplitude.track(eventAction, data)
}
}
if (target == null || target == AnalyticsTarget.FIREBASE) {
firebase.logEvent(eventAction, bundleOf(*data.toList().toTypedArray()))
if (this::firebase.isInitialized) {
if (target == null || target == AnalyticsTarget.FIREBASE) {
firebase.logEvent(eventAction, bundleOf(*data.toList().toTypedArray()))
}
}
}
}
Expand All @@ -85,17 +89,28 @@ object Analytics {
sharedPrefs.getString("launch_screen", "")?.let {
identify.set("launch_screen", it)
}
amplitude.identify(identify)
if (this::amplitude.isInitialized) {
amplitude.identify(identify)
}
}

fun setUserID(userID: String) {
amplitude.setUserId(userID)
if (this::amplitude.isInitialized) {
amplitude.setUserId(userID)
}
FirebaseCrashlytics.getInstance().setUserId(userID)
firebase.setUserId(userID)
if (this::firebase.isInitialized) {
firebase.setUserId(userID)
}
}

fun setUserProperty(identifier: String, value: String) {
firebase.setUserProperty(identifier, value)
fun setUserProperty(identifier: String, value: Any?) {
if (this::amplitude.isInitialized) {
amplitude.identify(mapOf(identifier to value))
}
if (this::firebase.isInitialized) {
firebase.setUserProperty(identifier, value?.toString())
}
}

fun logError(msg: String) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.app.Activity
import android.content.Context
import android.content.SharedPreferences
import androidx.core.content.edit
import androidx.core.os.bundleOf
import androidx.lifecycle.asFlow
import com.android.billingclient.api.AcknowledgePurchaseParams
import com.android.billingclient.api.BillingClient
Expand Down Expand Up @@ -32,7 +31,6 @@ import com.habitrpg.android.habitica.models.user.User
import com.habitrpg.android.habitica.ui.activities.PurchaseActivity
import com.habitrpg.android.habitica.ui.viewmodels.MainUserViewModel
import com.habitrpg.android.habitica.ui.views.dialogs.HabiticaAlertDialog
import com.habitrpg.common.habitica.helpers.AnalyticsManager
import com.habitrpg.common.habitica.helpers.ExceptionHandler
import com.habitrpg.common.habitica.helpers.launchCatching
import com.habitrpg.common.habitica.models.IAPGift
Expand All @@ -55,7 +53,6 @@ import kotlin.time.toDuration

class PurchaseHandler(
private val context: Context,
private val analyticsManager: AnalyticsManager,
private val apiClient: ApiClient,
private val userViewModel: MainUserViewModel
) : PurchasesUpdatedListener, PurchasesResponseListener {
Expand Down Expand Up @@ -349,7 +346,7 @@ class PurchaseHandler(
try {
apiClient.validateSubscription(validationRequest)
processedPurchase(purchase)
Analytics.sendEvent("user_subscribed", bundleOf(Pair("sku", sku)))
Analytics.sendEvent("user_subscribed", EventCategory.BEHAVIOUR, HitType.EVENT, mapOf("sku" to (sku ?: "")))
CoroutineScope(Dispatchers.IO).launch(ExceptionHandler.coroutine()) {
acknowledgePurchase(purchase)
}
Expand Down
Loading

0 comments on commit c630aa6

Please sign in to comment.