diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt index e0bd2bac..11778578 100644 --- a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt +++ b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/SamsungWatch.kt @@ -6,25 +6,29 @@ import com.ejada.hmg.MainActivity import android.os.Build import android.util.Log import androidx.annotation.RequiresApi -import com.ejada.hmg.penguin.PenguinView import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodCall -import com.ejada.hmg.PermissionManager.HostNotificationPermissionManager -import com.ejada.hmg.PermissionManager.HostBgLocationManager -import com.ejada.hmg.PermissionManager.HostGpsStateManager +import com.ejada.hmg.samsung_watch.model.Vitals import com.samsung.android.sdk.health.data.HealthDataService import com.samsung.android.sdk.health.data.HealthDataStore +import com.samsung.android.sdk.health.data.data.AggregatedData +import com.samsung.android.sdk.health.data.data.HealthDataPoint import com.samsung.android.sdk.health.data.permission.AccessType import com.samsung.android.sdk.health.data.permission.Permission +import com.samsung.android.sdk.health.data.request.DataType import com.samsung.android.sdk.health.data.request.DataTypes import com.samsung.android.sdk.health.data.request.LocalTimeFilter +import com.samsung.android.sdk.health.data.request.LocalTimeGroup +import com.samsung.android.sdk.health.data.request.LocalTimeGroupUnit import com.samsung.android.sdk.health.data.request.Ordering +import com.samsung.android.sdk.health.data.response.DataResponse import io.flutter.plugin.common.MethodChannel import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.cancel import kotlinx.coroutines.launch +import java.time.Duration import java.time.LocalDateTime import java.time.LocalTime @@ -37,6 +41,9 @@ class SamsungWatch( private lateinit var dataStore: HealthDataStore private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) private val TAG = "SamsungWatch" + + + private lateinit var vitals: MutableMap> companion object { private const val CHANNEL = "samsung_watch" @@ -55,6 +62,7 @@ class SamsungWatch( "init" -> { Log.d(TAG, "onMethodCall: init called") dataStore = HealthDataService.getStore(mainActivity) + vitals = mutableMapOf() result.success("initialized") } @@ -75,13 +83,17 @@ class SamsungWatch( try { var granted = dataStore.getGrantedPermissions(permSet) - if(granted.containsAll(granted)) - result.success("Permission Granted") // adapt result as needed + if (granted.containsAll(permSet)) { + result.success("Permission Granted") + return@launch + } granted = dataStore.requestPermissions(permSet, mainActivity) - if(granted.containsAll(granted)) + if (granted.containsAll(permSet)) { result.success("Permission Granted") // adapt result as needed + return@launch + } result.error("PermissionError", "Permission Not Granted", null) // adapt result as needed } catch (e: Exception) { Log.e(TAG, "create: getPermission failed", e) @@ -91,8 +103,8 @@ class SamsungWatch( } "getHeartRate"->{ - val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT) - val localTimeFilter = LocalTimeFilter.of(dateTime, dateTime.minusDays(365)) + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder .setLocalTimeFilter(localTimeFilter) .setOrdering(Ordering.DESC) @@ -100,8 +112,46 @@ class SamsungWatch( scope.launch { val heartRateList = dataStore.readData(readRequest).dataList - Log.d(TAG, "create: heart rate data count: ${heartRateList}") + processHeartVital(heartRateList) + Log.d("TAG"," the data is ${vitals}") + print("the data is ${vitals}") + result.success("Permission Granted") + } + } + + + "getSleepData" -> { + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val readRequest = DataTypes.SLEEP.readDataRequestBuilder + .setLocalTimeFilter(localTimeFilter) + .setOrdering(Ordering.ASC) + .build() + scope.launch { + val sleepData = dataStore.readData(readRequest).dataList + processSleepVital(sleepData) + print("the data is $vitals") + Log.d(TAG, "the data is $vitals") + result.success("Permission Granted") + } + + } + + "steps"->{ + val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365) + val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now()) + val localTimeGroup = LocalTimeGroup.of(LocalTimeGroupUnit.HOURLY, 1) + val aggregateRequest = DataType.StepsType.TOTAL.requestBuilder + .setLocalTimeFilterWithGroup(localTimeFilter, localTimeGroup) + .setOrdering(Ordering.ASC) + .build() + scope.launch { + val steps = dataStore.aggregateData(aggregateRequest) + processStepsCount(steps) + print("the data is $vitals") + Log.d(TAG, "the data is $vitals") + result.success("Permission Granted") } } @@ -118,6 +168,50 @@ class SamsungWatch( } } + private fun CoroutineScope.processStepsCount(result: DataResponse>) { + val stepCount = ArrayList>() + var totalSteps: Long = 0 + vitals["steps"] = emptyList() + result.dataList.forEach { stepData -> + val vitalData = Vitals().apply { + value = (stepData.value as Long).toString() + timeStamp = stepData.startTime.toString() + } + (vitals["sleep"] as MutableList).add(vitalData) + } + + } + + private fun CoroutineScope.processSleepVital(sleepData: List) { + vitals["sleep"] = mutableListOf() + sleepData.forEach { + (vitals["sleep"] as MutableList).add( + Vitals().apply { + timeStamp = it.startTime.toString() + value = (it.getValue(DataType.SleepType.DURATION)?.toString().toString()) + } + ) + } + } + + private suspend fun CoroutineScope.processHeartVital( + heartRateList: List, + ) { + vitals["heartRate"] = mutableListOf() + heartRateList.forEach { + (vitals["heartRate"] as MutableList).add(processHeartRateData(it)) + } + } + + private fun processHeartRateData(heartRateData: HealthDataPoint) = + Vitals().apply { + heartRateData.getValue(DataType.HeartRateType.MAX_HEART_RATE)?.let { + value = it.toString() + } + timeStamp = heartRateData.startTime.toString() + } + + fun destroy() { scope.cancel() } diff --git a/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt new file mode 100644 index 00000000..c3a0c672 --- /dev/null +++ b/android/app/src/main/kotlin/com/ejada/hmg/samsung_watch/model/Vitals.kt @@ -0,0 +1,6 @@ +package com.ejada.hmg.samsung_watch.model + +data class Vitals( + var value : String = "", + var timeStamp : String = "" +) \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/health_provider.dart b/lib/features/smartwatch_health_data/health_provider.dart index 662b8141..23d73114 100644 --- a/lib/features/smartwatch_health_data/health_provider.dart +++ b/lib/features/smartwatch_health_data/health_provider.dart @@ -109,6 +109,7 @@ class HealthProvider with ChangeNotifier { if (result.isError) { error = 'Error initializing device: ${result.asError}'; } else { + getHeartRate(); getIt.get().pushPage(page: SmartWatchActivity()); print('Device initialized successfully'); } diff --git a/lib/features/smartwatch_health_data/health_service.dart b/lib/features/smartwatch_health_data/health_service.dart index b8ffbc99..198648a6 100644 --- a/lib/features/smartwatch_health_data/health_service.dart +++ b/lib/features/smartwatch_health_data/health_service.dart @@ -185,6 +185,13 @@ class HealthService { print('No watch helper found'); return; } - await watchHelper!.getHeartRate(); + try { + await watchHelper!.getHeartRate(); + await watchHelper!.getSleep(); + await watchHelper!.getSteps(); + }catch(e){ + print('Error getting heart rate: $e'); + } + } } diff --git a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart index ee3a3e83..efc3e39f 100644 --- a/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart +++ b/lib/features/smartwatch_health_data/platform_channel/samsung_platform_channel.dart @@ -28,4 +28,20 @@ class SamsungPlatformChannel { return Result.error(e); } } + Future> getSleep() async { + try{ + await _channel.invokeMethod('getSleepData'); + return Result.value(true); + }catch(e){ + return Result.error(e); + } + } + Future> getSteps() async { + try{ + await _channel.invokeMethod('steps'); + return Result.value(true); + }catch(e){ + return Result.error(e); + } + } } \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart index 69d0b88a..fd1c257b 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/samsung_health.dart @@ -10,7 +10,14 @@ class SamsungHealth extends WatchHelper { @override FutureOr getHeartRate() async { - await platformChannel.getHeartRate(); + try { + await platformChannel.getHeartRate(); + + }catch(e){ + print('Error getting heart rate: $e'); + } + + } @override @@ -22,4 +29,24 @@ class SamsungHealth extends WatchHelper { return await platformChannel.getRequestedPermission(); } + @override + FutureOr getSleep() async { + try { + await platformChannel.getSleep(); + + }catch(e){ + print('Error getting heart rate: $e'); + } + } + + @override + FutureOr getSteps() async{ + try { + await platformChannel.getSteps(); + + }catch(e){ + print('Error getting heart rate: $e'); + } + } + } \ No newline at end of file diff --git a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart index faa98d39..0ce360fe 100644 --- a/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart +++ b/lib/features/smartwatch_health_data/watch_connectors/watch_helper.dart @@ -3,5 +3,7 @@ import 'package:async/async.dart'; abstract class WatchHelper { Future> initDevice(); FutureOr getHeartRate(); + FutureOr getSleep(); + FutureOr getSteps(); } \ No newline at end of file