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