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