1 /** <lambda>null2 * 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.testapps.toolbox.utils 17 18 import android.content.Context 19 import android.content.Intent 20 import android.health.connect.HealthConnectManager 21 import android.health.connect.InsertRecordsResponse 22 import android.health.connect.ReadRecordsRequest 23 import android.health.connect.ReadRecordsRequestUsingFilters 24 import android.health.connect.ReadRecordsResponse 25 import android.health.connect.TimeRangeFilter 26 import android.health.connect.datatypes.DataOrigin 27 import android.health.connect.datatypes.Device 28 import android.health.connect.datatypes.Metadata 29 import android.health.connect.datatypes.Record 30 import android.os.Build.MANUFACTURER 31 import android.os.Build.MODEL 32 import android.util.Log 33 import androidx.appcompat.app.AlertDialog 34 import androidx.core.os.asOutcomeReceiver 35 import com.android.healthconnect.testapps.toolbox.R 36 import java.lang.reflect.Field 37 import java.lang.reflect.Modifier 38 import kotlin.reflect.KClass 39 import kotlinx.coroutines.suspendCancellableCoroutine 40 import java.io.Serializable 41 42 class GeneralUtils { 43 44 companion object { 45 fun getMetaData(context: Context, recordUuid: String): Metadata { 46 val device: Device = 47 Device.Builder().setManufacturer(MANUFACTURER).setModel(MODEL).setType(1).build() 48 val dataOrigin = DataOrigin.Builder().setPackageName(context.packageName).build() 49 return Metadata.Builder() 50 .setDevice(device) 51 .setDataOrigin(dataOrigin) 52 .setId(recordUuid) 53 .build() 54 } 55 56 fun getMetaData(context: Context): Metadata { 57 val device: Device = 58 Device.Builder().setManufacturer(MANUFACTURER).setModel(MODEL).setType(1).build() 59 val dataOrigin = DataOrigin.Builder().setPackageName(context.packageName).build() 60 return Metadata.Builder().setDevice(device).setDataOrigin(dataOrigin).build() 61 } 62 63 suspend fun <T : Record> insertRecords( 64 records: List<T>, 65 manager: HealthConnectManager, 66 ): List<Record> { 67 68 val insertedRecords = 69 try { 70 suspendCancellableCoroutine<InsertRecordsResponse> { continuation -> 71 manager.insertRecords( 72 records, Runnable::run, continuation.asOutcomeReceiver()) 73 } 74 .records 75 } catch (ex: Exception) { 76 throw ex 77 } 78 return insertedRecords 79 } 80 81 suspend fun <T : Record> updateRecords( 82 records: List<T>, 83 manager: HealthConnectManager, 84 ) { 85 try { 86 suspendCancellableCoroutine<Void> { continuation -> 87 manager.updateRecords(records, Runnable::run, continuation.asOutcomeReceiver()) 88 } 89 } catch (ex: Exception) { 90 throw ex 91 } 92 } 93 94 fun <T : Any> getStaticFieldNamesAndValues( 95 obj: KClass<T>, 96 ): EnumFieldsWithValues { 97 val fieldNameToValue: MutableMap<String, Any> = emptyMap<String, Any>().toMutableMap() 98 val fields: List<Field> = 99 obj.java.declaredFields.filter { field -> 100 Modifier.isStatic(field.modifiers) && field.type == Int::class.java 101 } 102 for (field in fields) { 103 fieldNameToValue[field.name] = field.get(obj)!! 104 } 105 return EnumFieldsWithValues(fieldNameToValue.toMap()) 106 } 107 108 suspend fun readRecords( 109 recordType: Class<out Record>, 110 timeFilterRange: TimeRangeFilter, 111 numberOfRecordsPerBatch: Long, 112 manager: HealthConnectManager, 113 ): List<Record> { 114 val filter = 115 ReadRecordsRequestUsingFilters.Builder(recordType) 116 .setTimeRangeFilter(timeFilterRange) 117 .setPageSize(numberOfRecordsPerBatch.toInt()) 118 .build() 119 val records = 120 suspendCancellableCoroutine<ReadRecordsResponse<*>> { continuation -> 121 manager.readRecords(filter, Runnable::run, continuation.asOutcomeReceiver()) 122 } 123 .records 124 Log.d("READ_RECORDS", "Read ${records.size} records") 125 return records 126 } 127 128 suspend fun <T : Record> readRecords( 129 manager: HealthConnectManager, 130 request: ReadRecordsRequest<T>, 131 ): List<T> { 132 val records = 133 suspendCancellableCoroutine<ReadRecordsResponse<T>> { continuation -> 134 manager.readRecords( 135 request, Runnable::run, continuation.asOutcomeReceiver()) 136 } 137 .records 138 Log.d("READ_RECORDS", "Read ${records.size} records") 139 return records 140 } 141 142 inline fun <reified T> Context.requireSystemService(): T = 143 requireNotNull(getSystemService(T::class.java)) 144 145 fun Intent.requireStringExtra(name: String): String = 146 requireNotNull(getStringExtra(name)) 147 148 fun Intent.requireByteArrayExtra(name: String): ByteArray = 149 requireNotNull(getByteArrayExtra(name)) 150 151 inline fun <reified T : Serializable> Intent.requireSerializable(name: String): T = 152 requireNotNull(getSerializableExtra(name, T::class.java)) 153 154 fun Context.showMessageDialog(text: String) { 155 AlertDialog.Builder(this) 156 .setTitle(R.string.app_label) 157 .setNegativeButton(android.R.string.cancel, null) 158 .setMessage(text) 159 .show() 160 } 161 } 162 } 163