Skip to content

Commit

Permalink
Improve Health Connect error handling (#105)
Browse files Browse the repository at this point in the history
* Fix health connect availability check

* Fix null values on home screen cards

* Remove unused import
  • Loading branch information
vishnuravi authored Mar 1, 2024
1 parent d759d84 commit 6d33551
Show file tree
Hide file tree
Showing 13 changed files with 72 additions and 41 deletions.
2 changes: 1 addition & 1 deletion .idea/compiler.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/deploymentTargetDropDown.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/kotlinc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions .idea/migrations.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ class MainActivity : AppCompatActivity() {
val granted = healthViewModel
.healthConnectManager
.healthConnectClient
.permissionController
.getGrantedPermissions()
if (!granted.containsAll(permissions)) {
?.permissionController
?.getGrantedPermissions()
if (granted != null && !granted.containsAll(permissions)) {
requestPermissions.launch(permissions)
} else {
healthViewModel.updatePermissionsStatus(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ import javax.inject.Inject
class HealthViewModel @Inject constructor(
var healthConnectManager: HealthConnectManager
) : ViewModel() {
var totalStepsToday = mutableStateOf<Long>(0)
var totalStepsToday = mutableStateOf<Long?>(null)
private set

var weeklyAverageWeight = mutableStateOf<Mass?>(null)
private set

private var permissionsGranted = mutableStateOf<Boolean>(false)
private var permissionsGranted = mutableStateOf<Boolean?>(false)

val permissions = setOf(
HealthPermission.getReadPermission(StepsRecord::class),
Expand All @@ -41,7 +41,7 @@ class HealthViewModel @Inject constructor(
}

fun getTotalStepsToday() = viewModelScope.launch {
if (permissionsGranted.value) {
if (permissionsGranted.value == true) {
totalStepsToday.value = healthConnectManager.aggregateSteps(
startTime = LocalDate.now().atStartOfDay(ZoneId.systemDefault()).toInstant(),
endTime = Instant.now()
Expand All @@ -56,7 +56,7 @@ class HealthViewModel @Inject constructor(
val endOfWeek = Instant.now()
val startOfWeek = endOfWeek.minus(7, ChronoUnit.DAYS)

if (permissionsGranted.value) {
if (permissionsGranted.value == true) {
weeklyAverageWeight.value = healthConnectManager.getAverageWeight(
startTime = startOfWeek,
endTime = endOfWeek
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ fun StepsCard(
viewModel: HealthViewModel = hiltViewModel()
) {
viewModel.getTotalStepsToday()
val totalStepsString = viewModel.totalStepsToday.value?.toString() ?: "-"

Card(
modifier = Modifier
.width(165.dp)
Expand All @@ -48,7 +50,7 @@ fun StepsCard(
color = MaterialTheme.colorScheme.onSecondary
)
Text(
text = viewModel.totalStepsToday.value.toString(),
text = totalStepsString,
fontSize = 40.sp,
color = MaterialTheme.colorScheme.onSecondary
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,16 @@ fun WeightCard(
var avgWeightString = "-"
val avgWeight = viewModel.weeklyAverageWeight.value

if (useMetricUnits) {
avgWeight?.inKilograms?.roundToInt().let {
avgWeightString = "$it kg"
}
val weightInSelectedUnit = if (useMetricUnits) {
avgWeight?.inKilograms?.roundToInt()
} else {
avgWeight?.inPounds?.roundToInt().let {
avgWeightString = "$it lbs"
}
avgWeight?.inPounds?.roundToInt()
}

avgWeightString = weightInSelectedUnit?.let {
"$it ${if (useMetricUnits) "kg" else "lbs"}"
} ?: "-"

Card(
modifier = Modifier
.width(165.dp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,9 @@ fun StepGoalProgress(
// Fetch total step count and calculate metrics
healthViewModel.getTotalStepsToday()
val goal = task.context.integerGoal
val totalStepsToday = healthViewModel.totalStepsToday.value
var progress = healthViewModel.totalStepsToday.value.toFloat() / goal
val totalStepsToday = healthViewModel.totalStepsToday.value ?: 0

var progress = totalStepsToday.toFloat() / goal
if (progress > 1.0F) {
progress = 1.0F
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,27 @@ import javax.inject.Inject
class HealthConnectManager @Inject constructor(
private val context: Context
) {
val healthConnectClient by lazy { HealthConnectClient.getOrCreate(context) }
var healthConnectClient: HealthConnectClient? = null

var isAvailable = mutableStateOf(false)
private set
private var isAvailable = mutableStateOf(false)

init {
isAvailable.value = checkAvailabilityStatus()
if (isAvailable.value) {
healthConnectClient = HealthConnectClient.getOrCreate(context)
}
}

fun checkAvailabilityStatus(): Boolean {
private fun checkAvailabilityStatus(): Boolean {
val availabilityStatus = HealthConnectClient.sdkStatus(context, "com.google.android.apps.healthdata")
return availabilityStatus == HealthConnectClient.SDK_AVAILABLE
}

/**
* Determines if all requested permissions are granted.
*/
suspend fun hasAllPermissions(permissions: Set<String>): Boolean {
return healthConnectClient.permissionController.getGrantedPermissions().containsAll(permissions)
suspend fun hasAllPermissions(permissions: Set<String>): Boolean? {
return healthConnectClient?.permissionController?.getGrantedPermissions()?.containsAll(permissions)
}

/**
Expand All @@ -44,15 +46,15 @@ class HealthConnectManager @Inject constructor(
suspend fun readStepsByTimeRange(
startTime: Instant,
endTime: Instant
): List<StepsRecord> {
): List<StepsRecord>? {
val response =
healthConnectClient.readRecords(
healthConnectClient?.readRecords(
ReadRecordsRequest(
StepsRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
return response.records
return response?.records
}

/**
Expand All @@ -63,13 +65,13 @@ class HealthConnectManager @Inject constructor(
endTime: Instant
): Long {
val response =
healthConnectClient.aggregate(
healthConnectClient?.aggregate(
AggregateRequest(
metrics = setOf(StepsRecord.COUNT_TOTAL),
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
return response[StepsRecord.COUNT_TOTAL] ?: 0
return response?.get(StepsRecord.COUNT_TOTAL) ?: 0
}

/**
Expand All @@ -78,9 +80,9 @@ class HealthConnectManager @Inject constructor(
suspend fun aggregateHeartRate(
startTime: Instant,
endTime: Instant
): AggregationResult {
): AggregationResult? {
val response =
healthConnectClient.aggregate(
healthConnectClient?.aggregate(
AggregateRequest(
setOf(HeartRateRecord.BPM_MAX, HeartRateRecord.BPM_MIN),
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
Expand All @@ -94,26 +96,26 @@ class HealthConnectManager @Inject constructor(
*/
suspend fun getAverageWeight(startTime: Instant, endTime: Instant): Mass? {
val response =
healthConnectClient.aggregate(
healthConnectClient?.aggregate(
AggregateRequest(
metrics = setOf(WeightRecord.WEIGHT_AVG),
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
return response[WeightRecord.WEIGHT_AVG]
return response?.get(WeightRecord.WEIGHT_AVG)
}

/**
* Get all weight records for a certain time period
*/
suspend fun getWeightRecords(startTime: Instant, endTime: Instant): List<WeightRecord> {
suspend fun getWeightRecords(startTime: Instant, endTime: Instant): List<WeightRecord>? {
val response =
healthConnectClient.readRecords(
healthConnectClient?.readRecords(
ReadRecordsRequest(
recordType = WeightRecord::class,
timeRangeFilter = TimeRangeFilter.between(startTime, endTime)
)
)
return response.records
return response?.records
}
}
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ buildscript {
compose_version = "1.4.1"
compose_bom_version = "2023.03.00"
hilt_navigation_compose_version = "1.0.0"
firebase_bom_version = "30.1.0"
firebase_bom_version = "32.7.0"
play_services_version = "1.6.2"
play_services_auth_version = "20.3.0"
accompanist_version = "0.24.10-beta"
Expand Down

0 comments on commit 6d33551

Please sign in to comment.