|
|
|
@ -6,25 +6,29 @@ import com.ejada.hmg.MainActivity
|
|
|
|
import android.os.Build
|
|
|
|
import android.os.Build
|
|
|
|
import android.util.Log
|
|
|
|
import android.util.Log
|
|
|
|
import androidx.annotation.RequiresApi
|
|
|
|
import androidx.annotation.RequiresApi
|
|
|
|
import com.ejada.hmg.penguin.PenguinView
|
|
|
|
|
|
|
|
import io.flutter.embedding.engine.FlutterEngine
|
|
|
|
import io.flutter.embedding.engine.FlutterEngine
|
|
|
|
import io.flutter.plugin.common.MethodCall
|
|
|
|
import io.flutter.plugin.common.MethodCall
|
|
|
|
import com.ejada.hmg.PermissionManager.HostNotificationPermissionManager
|
|
|
|
import com.ejada.hmg.samsung_watch.model.Vitals
|
|
|
|
import com.ejada.hmg.PermissionManager.HostBgLocationManager
|
|
|
|
|
|
|
|
import com.ejada.hmg.PermissionManager.HostGpsStateManager
|
|
|
|
|
|
|
|
import com.samsung.android.sdk.health.data.HealthDataService
|
|
|
|
import com.samsung.android.sdk.health.data.HealthDataService
|
|
|
|
import com.samsung.android.sdk.health.data.HealthDataStore
|
|
|
|
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.AccessType
|
|
|
|
import com.samsung.android.sdk.health.data.permission.Permission
|
|
|
|
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.DataTypes
|
|
|
|
import com.samsung.android.sdk.health.data.request.LocalTimeFilter
|
|
|
|
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.request.Ordering
|
|
|
|
|
|
|
|
import com.samsung.android.sdk.health.data.response.DataResponse
|
|
|
|
import io.flutter.plugin.common.MethodChannel
|
|
|
|
import io.flutter.plugin.common.MethodChannel
|
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
|
import kotlinx.coroutines.CoroutineScope
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.Dispatchers
|
|
|
|
import kotlinx.coroutines.SupervisorJob
|
|
|
|
import kotlinx.coroutines.SupervisorJob
|
|
|
|
import kotlinx.coroutines.cancel
|
|
|
|
import kotlinx.coroutines.cancel
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
import kotlinx.coroutines.launch
|
|
|
|
|
|
|
|
import java.time.Duration
|
|
|
|
import java.time.LocalDateTime
|
|
|
|
import java.time.LocalDateTime
|
|
|
|
import java.time.LocalTime
|
|
|
|
import java.time.LocalTime
|
|
|
|
|
|
|
|
|
|
|
|
@ -37,6 +41,9 @@ class SamsungWatch(
|
|
|
|
private lateinit var dataStore: HealthDataStore
|
|
|
|
private lateinit var dataStore: HealthDataStore
|
|
|
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
|
|
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
|
|
|
|
private val TAG = "SamsungWatch"
|
|
|
|
private val TAG = "SamsungWatch"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private lateinit var vitals: MutableMap<String, List<Vitals>>
|
|
|
|
companion object {
|
|
|
|
companion object {
|
|
|
|
private const val CHANNEL = "samsung_watch"
|
|
|
|
private const val CHANNEL = "samsung_watch"
|
|
|
|
|
|
|
|
|
|
|
|
@ -55,6 +62,7 @@ class SamsungWatch(
|
|
|
|
"init" -> {
|
|
|
|
"init" -> {
|
|
|
|
Log.d(TAG, "onMethodCall: init called")
|
|
|
|
Log.d(TAG, "onMethodCall: init called")
|
|
|
|
dataStore = HealthDataService.getStore(mainActivity)
|
|
|
|
dataStore = HealthDataService.getStore(mainActivity)
|
|
|
|
|
|
|
|
vitals = mutableMapOf()
|
|
|
|
result.success("initialized")
|
|
|
|
result.success("initialized")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@ -75,13 +83,17 @@ class SamsungWatch(
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
var granted = dataStore.getGrantedPermissions(permSet)
|
|
|
|
var granted = dataStore.getGrantedPermissions(permSet)
|
|
|
|
|
|
|
|
|
|
|
|
if(granted.containsAll(granted))
|
|
|
|
if (granted.containsAll(permSet)) {
|
|
|
|
result.success("Permission Granted") // adapt result as needed
|
|
|
|
result.success("Permission Granted")
|
|
|
|
|
|
|
|
return@launch
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
granted = dataStore.requestPermissions(permSet, mainActivity)
|
|
|
|
granted = dataStore.requestPermissions(permSet, mainActivity)
|
|
|
|
|
|
|
|
|
|
|
|
if(granted.containsAll(granted))
|
|
|
|
if (granted.containsAll(permSet)) {
|
|
|
|
result.success("Permission Granted") // adapt result as needed
|
|
|
|
result.success("Permission Granted") // adapt result as needed
|
|
|
|
|
|
|
|
return@launch
|
|
|
|
|
|
|
|
}
|
|
|
|
result.error("PermissionError", "Permission Not Granted", null) // adapt result as needed
|
|
|
|
result.error("PermissionError", "Permission Not Granted", null) // adapt result as needed
|
|
|
|
} catch (e: Exception) {
|
|
|
|
} catch (e: Exception) {
|
|
|
|
Log.e(TAG, "create: getPermission failed", e)
|
|
|
|
Log.e(TAG, "create: getPermission failed", e)
|
|
|
|
@ -91,8 +103,8 @@ class SamsungWatch(
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
"getHeartRate"->{
|
|
|
|
"getHeartRate"->{
|
|
|
|
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT)
|
|
|
|
val dateTime = LocalDateTime.now().with(LocalTime.MIDNIGHT).minusDays(365)
|
|
|
|
val localTimeFilter = LocalTimeFilter.of(dateTime, dateTime.minusDays(365))
|
|
|
|
val localTimeFilter = LocalTimeFilter.of(dateTime, LocalDateTime.now())
|
|
|
|
val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder
|
|
|
|
val readRequest = DataTypes.HEART_RATE.readDataRequestBuilder
|
|
|
|
.setLocalTimeFilter(localTimeFilter)
|
|
|
|
.setLocalTimeFilter(localTimeFilter)
|
|
|
|
.setOrdering(Ordering.DESC)
|
|
|
|
.setOrdering(Ordering.DESC)
|
|
|
|
@ -100,8 +112,46 @@ class SamsungWatch(
|
|
|
|
|
|
|
|
|
|
|
|
scope.launch {
|
|
|
|
scope.launch {
|
|
|
|
val heartRateList = dataStore.readData(readRequest).dataList
|
|
|
|
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<AggregatedData<Long>>) {
|
|
|
|
|
|
|
|
val stepCount = ArrayList<AggregatedData<Long>>()
|
|
|
|
|
|
|
|
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<HealthDataPoint>) {
|
|
|
|
|
|
|
|
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<HealthDataPoint>,
|
|
|
|
|
|
|
|
) {
|
|
|
|
|
|
|
|
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() {
|
|
|
|
fun destroy() {
|
|
|
|
scope.cancel()
|
|
|
|
scope.cancel()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|