mirror of
https://github.com/meshtastic/Meshtastic-Android.git
synced 2026-04-20 22:23:37 +00:00
refactor(analytics)!: modularize analytics - remove Logging (#3256)
Signed-off-by: James Rich <2199651+jamesarich@users.noreply.github.com>
This commit is contained in:
parent
9aa0cf9335
commit
cad88d277b
72 changed files with 1219 additions and 1426 deletions
|
|
@ -1,33 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.geeksville.mesh
|
||||
|
||||
import com.geeksville.mesh.android.GeeksvilleApplication
|
||||
import dagger.hilt.android.HiltAndroidApp
|
||||
import org.meshtastic.core.prefs.analytics.AnalyticsPrefs
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltAndroidApp
|
||||
class MeshUtilApplication : GeeksvilleApplication() {
|
||||
|
||||
@Inject override lateinit var analyticsPrefs: AnalyticsPrefs
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.geeksville.mesh.analytics
|
||||
|
||||
import android.content.Context
|
||||
import com.geeksville.mesh.android.Logging
|
||||
|
||||
class DataPair(val name: String, valueIn: Any?) {
|
||||
val value = valueIn ?: "null"
|
||||
|
||||
// / An accumulating firebase event - only one allowed per event
|
||||
constructor(d: Double) : this("BOGUS", d)
|
||||
|
||||
constructor(d: Int) : this("BOGUS", d)
|
||||
}
|
||||
|
||||
/** Implement our analytics API using Firebase Analytics */
|
||||
@Suppress("UNUSED_PARAMETER", "EmptyFunctionBlock", "EmptyInitBlock")
|
||||
class NopAnalytics(context: Context) :
|
||||
AnalyticsProvider,
|
||||
Logging {
|
||||
|
||||
init {}
|
||||
|
||||
override fun setEnabled(on: Boolean) {}
|
||||
|
||||
override fun endSession() {}
|
||||
|
||||
override fun trackLowValue(event: String, vararg properties: DataPair) {}
|
||||
|
||||
override fun track(event: String, vararg properties: DataPair) {}
|
||||
|
||||
override fun startSession() {}
|
||||
|
||||
override fun setUserInfo(vararg p: DataPair) {}
|
||||
|
||||
override fun increment(name: String, amount: Double) {}
|
||||
|
||||
/** Send a google analytics screen view event */
|
||||
override fun sendScreenView(name: String) {}
|
||||
|
||||
override fun endScreenView() {}
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2025 Meshtastic LLC
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.geeksville.mesh.android
|
||||
|
||||
import android.app.Application
|
||||
import android.content.Context
|
||||
import android.provider.Settings
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.navigation.NavHostController
|
||||
import com.geeksville.mesh.BuildConfig
|
||||
import com.geeksville.mesh.analytics.AnalyticsProvider
|
||||
import com.geeksville.mesh.analytics.NopAnalytics
|
||||
import com.geeksville.mesh.android.BuildUtils.debug
|
||||
import com.geeksville.mesh.android.BuildUtils.info
|
||||
import org.meshtastic.core.model.DeviceHardware
|
||||
import org.meshtastic.core.prefs.analytics.AnalyticsPrefs
|
||||
import timber.log.Timber
|
||||
|
||||
abstract class GeeksvilleApplication :
|
||||
Application(),
|
||||
Logging {
|
||||
|
||||
companion object {
|
||||
lateinit var analytics: AnalyticsProvider
|
||||
}
|
||||
|
||||
// / Are we running inside the testlab?
|
||||
val isInTestLab: Boolean
|
||||
get() {
|
||||
val testLabSetting = Settings.System.getString(contentResolver, "firebase.test.lab") ?: null
|
||||
if (testLabSetting != null) {
|
||||
info("Testlab is $testLabSetting")
|
||||
}
|
||||
return "true" == testLabSetting
|
||||
}
|
||||
|
||||
abstract val analyticsPrefs: AnalyticsPrefs
|
||||
|
||||
@Suppress("EmptyFunctionBlock", "UnusedParameter")
|
||||
fun askToRate(application: AppCompatActivity) {}
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
if (BuildConfig.DEBUG) {
|
||||
Timber.plant(Timber.DebugTree())
|
||||
}
|
||||
|
||||
val nopAnalytics = NopAnalytics(this)
|
||||
analytics = nopAnalytics
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UnusedParameter")
|
||||
fun setAttributes(deviceVersion: String, deviceHardware: DeviceHardware) {
|
||||
// No-op for F-Droid version
|
||||
info("Setting attributes: deviceVersion=$deviceVersion, deviceHardware=$deviceHardware")
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun AddNavigationTracking(navController: NavHostController) {
|
||||
// No-op for F-Droid version
|
||||
navController.addOnDestinationChangedListener { _, destination, _ ->
|
||||
debug("Navigation changed to: ${destination.route}")
|
||||
}
|
||||
}
|
||||
|
||||
val Context.isAnalyticsAvailable: Boolean
|
||||
get() = false
|
||||
|
|
@ -63,7 +63,6 @@ import androidx.compose.ui.viewinterop.AndroidView
|
|||
import androidx.hilt.lifecycle.viewmodel.compose.hiltViewModel
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.geeksville.mesh.MeshProtos.Waypoint
|
||||
import com.geeksville.mesh.android.BuildUtils.debug
|
||||
import com.geeksville.mesh.android.gpsDisabled
|
||||
import com.geeksville.mesh.android.hasGps
|
||||
import com.geeksville.mesh.copy
|
||||
|
|
@ -107,6 +106,7 @@ import org.osmdroid.views.overlay.Marker
|
|||
import org.osmdroid.views.overlay.Polygon
|
||||
import org.osmdroid.views.overlay.infowindow.InfoWindow
|
||||
import org.osmdroid.views.overlay.mylocation.MyLocationNewOverlay
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.text.DateFormat
|
||||
|
||||
|
|
@ -116,7 +116,7 @@ private fun MapView.UpdateMarkers(
|
|||
waypointMarkers: List<MarkerWithLabel>,
|
||||
nodeClusterer: RadiusMarkerClusterer,
|
||||
) {
|
||||
debug("Showing on map: ${nodeMarkers.size} nodes ${waypointMarkers.size} waypoints")
|
||||
Timber.d("Showing on map: ${nodeMarkers.size} nodes ${waypointMarkers.size} waypoints")
|
||||
overlays.removeAll { it is MarkerWithLabel }
|
||||
// overlays.addAll(nodeMarkers + waypointMarkers)
|
||||
overlays.addAll(waypointMarkers)
|
||||
|
|
@ -242,7 +242,7 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails:
|
|||
|
||||
fun loadOnlineTileSourceBase(): ITileSource {
|
||||
val id = mapViewModel.mapStyleId
|
||||
debug("mapStyleId from prefs: $id")
|
||||
Timber.d("mapStyleId from prefs: $id")
|
||||
return CustomTileSource.getTileSource(id).also {
|
||||
zoomLevelMax = it.maximumZoomLevel.toDouble()
|
||||
showDownloadButton = if (it is OnlineTileSourceBase) it.tileSourcePolicy.acceptsBulkDownload() else false
|
||||
|
|
@ -261,11 +261,11 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails:
|
|||
|
||||
fun MapView.toggleMyLocation() {
|
||||
if (context.gpsDisabled()) {
|
||||
debug("Telling user we need location turned on for MyLocationNewOverlay")
|
||||
Timber.d("Telling user we need location turned on for MyLocationNewOverlay")
|
||||
Toast.makeText(context, R.string.location_disabled, Toast.LENGTH_SHORT).show()
|
||||
return
|
||||
}
|
||||
debug("user clicked MyLocationNewOverlay ${myLocationOverlay == null}")
|
||||
Timber.d("user clicked MyLocationNewOverlay ${myLocationOverlay == null}")
|
||||
if (myLocationOverlay == null) {
|
||||
myLocationOverlay =
|
||||
MyLocationNewOverlay(this).apply {
|
||||
|
|
@ -352,14 +352,14 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails:
|
|||
fun showDeleteMarkerDialog(waypoint: Waypoint) {
|
||||
val builder = MaterialAlertDialogBuilder(context)
|
||||
builder.setTitle(R.string.waypoint_delete)
|
||||
builder.setNeutralButton(R.string.cancel) { _, _ -> debug("User canceled marker delete dialog") }
|
||||
builder.setNeutralButton(R.string.cancel) { _, _ -> Timber.d("User canceled marker delete dialog") }
|
||||
builder.setNegativeButton(R.string.delete_for_me) { _, _ ->
|
||||
debug("User deleted waypoint ${waypoint.id} for me")
|
||||
Timber.d("User deleted waypoint ${waypoint.id} for me")
|
||||
mapViewModel.deleteWaypoint(waypoint.id)
|
||||
}
|
||||
if (waypoint.lockedTo in setOf(0, mapViewModel.myNodeNum ?: 0) && isConnected) {
|
||||
builder.setPositiveButton(R.string.delete_for_everyone) { _, _ ->
|
||||
debug("User deleted waypoint ${waypoint.id} for everyone")
|
||||
Timber.d("User deleted waypoint ${waypoint.id} for everyone")
|
||||
mapViewModel.sendWaypoint(waypoint.copy { expire = 1 })
|
||||
mapViewModel.deleteWaypoint(waypoint.id)
|
||||
}
|
||||
|
|
@ -382,7 +382,7 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails:
|
|||
|
||||
fun showMarkerLongPressDialog(id: Int) {
|
||||
performHapticFeedback()
|
||||
debug("marker long pressed id=$id")
|
||||
Timber.d("marker long pressed id=$id")
|
||||
val waypoint = waypoints[id]?.data?.waypoint ?: return
|
||||
// edit only when unlocked or lockedTo myNodeNum
|
||||
if (waypoint.lockedTo in setOf(0, mapViewModel.myNodeNum ?: 0) && isConnected) {
|
||||
|
|
@ -570,9 +570,9 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails:
|
|||
),
|
||||
)
|
||||
} catch (ex: TileSourcePolicyException) {
|
||||
debug("Tile source does not allow archiving: ${ex.message}")
|
||||
Timber.d("Tile source does not allow archiving: ${ex.message}")
|
||||
} catch (ex: Exception) {
|
||||
debug("Tile source exception: ${ex.message}")
|
||||
Timber.d("Tile source exception: ${ex.message}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -582,7 +582,7 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails:
|
|||
|
||||
val mapStyleInt = mapViewModel.mapStyleId
|
||||
builder.setSingleChoiceItems(mapStyles, mapStyleInt) { dialog, which ->
|
||||
debug("Set mapStyleId pref to $which")
|
||||
Timber.d("Set mapStyleId pref to $which")
|
||||
mapViewModel.mapStyleId = which
|
||||
dialog.dismiss()
|
||||
map.setTileSource(loadOnlineTileSourceBase())
|
||||
|
|
@ -768,7 +768,7 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails:
|
|||
EditWaypointDialog(
|
||||
waypoint = showEditWaypointDialog ?: return, // Safe call
|
||||
onSendClicked = { waypoint ->
|
||||
debug("User clicked send waypoint ${waypoint.id}")
|
||||
Timber.d("User clicked send waypoint ${waypoint.id}")
|
||||
showEditWaypointDialog = null
|
||||
mapViewModel.sendWaypoint(
|
||||
waypoint.copy {
|
||||
|
|
@ -781,12 +781,12 @@ fun MapView(mapViewModel: MapViewModel = hiltViewModel(), navigateToNodeDetails:
|
|||
)
|
||||
},
|
||||
onDeleteClicked = { waypoint ->
|
||||
debug("User clicked delete waypoint ${waypoint.id}")
|
||||
Timber.d("User clicked delete waypoint ${waypoint.id}")
|
||||
showEditWaypointDialog = null
|
||||
showDeleteMarkerDialog(waypoint)
|
||||
},
|
||||
onDismissRequest = {
|
||||
debug("User clicked cancel marker edit dialog")
|
||||
Timber.d("User clicked cancel marker edit dialog")
|
||||
showEditWaypointDialog = null
|
||||
},
|
||||
)
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ import androidx.lifecycle.Lifecycle
|
|||
import androidx.lifecycle.LifecycleEventObserver
|
||||
import androidx.lifecycle.compose.LocalLifecycleOwner
|
||||
import com.geeksville.mesh.BuildConfig
|
||||
import com.geeksville.mesh.android.BuildUtils.errormsg
|
||||
import org.meshtastic.feature.map.requiredZoomLevel
|
||||
import org.osmdroid.config.Configuration
|
||||
import org.osmdroid.tileprovider.tilesource.ITileSource
|
||||
|
|
@ -43,6 +42,7 @@ import org.osmdroid.util.BoundingBox
|
|||
import org.osmdroid.util.GeoPoint
|
||||
import org.osmdroid.views.CustomZoomButtonsController
|
||||
import org.osmdroid.views.MapView
|
||||
import timber.log.Timber
|
||||
|
||||
@SuppressLint("WakelockTimeout")
|
||||
private fun PowerManager.WakeLock.safeAcquire() {
|
||||
|
|
@ -50,9 +50,9 @@ private fun PowerManager.WakeLock.safeAcquire() {
|
|||
try {
|
||||
acquire()
|
||||
} catch (e: SecurityException) {
|
||||
errormsg("WakeLock permission exception: ${e.message}")
|
||||
Timber.e("WakeLock permission exception: ${e.message}")
|
||||
} catch (e: IllegalStateException) {
|
||||
errormsg("WakeLock acquire() exception: ${e.message}")
|
||||
Timber.e("WakeLock acquire() exception: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -62,7 +62,7 @@ private fun PowerManager.WakeLock.safeRelease() {
|
|||
try {
|
||||
release()
|
||||
} catch (e: IllegalStateException) {
|
||||
errormsg("WakeLock release() exception: ${e.message}")
|
||||
Timber.e("WakeLock release() exception: ${e.message}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue