Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Added Matomo analytics tracking #684

Merged
merged 2 commits into from
Jan 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,8 @@ dependencies {

implementation 'io.sentry:sentry-android:5.1.2'

implementation 'com.github.matomo-org:matomo-sdk-android:4.1.4'

annotationProcessor "org.androidannotations:androidannotations:$androidAnnotationsVersion"
kapt 'com.github.bumptech.glide:compiler:4.7.1'
implementation("org.androidannotations:androidannotations-api:$androidAnnotationsVersion")
Expand Down
4 changes: 2 additions & 2 deletions android/app/libs/liblantern-all.aar
Git LFS file not shown
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.matomo.sdk.Matomo;
import org.matomo.sdk.Tracker;
import org.matomo.sdk.TrackerBuilder;

import java.io.IOException;
import java.net.InetSocketAddress;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,18 @@ package org.getlantern.lantern.activity
import android.os.Bundle
import android.view.WindowManager
import androidx.fragment.app.FragmentActivity
import org.getlantern.lantern.util.Analytics

abstract class BaseFragmentActivity : FragmentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// prevent screenshots of this activity by other apps
window.addFlags(WindowManager.LayoutParams.FLAG_SECURE)
}

override fun onResume() {
super.onResume()
// track the screen view
Analytics.screen(this, this)
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package org.getlantern.lantern.activity;

import android.content.Intent;
import android.os.Bundle;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.ForegroundColorSpan;
import android.view.View;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;

import com.google.gson.JsonObject;
import okhttp3.HttpUrl;
import okhttp3.Response;
Expand All @@ -22,7 +21,7 @@
import org.getlantern.lantern.model.*;
import org.getlantern.lantern.util.ActivityExtKt;
import org.getlantern.lantern.util.DateUtil;
import org.getlantern.mobilesdk.Lantern;
import org.getlantern.lantern.util.Analytics;
import org.getlantern.mobilesdk.Logger;
import org.joda.time.LocalDateTime;

Expand Down Expand Up @@ -98,7 +97,7 @@ private void initViews() {
}

private void sendScreenViewEvent() {
Lantern.sendEvent(this, "plans_view");
Analytics.event(this, Analytics.CATEGORY_PURCHASING, "plans_view");
}

protected void setPaymentGateway() {
Expand Down Expand Up @@ -220,10 +219,13 @@ private void selectPlan(View view) {
final String planId = (String) view.getTag();
Logger.debug(TAG, "Plan selected: " + planId);

final Bundle params = new Bundle();
params.putString("plan_id", planId);
params.putString("app_version", Utils.appVersion(this));
Lantern.sendEvent(this, "plan_selected", params);
final Map<Integer, String> params = new HashMap<>();
params.put(Analytics.DIMENSION_PLAN_ID, planId);
Analytics.event(
this,
Analytics.CATEGORY_PURCHASING,
"plan_selected",
params);

LanternApp.getSession().setProPlan(plans.get(planId));
startActivity(new Intent(this, CheckoutActivity_.class));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import android.app.ProgressDialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;

import androidx.annotation.NonNull;
Expand All @@ -16,7 +15,7 @@
import org.getlantern.lantern.activity.WelcomeActivity_;
import org.getlantern.lantern.service.BackgroundChecker_;
import org.getlantern.lantern.util.ActivityExtKt;
import org.getlantern.mobilesdk.Lantern;
import org.getlantern.lantern.util.Analytics;
import org.getlantern.mobilesdk.Logger;

import okhttp3.FormBody;
Expand Down Expand Up @@ -164,35 +163,14 @@ public static void sendPurchaseEvent(final Context context,
return;
}

final Bundle params = new Bundle();
// the currency and value fields are firebase specific.
// they are always logged using the USD price because firebase
// does not support all currencies in use (ie no Iranian Rial)
params.putString("currency", "USD");
Long usdPrice = plan.getUSDEquivalentPrice();
if (usdPrice != null) {
params.putFloat("value", (float) (usdPrice / 100.0));
}
else {
Logger.error(TAG, "Missing USD equivalent price for plan " + plan.getId());
params.putFloat("value", (float) 0.0);
}

// original_currency/value indicate the true amount paid by the user
params.putFloat("original_value", (float) (LanternApp.getSession().getSelectedPlanCost() / 100.0));
params.putString("original_currency", LanternApp.getSession().getSelectedPlanCurrency());
params.putString("plan", plan.getId());
params.putString("provider", provider);
params.putString("country", LanternApp.getSession().getCountryCode());

if (error == null) {
// The 'ecommerce_purchase' event type is a specific event type
// understood by firebase.
Lantern.sendEvent(context, "ecommerce_purchase", params);
} else {
params.putString("error", error);
Lantern.sendEvent(context, "purchase_error", params);
if (error != null) {
Logger.error(TAG, "Encountered error, not logging purchase event", error);
return;
}
Analytics.purchase(
context,
provider,
plan);
}

}
108 changes: 108 additions & 0 deletions android/app/src/main/java/org/getlantern/lantern/util/Analytics.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package org.getlantern.lantern.util;

import android.app.Activity;
import android.content.Context;

import org.getlantern.lantern.LanternApp;
import org.getlantern.lantern.model.ProPlan;
import org.getlantern.lantern.model.Utils;
import org.matomo.sdk.Tracker;
import org.matomo.sdk.TrackerBuilder;
import org.matomo.sdk.extra.EcommerceItems;
import org.matomo.sdk.extra.TrackHelper;

import java.util.Map;

/**
* Provides a facility for tracking activity in Matomo.
*/
public class Analytics {
public static final String CATEGORY_PURCHASING = "purchasing";
public static final String CATEGORY_SESSION = "session";

/**
* The below custom dimensions are defined in Matomo and the IDs have to match what's defined there.
**/
public static final int DIMENSION_PLAN_ID = 1;
public static final int DIMENSION_PROVIDER = 2;
public static final int DIMENSION_COUNTRY = 3;
public static final int DIMENSION_APP_VERSION = 4;

private static org.matomo.sdk.Tracker tracker;

synchronized private static org.matomo.sdk.Tracker getTracker(Context context) {
if (tracker == null) {
tracker = TrackerBuilder
.createDefault("https://matomo.128.network/matomo.php", 1)
.build(org.matomo.sdk.Matomo.getInstance(context));
track(context).download().with(tracker);
}
tracker.setOptOut(!LanternApp.getSession().matomoEnabled());
return tracker;
}

public static void screen(
final Context context,
final Activity activity) {
track(context).screen(activity).with(getTracker(context));
}

public static void screen(
final Context context,
final String path) {
track(context).screen(path).with(getTracker(context));
}

/**
* Sends a custom matomo event
*
* @param context application context
* @param category the event category
* @param name the event type
* @param dimensions dimensions to associate with event
*/
public static void event(
final Context context,
final String category,
final String name,
Map<Integer, String> dimensions) {
TrackHelper helper = track(context);
if (dimensions != null) {
for (Map.Entry<Integer, String> dimension : dimensions.entrySet()) {
helper.dimension(dimension.getKey(), dimension.getValue());
}
}
Tracker tracker = getTracker(context);
helper.event(category, name).with(tracker);
tracker.dispatch(); // immediately dispatch
}

public static void event(
final Context context,
final String category,
final String name) {
event(context, category, name, null);
}

public static void purchase(
final Context context,
final String provider,
ProPlan plan) {
TrackHelper helper = track(context);
EcommerceItems items = new EcommerceItems();
EcommerceItems.Item item =
new EcommerceItems.Item(plan.getId()).price(plan.getCurrencyPrice().intValue());
helper.cartUpdate(plan.getUSDEquivalentPrice().intValue()).items(items);
helper.dimension(DIMENSION_PROVIDER, provider);
Tracker tracker = getTracker(context);
helper.event(CATEGORY_PURCHASING, "purchase").with(tracker);
tracker.dispatch(); // immediately dispatch
}

private static TrackHelper track(Context context) {
TrackHelper helper = TrackHelper.track();
helper.dimension(DIMENSION_COUNTRY, LanternApp.getSession().getCountryCode());
helper.dimension(DIMENSION_APP_VERSION, Utils.appVersion(context));
return helper;
}
}
44 changes: 6 additions & 38 deletions android/app/src/main/java/org/getlantern/mobilesdk/Lantern.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

import android.content.Context;
import android.content.res.AssetManager;
import android.os.Bundle;

import org.getlantern.lantern.util.Analytics;

import java.io.BufferedReader;
import java.io.File;
Expand Down Expand Up @@ -141,45 +142,12 @@ public static void disable(final Context context) {
}

private static void trackStartSession(final Context context) {
sendSessionEvent(context, "Start");
}

private static void sendSessionEvent(
final Context context,
final String action) {
Bundle params = new Bundle();
params.putString("category", "Session");
params.putString("label", "android");
params.putString("action", action);
sendEvent(context, "proxy_session", params);
Analytics.event(
context,
Analytics.CATEGORY_SESSION,
"start");
}

/**
* Sends a custom firebase analytics event.
* Note: there is limit of 500 event types (names) per application.
*
* TODO: this has been disabled and will need to be migrated to Matomo.
*
* @param context application context
* @param name the event type
* @param params event fields (limit of 25)
*/
public static void sendEvent(final Context context, final String name, Bundle params) {
// FirebaseAnalytics.getInstance(context).logEvent(name, params);
}

/**
* Sends a custom firebase analytics event.
* Note: there is limit of 500 event types (names) per application.
*
* @param context application context
* @param name the event type
*/
public static void sendEvent(final Context context, final String name) {
sendEvent(context, name, null);
}


/**
* Prints the contents of file to logcat.
* Used for debugging purposes.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,14 @@ abstract class SessionManager(application: Application) : Session {
prefs.edit().putBoolean(CHAT_ENABLED, isDevMode ?: enabled).apply()
}

override fun setMatomoEnabled(enabled: Boolean) {
val isDevMode = prefs.getBoolean("DEVELOPMENT_MODE", BuildConfig.DEVELOPMENT_MODE)
Logger.d(TAG, "Setting $MATOMO_ENABLED to ${isDevMode ?: enabled}")
prefs.edit().putBoolean(MATOMO_ENABLED, isDevMode ?: enabled).apply()
}

fun matomoEnabled(): Boolean = prefs.getBoolean(MATOMO_ENABLED, false);

override fun appVersion(): String {
return appVersion
}
Expand Down Expand Up @@ -448,6 +456,7 @@ abstract class SessionManager(application: Application) : Session {

private const val REPLICA_ADDR = "replicaAddr"
private const val CHAT_ENABLED = "chatEnabled"
private const val MATOMO_ENABLED = "matomoEnabled"

private val chineseLocales = arrayOf<Locale?>(
Locale("zh", "CN"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import org.getlantern.lantern.model.ProError
import org.getlantern.lantern.model.ProUser
import org.getlantern.lantern.openHome
import org.getlantern.lantern.restartApp
import org.getlantern.lantern.util.Analytics
import org.getlantern.lantern.util.showAlertDialog
import org.getlantern.lantern.util.showErrorDialog
import org.getlantern.mobilesdk.Logger
Expand Down Expand Up @@ -103,6 +104,7 @@ class SessionModel(
tx.put("/selectedTab", call.argument<String>("tab")!!)
}
}
"trackScreenView" -> Analytics.screen(activity, call.arguments as String)
else -> super.doMethodCall(call, notImplemented)
}
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ require (
github.com/getlantern/dnsgrab v0.0.0-20211216020425-5d5e155a01a8
github.com/getlantern/errors v1.0.1
github.com/getlantern/eventual v1.0.0
github.com/getlantern/flashlight v0.0.0-20220124135153-50d19168a687
github.com/getlantern/flashlight v0.0.0-20220126020937-9b92ed149687
github.com/getlantern/golog v0.0.0-20210606115803-bce9f9fe5a5f
github.com/getlantern/idletiming v0.0.0-20201229174729-33d04d220c4e
github.com/getlantern/ipproxy v0.0.0-20201020142114-ed7e3a8d5d87
Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,10 @@ github.com/getlantern/filepersist v0.0.0-20210901195658-ed29a1cb0b7c h1:mcz27xtA
github.com/getlantern/filepersist v0.0.0-20210901195658-ed29a1cb0b7c/go.mod h1:8DGAx0LNUfXNnEH+fXI0s3OCBA/351kZCiz/8YSK3i8=
github.com/getlantern/flashlight v0.0.0-20220124135153-50d19168a687 h1:v3C9OCVZr8xjIVT4q58Shi/q+bjPks9OUNP1PGFOZ/0=
github.com/getlantern/flashlight v0.0.0-20220124135153-50d19168a687/go.mod h1:w+7BXoTsKsMs2jeONVTX3Cqca9Ircj5hTVXTAYdExlI=
github.com/getlantern/flashlight v0.0.0-20220125232505-f8095bcb9c8d h1:WhHOnKYawy4hzYe3yevDeUl9RThaNw9bk6CHlnvRgm4=
github.com/getlantern/flashlight v0.0.0-20220125232505-f8095bcb9c8d/go.mod h1:w+7BXoTsKsMs2jeONVTX3Cqca9Ircj5hTVXTAYdExlI=
github.com/getlantern/flashlight v0.0.0-20220126020937-9b92ed149687 h1:DlRf7aIMxho3C3x/CC4Za2IlrGwt66GqvuFsuJO+t+E=
github.com/getlantern/flashlight v0.0.0-20220126020937-9b92ed149687/go.mod h1:w+7BXoTsKsMs2jeONVTX3Cqca9Ircj5hTVXTAYdExlI=
github.com/getlantern/framed v0.0.0-20190601192238-ceb6431eeede h1:yrU6Px3ZkvCsDLPryPGi6FN+2iqFPq+JeCb7EFoDBhw=
github.com/getlantern/framed v0.0.0-20190601192238-ceb6431eeede/go.mod h1:nhnoiS6DE6zfe+BaCMU4YI01UpsuiXnDqM5S8jxHuuI=
github.com/getlantern/fronted v0.0.0-20210806163345-971f7e536246 h1:tRWQABDpTE7tr2P48SjqsVF35uzJzLERwmt+TV0YR/U=
Expand Down
Loading