diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/workouts/health/DetectedWorkout.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/workouts/health/DetectedWorkout.kt index 32ac42aaeb..bfb18e2e8b 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/workouts/health/DetectedWorkout.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/workouts/health/DetectedWorkout.kt @@ -45,4 +45,6 @@ data class DetectedWorkout( val maxHeartRate: Int?, val steps: Int?, val elevationGainMeters: Double?, + /** Human-readable name of the app/device that wrote the record (e.g. "Samsung Health"). */ + val source: String, ) diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/workouts/health/HealthConnectManager.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/workouts/health/HealthConnectManager.kt index be51a2d572..e313632d35 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/service/workouts/health/HealthConnectManager.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/service/workouts/health/HealthConnectManager.kt @@ -60,6 +60,20 @@ class HealthConnectManager( /** How far back the New Workout carousel looks for workouts to offer. */ const val LOOKBACK_DAYS = 7L + private const val DEFAULT_SOURCE = "Health Connect" + + /** Friendly names for well-known writers when their app isn't installed to read a label from. */ + private val KNOWN_SOURCES = + mapOf( + "com.sec.android.app.shealth" to "Samsung Health", + "com.google.android.apps.fitness" to "Google Fit", + "com.google.android.apps.healthdata" to "Health Connect", + "com.fitbit.FitbitMobile" to "Fitbit", + "com.garmin.android.apps.connectmobile" to "Garmin Connect", + "com.strava" to "Strava", + "com.nike.plusgps" to "Nike Run Club", + ) + /** Read permissions needed to map a workout. */ val PERMISSIONS = setOf( @@ -168,9 +182,25 @@ class HealthConnectManager( maxHeartRate = totals?.get(HeartRateRecord.BPM_MAX)?.toInt(), steps = totals?.get(StepsRecord.COUNT_TOTAL)?.toInt(), elevationGainMeters = totals?.get(ElevationGainedRecord.ELEVATION_GAINED_TOTAL)?.inMeters, + source = resolveSourceName(session.metadata.dataOrigin.packageName), ) } + /** + * Friendly name of the app/device that wrote the record. Resolves the + * Health Connect data-origin package to the installed app's label + * ("Samsung Health", "Google Fit", …); falls back to a known-package map, + * then the raw package, then "Health Connect" when nothing is available. + */ + private fun resolveSourceName(packageName: String): String { + if (packageName.isBlank()) return DEFAULT_SOURCE + runCatching { + val pm = context.packageManager + return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString() + } + return KNOWN_SOURCES[packageName] ?: packageName + } + /** Aggregates the optional metrics over the session window. Null if aggregation fails. */ private suspend fun aggregate(session: ExerciseSessionRecord): AggregationResult? = try { diff --git a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionShared.kt b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionShared.kt index 4e6d0be653..9cb951f49e 100644 --- a/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionShared.kt +++ b/amethyst/src/main/java/com/vitorpamplona/amethyst/ui/screen/loggedIn/workouts/suggestion/WorkoutSuggestionShared.kt @@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts.suggestion import android.text.format.DateUtils import com.vitorpamplona.amethyst.service.workouts.health.DetectedWorkout import com.vitorpamplona.amethyst.ui.navigation.routes.Route -import com.vitorpamplona.quartz.experimental.fitness.workout.tags.SourceTag /** Builds the pre-filled composer route for a detected workout. Shared by the * feed suggestion banner and the New Workout carousel so they never drift. */ @@ -39,7 +38,7 @@ internal fun DetectedWorkout.toNewWorkoutRoute(title: String) = steps = steps ?: 0, elevationGainMeters = elevationGainMeters ?: 0.0, startTime = startTimeEpochSeconds, - source = SourceTag.HEALTH_CONNECT, + source = source, ) internal fun formatWorkoutDuration(totalSeconds: Long): String {