From 47a417f6f6c3e6fd16252eb0c52850ab33cbbed1 Mon Sep 17 00:00:00 2001 From: Nathan Russell Date: Thu, 1 May 2025 14:35:26 -0500 Subject: [PATCH 1/2] [mapcache-817] Enhance matomo logging --- .../nga/mapcache/GeoPackageMapFragment.java | 7 +- .../java/mil/nga/mapcache/MainActivity.java | 19 ++++-- .../mil/nga/mapcache/MapCacheApplication.kt | 15 +++++ .../preferences/AboutMapcacheActivity.java | 3 + .../preferences/BasemapSettingsActivity.java | 3 + .../preferences/DisclaimerActivity.java | 3 + .../preferences/PreferencesActivity.java | 3 + .../preferences/PrivacyPolicyActivity.java | 3 + .../mapcache/preferences/TileUrlActivity.java | 3 + .../mapcache/tutorial/TutorialActivity.java | 3 + .../mapcache/utils/MatomoEventDispatcher.kt | 34 ++++++++++ .../mapcache/utils/MatomoHeartBeatManager.kt | 64 +++++++++++++++++++ .../view/map/feature/FeatureViewActivity.java | 3 + 13 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 mapcache/src/main/java/mil/nga/mapcache/utils/MatomoEventDispatcher.kt create mode 100644 mapcache/src/main/java/mil/nga/mapcache/utils/MatomoHeartBeatManager.kt diff --git a/mapcache/src/main/java/mil/nga/mapcache/GeoPackageMapFragment.java b/mapcache/src/main/java/mil/nga/mapcache/GeoPackageMapFragment.java index e077167e..34562b6f 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/GeoPackageMapFragment.java +++ b/mapcache/src/main/java/mil/nga/mapcache/GeoPackageMapFragment.java @@ -94,7 +94,6 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.textfield.TextInputEditText; - import org.jetbrains.annotations.NotNull; import org.locationtech.proj4j.units.Units; @@ -166,6 +165,7 @@ import mil.nga.mapcache.preferences.PreferencesActivity; import mil.nga.mapcache.repository.GeoPackageModifier; import mil.nga.mapcache.repository.sensors.SensorHandler; +import mil.nga.mapcache.utils.MatomoEventDispatcher; import mil.nga.mapcache.utils.SwipeController; import mil.nga.mapcache.utils.ViewAnimation; import mil.nga.mapcache.view.GeoPackageAdapter; @@ -477,6 +477,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, */ public void launchPreferences() { try { + MatomoEventDispatcher.Companion.submitButtonClickEvent("Settings"); Intent intent = new Intent(getContext(), PreferencesActivity.class); preferencePageActivityResultLauncher.launch(intent); } catch (Exception e) { @@ -1095,6 +1096,8 @@ public void onCancelButtonClicked() { */ public void openMapSelect() { if (getActivity() != null) { + MatomoEventDispatcher.Companion.submitButtonClickEvent("BaseMap Selection"); + Context wrapper = new ContextThemeWrapper(getContext(), R.style.MyPopupMenu); PopupMenu pm = new PopupMenu(wrapper, mapSelectButton); // Needed to make the icons visible @@ -1577,6 +1580,8 @@ private void showMaxFeaturesExceeded() { */ private void createNewWizard() { if (getActivity() != null) { + MatomoEventDispatcher.Companion.submitButtonClickEvent("New Geopackage"); + // Create Alert window with basic input text layout LayoutInflater inflater = LayoutInflater.from(getActivity()); View alertView = inflater.inflate(R.layout.new_geopackage_wizard, null); diff --git a/mapcache/src/main/java/mil/nga/mapcache/MainActivity.java b/mapcache/src/main/java/mil/nga/mapcache/MainActivity.java index bdcd928c..8b6fb246 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/MainActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/MainActivity.java @@ -10,14 +10,15 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.FragmentManager; import androidx.fragment.app.FragmentTransaction; + import java.util.Arrays; -import org.matomo.sdk.Matomo; import org.matomo.sdk.Tracker; -import org.matomo.sdk.TrackerBuilder; import org.matomo.sdk.extra.TrackHelper; import mil.nga.mapcache.io.MapCacheFileUtils; +import mil.nga.mapcache.utils.MatomoEventDispatcher; +import mil.nga.mapcache.utils.MatomoHeartBeatManager; /** * Main Activity @@ -36,6 +37,8 @@ public class MainActivity extends AppCompatActivity { */ private GeoPackageMapFragment mapFragment; + private MatomoHeartBeatManager matomoHeartBeatManager; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -60,12 +63,11 @@ protected void onCreate(Bundle savedInstanceState) { } } - String siteUrl = getString(R.string.matomo_url); - int siteId = getResources().getInteger(R.integer.matomo_site_id); + MatomoEventDispatcher.Companion.submitScreenEvent("/Main Activity", "App Opened"); - Tracker tracker = new TrackerBuilder(siteUrl, siteId, "MapCacheTracker").build(Matomo.getInstance(this)); - TrackHelper.track().screen("/Main Activity").title("App Opened").with(tracker); - tracker.dispatch(); + Tracker tracker = MapCacheApplication.Companion.getMatomoTracker(); + matomoHeartBeatManager = new MatomoHeartBeatManager(15); + getLifecycle().addObserver(matomoHeartBeatManager); } @Override @@ -145,5 +147,8 @@ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permis protected void onDestroy() { super.onDestroy(); MapCacheApplication.Companion.deleteCacheFiles(); + if (matomoHeartBeatManager != null) { + matomoHeartBeatManager.destroy(); + } } } diff --git a/mapcache/src/main/java/mil/nga/mapcache/MapCacheApplication.kt b/mapcache/src/main/java/mil/nga/mapcache/MapCacheApplication.kt index 6d24bf9f..960c3826 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/MapCacheApplication.kt +++ b/mapcache/src/main/java/mil/nga/mapcache/MapCacheApplication.kt @@ -3,12 +3,18 @@ package mil.nga.mapcache import android.app.Application import mil.nga.mapcache.io.CacheDirectoryType import mil.nga.mapcache.io.MapCacheFileUtils +import org.matomo.sdk.Matomo +import org.matomo.sdk.Tracker +import org.matomo.sdk.TrackerBuilder class MapCacheApplication: Application() { companion object { lateinit var appInstance: MapCacheApplication private set + lateinit var matomoTracker: Tracker + private set + //delete files from cache directories fun deleteCacheFiles() { MapCacheFileUtils.deleteCacheFiles(CacheDirectoryType.images) @@ -19,8 +25,17 @@ class MapCacheApplication: Application() { override fun onCreate() { super.onCreate() appInstance = this + matomoTracker = createMatomoTracker() + deleteCacheFiles() } + private fun createMatomoTracker(): Tracker { + val siteUrl = getString(R.string.matomo_url) + val siteId = resources.getInteger(R.integer.matomo_site_id) + + return TrackerBuilder(siteUrl, siteId, "MapCacheTracker").build(Matomo.getInstance(this)) + } + } diff --git a/mapcache/src/main/java/mil/nga/mapcache/preferences/AboutMapcacheActivity.java b/mapcache/src/main/java/mil/nga/mapcache/preferences/AboutMapcacheActivity.java index 9133aaa1..e6ced3cf 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/preferences/AboutMapcacheActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/preferences/AboutMapcacheActivity.java @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity; import mil.nga.mapcache.R; +import mil.nga.mapcache.utils.MatomoEventDispatcher; public class AboutMapcacheActivity extends AppCompatActivity { @@ -17,6 +18,8 @@ protected void onCreate(Bundle savedInstanceState) { // Adds back arrow button to action bar getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new AboutMapcacheActivityFragment()).commit(); + + MatomoEventDispatcher.Companion.submitScreenEvent("/About MapCache Activity", "About MapCache Opened"); } /** diff --git a/mapcache/src/main/java/mil/nga/mapcache/preferences/BasemapSettingsActivity.java b/mapcache/src/main/java/mil/nga/mapcache/preferences/BasemapSettingsActivity.java index 3d773385..5777b419 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/preferences/BasemapSettingsActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/preferences/BasemapSettingsActivity.java @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity; import mil.nga.mapcache.R; +import mil.nga.mapcache.utils.MatomoEventDispatcher; /** * The activity where the user can configure their basemaps. @@ -19,6 +20,8 @@ protected void onCreate(Bundle savedInstanceState) { // Adds back arrow button to action bar getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new BasemapSettingsFragment(this)).commit(); + + MatomoEventDispatcher.Companion.submitScreenEvent("/BaseMap Settings Activity", "BaseMap Settings Opened"); } /** diff --git a/mapcache/src/main/java/mil/nga/mapcache/preferences/DisclaimerActivity.java b/mapcache/src/main/java/mil/nga/mapcache/preferences/DisclaimerActivity.java index 79ac17fc..44a27156 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/preferences/DisclaimerActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/preferences/DisclaimerActivity.java @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity; import mil.nga.mapcache.R; +import mil.nga.mapcache.utils.MatomoEventDispatcher; public class DisclaimerActivity extends AppCompatActivity { @@ -17,6 +18,8 @@ protected void onCreate(Bundle savedInstanceState) { // Adds back arrow button to action bar getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new DisclaimerFragment()).commit(); + + MatomoEventDispatcher.Companion.submitScreenEvent("/Disclaimer Activity", "Disclaimer Opened"); } /** diff --git a/mapcache/src/main/java/mil/nga/mapcache/preferences/PreferencesActivity.java b/mapcache/src/main/java/mil/nga/mapcache/preferences/PreferencesActivity.java index 640db183..9fdebc14 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/preferences/PreferencesActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/preferences/PreferencesActivity.java @@ -15,6 +15,7 @@ import androidx.preference.PreferenceFragmentCompat; import mil.nga.mapcache.R; +import mil.nga.mapcache.utils.MatomoEventDispatcher; /** * Activity for the Preferences menu @@ -34,6 +35,8 @@ protected void onCreate(Bundle savedInstanceState) { // Adds back arrow button to action bar getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new PreferencesFragment()).commit(); + + MatomoEventDispatcher.Companion.submitScreenEvent("/Preferences Activity", "Settings Opened"); } /** diff --git a/mapcache/src/main/java/mil/nga/mapcache/preferences/PrivacyPolicyActivity.java b/mapcache/src/main/java/mil/nga/mapcache/preferences/PrivacyPolicyActivity.java index 739353e9..488338dd 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/preferences/PrivacyPolicyActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/preferences/PrivacyPolicyActivity.java @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity; import mil.nga.mapcache.R; +import mil.nga.mapcache.utils.MatomoEventDispatcher; public class PrivacyPolicyActivity extends AppCompatActivity { @@ -23,6 +24,8 @@ protected void onCreate(Bundle savedInstanceState) { // Adds back arrow button to action bar getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new PrivacyPolicyFragment()).commit(); + + MatomoEventDispatcher.Companion.submitScreenEvent("/Privacy Policy Activity", "Privacy Policy Opened"); } /** diff --git a/mapcache/src/main/java/mil/nga/mapcache/preferences/TileUrlActivity.java b/mapcache/src/main/java/mil/nga/mapcache/preferences/TileUrlActivity.java index 9c3d3166..221b2910 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/preferences/TileUrlActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/preferences/TileUrlActivity.java @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity; import mil.nga.mapcache.R; +import mil.nga.mapcache.utils.MatomoEventDispatcher; public class TileUrlActivity extends AppCompatActivity { @Override @@ -16,6 +17,8 @@ protected void onCreate(Bundle savedInstanceState) { // Adds back arrow button to action bar getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new TileUrlFragment()).commit(); + + MatomoEventDispatcher.Companion.submitScreenEvent("/Add Tile Server Activity", "Add Tile Server Opened"); } /** diff --git a/mapcache/src/main/java/mil/nga/mapcache/tutorial/TutorialActivity.java b/mapcache/src/main/java/mil/nga/mapcache/tutorial/TutorialActivity.java index 072beaf5..a2013e96 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/tutorial/TutorialActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/tutorial/TutorialActivity.java @@ -6,6 +6,7 @@ import androidx.appcompat.app.AppCompatActivity; import mil.nga.mapcache.R; +import mil.nga.mapcache.utils.MatomoEventDispatcher; public class TutorialActivity extends AppCompatActivity { @@ -17,6 +18,8 @@ protected void onCreate(Bundle savedInstanceState) { // Adds back arrow button to action bar getSupportActionBar().setDisplayHomeAsUpEnabled(true); getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new TutorialFragment()).commit(); + + MatomoEventDispatcher.Companion.submitScreenEvent("/Tutorial Activity", "Tutorial Opened"); } /** diff --git a/mapcache/src/main/java/mil/nga/mapcache/utils/MatomoEventDispatcher.kt b/mapcache/src/main/java/mil/nga/mapcache/utils/MatomoEventDispatcher.kt new file mode 100644 index 00000000..b6be6ce9 --- /dev/null +++ b/mapcache/src/main/java/mil/nga/mapcache/utils/MatomoEventDispatcher.kt @@ -0,0 +1,34 @@ +package mil.nga.mapcache.utils + +import mil.nga.mapcache.MapCacheApplication +import org.matomo.sdk.extra.TrackHelper + +class MatomoEventDispatcher { + + enum class EventTypes { + BUTTON_CLICK, + APPLICATION + } + + companion object{ + private val tracker = MapCacheApplication.matomoTracker + + //button click tracking + fun submitButtonClickEvent(buttonName: String) { + TrackHelper.track().event(EventTypes.BUTTON_CLICK.toString(), buttonName).with(tracker) + tracker.dispatch() + } + + //screen tracking + fun submitScreenEvent(screenName: String, title: String) { + TrackHelper.track().screen(screenName).title(title).with(tracker) + tracker.dispatch() + } + + //heart beat tracking + fun submitHeartBeat() { + TrackHelper.track().event(EventTypes.APPLICATION.toString(), "HeartBeat").with(tracker) + tracker.dispatch() + } + } +} \ No newline at end of file diff --git a/mapcache/src/main/java/mil/nga/mapcache/utils/MatomoHeartBeatManager.kt b/mapcache/src/main/java/mil/nga/mapcache/utils/MatomoHeartBeatManager.kt new file mode 100644 index 00000000..c16a3e94 --- /dev/null +++ b/mapcache/src/main/java/mil/nga/mapcache/utils/MatomoHeartBeatManager.kt @@ -0,0 +1,64 @@ +package mil.nga.mapcache.utils + +import android.util.Log +import androidx.lifecycle.Lifecycle +import androidx.lifecycle.LifecycleEventObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.OnLifecycleEvent +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.Job +import kotlinx.coroutines.cancel +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.matomo.sdk.Tracker +import org.matomo.sdk.extra.TrackHelper +import java.util.concurrent.TimeUnit + +class MatomoHeartBeatManager(private val heartbeatIntervalSeconds: Long = 15) : LifecycleEventObserver { + + companion object { + private const val TAG = "MatomoHeartBeat" + } + + private val scope = CoroutineScope(Dispatchers.IO) + private var heartBeatJob: Job? = null + + private fun sendHeartbeat() { + MatomoEventDispatcher.submitHeartBeat() + } + + private fun startHeartBeatTimer() { + heartBeatJob = scope.launch { + while (true) { + delay(TimeUnit.SECONDS.toMillis(heartbeatIntervalSeconds)) + sendHeartbeat() + } + } + } + + private fun stopHeartbeatTimer() { + heartBeatJob?.cancel() + heartBeatJob = null + Log.d(TAG, "HeartBeat timer stopped") + } + + override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) { + when (event) { + Lifecycle.Event.ON_START -> { + Log.d(TAG, "App moved to foreground. Starting matomo heart beat") + startHeartBeatTimer() + } + Lifecycle.Event.ON_STOP -> { + Log.d(TAG, "App moved to background. Stopping matomo heart beat") + stopHeartbeatTimer() + } + else -> {} + } + } + + fun destroy() { + stopHeartbeatTimer() + scope.cancel() + } +} \ No newline at end of file diff --git a/mapcache/src/main/java/mil/nga/mapcache/view/map/feature/FeatureViewActivity.java b/mapcache/src/main/java/mil/nga/mapcache/view/map/feature/FeatureViewActivity.java index 90cd071a..85d19710 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/view/map/feature/FeatureViewActivity.java +++ b/mapcache/src/main/java/mil/nga/mapcache/view/map/feature/FeatureViewActivity.java @@ -51,6 +51,7 @@ import mil.nga.mapcache.io.MapCacheFileUtils; import mil.nga.mapcache.listeners.DeleteImageListener; import mil.nga.mapcache.utils.ImageUtils; +import mil.nga.mapcache.utils.MatomoEventDispatcher; import mil.nga.mapcache.viewmodel.GeoPackageViewModel; public class FeatureViewActivity extends AppCompatActivity { @@ -233,6 +234,8 @@ protected void onCreate(Bundle savedInstanceState) { // set up the image gallery createImageGallery(); + + MatomoEventDispatcher.Companion.submitScreenEvent("/Feature View Activity", "Feature View Opened"); } From f10c5a76cb8dad575c8fea03dea964ecb758cfb6 Mon Sep 17 00:00:00 2001 From: Nathan Russell Date: Thu, 1 May 2025 16:24:33 -0500 Subject: [PATCH 2/2] [mapcache-817] Additional matomo event logging --- .../java/mil/nga/mapcache/GeoPackageMapFragment.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/mapcache/src/main/java/mil/nga/mapcache/GeoPackageMapFragment.java b/mapcache/src/main/java/mil/nga/mapcache/GeoPackageMapFragment.java index 34562b6f..b3594af7 100644 --- a/mapcache/src/main/java/mil/nga/mapcache/GeoPackageMapFragment.java +++ b/mapcache/src/main/java/mil/nga/mapcache/GeoPackageMapFragment.java @@ -877,6 +877,7 @@ public void onShareGP(String gpName) { gpkgData = new GpkgDataToExport(gpName, databaseFile); showSaveOrShareDialog(gpkgData); + MatomoEventDispatcher.Companion.submitButtonClickEvent("Share GeoPackage"); } @@ -902,6 +903,7 @@ public void showSaveOrShareDialog(GpkgDataToExport gpkgData){ ShareGpkgExecutor shareExec = new ShareGpkgExecutor(getActivity(), gpkgData); shareExec.shareDatabaseViaIntent(); alertDialog.dismiss(); + MatomoEventDispatcher.Companion.submitButtonClickEvent("Share with apps"); }); // Click listener for "Save" @@ -909,6 +911,7 @@ public void showSaveOrShareDialog(GpkgDataToExport gpkgData){ .setOnClickListener(v -> { sendIntentForGpkgFileCreation(gpkgData); alertDialog.dismiss(); + MatomoEventDispatcher.Companion.submitButtonClickEvent("Save to storage"); }); alertDialog.show(); @@ -1412,6 +1415,7 @@ private void setNewLayerFab() { String geoName = detailPageAdapter.getGeoPackageName(); if (geoName != null) { newLayerWizard(); + MatomoEventDispatcher.Companion.submitButtonClickEvent("New GeoPackage Layer"); } }); } @@ -1581,7 +1585,7 @@ private void showMaxFeaturesExceeded() { private void createNewWizard() { if (getActivity() != null) { MatomoEventDispatcher.Companion.submitButtonClickEvent("New Geopackage"); - + // Create Alert window with basic input text layout LayoutInflater inflater = LayoutInflater.from(getActivity()); View alertView = inflater.inflate(R.layout.new_geopackage_wizard, null); @@ -1600,6 +1604,7 @@ private void createNewWizard() { .setOnClickListener((View v) -> { createGeoPackage(); alertDialog.dismiss(); + MatomoEventDispatcher.Companion.submitButtonClickEvent("Create New"); }); // Click listener for "Import URL" @@ -1607,6 +1612,7 @@ private void createNewWizard() { .setOnClickListener((View v) -> { showGpkgImportFromUrlDialog(); alertDialog.dismiss(); + MatomoEventDispatcher.Companion.submitButtonClickEvent("Import from URL"); }); // Click listener for "Import from file" @@ -1614,6 +1620,7 @@ private void createNewWizard() { .setOnClickListener((View v) -> { importGeopackageFromFile(); alertDialog.dismiss(); + MatomoEventDispatcher.Companion.submitButtonClickEvent("Import from File"); }); alertDialog.show(); @@ -1697,6 +1704,7 @@ public void newLayerWizard() { createFeature.setOnClickListener((View v) -> { createFeatureOption(); alertDialog.dismiss(); + MatomoEventDispatcher.Companion.submitButtonClickEvent("Create Feature Layer"); }); // Listener for create tiles @@ -1707,6 +1715,7 @@ public void newLayerWizard() { newTileLayerWizard(geoName); } alertDialog.dismiss(); + MatomoEventDispatcher.Companion.submitButtonClickEvent("Create Tile Layer"); });