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 = getDataType(record)) 51 } 52 53 /** Returns localized average StepsCadence from multiple data points. */ formatValuenull54 override suspend fun formatValue( 55 record: StepsCadenceRecord, 56 unitPreferences: UnitPreferences 57 ): String { 58 return formatRange(R.string.steps_per_minute, record.samples) 59 } 60 61 /** Returns localized StepsCadence value. */ formatA11yValuenull62 override suspend fun formatA11yValue( 63 record: StepsCadenceRecord, 64 unitPreferences: UnitPreferences 65 ): String { 66 return formatRange(R.string.steps_per_minute_long, record.samples) 67 } 68 formatRecordDetailsnull69 override suspend fun formatRecordDetails(record: StepsCadenceRecord): List<FormattedEntry> { 70 return record.samples.sortedBy { it.time }.map { formatSample(record.metadata.id, it) } 71 } 72 formatSamplenull73 private fun formatSample( 74 id: String, 75 sample: StepsCadenceRecordSample 76 ): FormattedEntry.FormattedSessionDetail { 77 return FormattedEntry.FormattedSessionDetail( 78 uuid = id, 79 header = timeFormatter.formatTime(sample.time), 80 headerA11y = timeFormatter.formatTime(sample.time), 81 title = 82 MessageFormat.format( 83 context.getString(R.string.steps_per_minute), mapOf("value" to sample.rate)), 84 titleA11y = 85 MessageFormat.format( 86 context.getString(R.string.steps_per_minute_long), 87 mapOf("value" to sample.rate))) 88 } 89 formatRangenull90 private fun formatRange(@StringRes res: Int, samples: List<StepsCadenceRecordSample>): String { 91 return if (samples.isEmpty()) { 92 context.getString(R.string.no_data) 93 } else { 94 val avrStepsCadence = samples.sumOf { it.rate } / samples.size 95 MessageFormat.format(context.getString(res), mapOf("value" to avrStepsCadence)) 96 } 97 } 98 } 99