1 /** 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 * in compliance with the License. You may obtain a copy of the License at 6 * 7 * ``` 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * ``` 10 * 11 * Unless required by applicable law or agreed to in writing, software distributed under the License 12 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 13 * or implied. See the License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 package com.android.healthconnect.controller.dataentries.formatters 17 18 import android.content.Context 19 import android.health.connect.datatypes.StepsCadenceRecord 20 import android.health.connect.datatypes.StepsCadenceRecord.StepsCadenceRecordSample 21 import android.icu.text.MessageFormat 22 import androidx.annotation.StringRes 23 import com.android.healthconnect.controller.R 24 import com.android.healthconnect.controller.data.entries.FormattedEntry 25 import com.android.healthconnect.controller.dataentries.formatters.shared.EntryFormatter 26 import com.android.healthconnect.controller.dataentries.formatters.shared.RecordDetailsFormatter 27 import com.android.healthconnect.controller.dataentries.units.UnitPreferences 28 import com.android.healthconnect.controller.utils.LocalDateTimeFormatter 29 import dagger.hilt.android.qualifiers.ApplicationContext 30 import javax.inject.Inject 31 32 /** Formatter for printing StepsCadence series data. */ 33 class StepsCadenceFormatter @Inject constructor(@ApplicationContext private val context: Context) : 34 EntryFormatter<StepsCadenceRecord>(context), RecordDetailsFormatter<StepsCadenceRecord> { 35 36 private val timeFormatter = LocalDateTimeFormatter(context) 37 formatRecordnull38 override suspend fun formatRecord( 39 record: StepsCadenceRecord, 40 header: String, 41 headerA11y: String, 42 unitPreferences: UnitPreferences, 43 ): FormattedEntry { 44 return FormattedEntry.SeriesDataEntry( 45 uuid = record.metadata.id, 46 header = header, 47 headerA11y = headerA11y, 48 title = formatValue(record, unitPreferences), 49 titleA11y = formatA11yValue(record, unitPreferences), 50 dataType = record::class, 51 ) 52 } 53 54 /** Returns localized average StepsCadence from multiple data points. */ formatValuenull55 override suspend fun formatValue( 56 record: StepsCadenceRecord, 57 unitPreferences: UnitPreferences, 58 ): String { 59 return formatRange(R.string.steps_per_minute, record.samples) 60 } 61 62 /** Returns localized StepsCadence value. */ formatA11yValuenull63 override suspend fun formatA11yValue( 64 record: StepsCadenceRecord, 65 unitPreferences: UnitPreferences, 66 ): String { 67 return formatRange(R.string.steps_per_minute_long, record.samples) 68 } 69 formatRecordDetailsnull70 override suspend fun formatRecordDetails(record: StepsCadenceRecord): List<FormattedEntry> { 71 return record.samples.sortedBy { it.time }.map { formatSample(record.metadata.id, it) } 72 } 73 formatSamplenull74 private fun formatSample( 75 id: String, 76 sample: StepsCadenceRecordSample, 77 ): FormattedEntry.FormattedSessionDetail { 78 return FormattedEntry.FormattedSessionDetail( 79 uuid = id, 80 header = timeFormatter.formatTime(sample.time), 81 headerA11y = timeFormatter.formatTime(sample.time), 82 title = 83 MessageFormat.format( 84 context.getString(R.string.steps_per_minute), 85 mapOf("value" to sample.rate), 86 ), 87 titleA11y = 88 MessageFormat.format( 89 context.getString(R.string.steps_per_minute_long), 90 mapOf("value" to sample.rate), 91 ), 92 ) 93 } 94 formatRangenull95 private fun formatRange(@StringRes res: Int, samples: List<StepsCadenceRecordSample>): String { 96 return if (samples.isEmpty()) { 97 context.getString(R.string.no_data) 98 } else { 99 val avrStepsCadence = samples.sumOf { it.rate } / samples.size 100 MessageFormat.format(context.getString(res), mapOf("value" to avrStepsCadence)) 101 } 102 } 103 } 104