Skip to content

Commit

Permalink
Integration of Fitbit & HealthConnect (#18)
Browse files Browse the repository at this point in the history
* Auth setup

* Minor bug fixes ✨

* added Fitbit ECG

* added reading heartrate data functionality

* made seperate activity for reading data

* added button to access health connect app

* Integrated fitbit heart rate series

* removed unnecessary files

* Added seperate fragments for ECG and Heart Rate data

* Added UI for Fitbit Heart Rate Series

* Improved UI of Health Connect Screens

* Added UI screens for ECG Data(testing only)

* bug fixes

* feat: Merged fitbit branch into main

* Minor UI Improvements

---------

Co-authored-by: Shivam <shivampachchigar14112@gmail.com>
Co-authored-by: Yuvraj S Bhadauria <73571511+UvrajSB@users.noreply.github.com>
  • Loading branch information
3 people authored Jan 31, 2023
1 parent ab66295 commit 05cf036
Show file tree
Hide file tree
Showing 59 changed files with 2,353 additions and 211 deletions.
4 changes: 4 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

19 changes: 19 additions & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ plugins {
id 'org.jetbrains.kotlin.android'
// chaquopy lib for running python code
id 'com.chaquo.python'
id 'androidx.navigation.safeargs.kotlin'
id 'com.google.gms.google-services'
id "kotlin-parcelize"
}

android {
Expand Down Expand Up @@ -44,6 +47,7 @@ android {
buildFeatures{
dataBinding = true
}
namespace 'com.devsoc.hrmaa'
}

dependencies {
Expand All @@ -53,6 +57,8 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.1'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.1'
implementation 'androidx.browser:browser:1.4.0'
implementation 'com.google.firebase:firebase-firestore-ktx:24.4.1'
testImplementation 'junit:junit:4.13.2'
implementation 'com.airbnb.android:lottie:5.2.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
Expand All @@ -71,4 +77,17 @@ dependencies {

//Splash Screen
implementation 'androidx.core:core-splashscreen:1.0.0'

//retrofit
implementation 'com.squareup.retrofit2:retrofit:2.9.0'

//Gson
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'

//Http
implementation 'com.squareup.okhttp3:okhttp:4.9.0'

//Graph plotter
implementation 'com.jjoe64:graphview:4.2.2'

}
39 changes: 39 additions & 0 deletions app/google-services.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"project_info": {
"project_number": "557049753871",
"project_id": "hrmaa-fitbit",
"storage_bucket": "hrmaa-fitbit.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:557049753871:android:dd440e381f00815b5ace7a",
"android_client_info": {
"package_name": "com.devsoc.hrmaa"
}
},
"oauth_client": [
{
"client_id": "557049753871-31hlvd6d5m4rc314nm1aiq39ukh2u1lb.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyDnJPVzxFEmzK6d-lA73IddXnysYifj0kc"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "557049753871-31hlvd6d5m4rc314nm1aiq39ukh2u1lb.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}
59 changes: 50 additions & 9 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.devsoc.hrmaa">
<!-- To check whether healthcore apk is installed or not -->
<!-- To check whether healthcare apk is installed or not -->
<queries>
<package android:name="com.google.android.apps.healthdata" />
</queries>

<uses-permission android:name="android.permission.INTERNET"/>

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- permissions for Bluetooth in Android Devices using API 21 -->
Expand All @@ -24,36 +26,75 @@
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.App.Starting"
android:theme="@style/Theme.HRMAA_PROTOTYPE"
tools:targetApi="31">
<activity
android:name=".healthConnect.DateActivity"
android:exported="false"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar"
android:screenOrientation="portrait">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".bluetooth.ECGHome"
android:exported="false"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar">
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar"
android:screenOrientation="portrait">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".bluetooth.AvailableDevicesActivity"
android:exported="false"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar" />
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar"
android:screenOrientation="portrait"/>
<activity
android:name=".healthConnect.HealthConnectActivity"
android:enabled="true"
android:exported="true"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar"
android:screenOrientation="portrait">

<!-- TODO: Required to specify which Health Connect permissions the app can request -->
<meta-data
android:name="health_permissions"
android:resource="@array/health_permissions" />
<!-- (b) handle intent -->
<intent-filter>
<action android:name="androidx.health.ACTION_SHOW_PERMISSIONS_RATIONALE" />
</intent-filter>
</activity>
<activity
android:name=".healthConnect.ReadDataActivity"
android:exported="false"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar" />
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar"
android:screenOrientation="portrait"/>
<activity
android:name=".fitbit.FitbitActivity"
android:exported="false"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar" />
android:exported="true"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="hrma"
android:host="www.example.com" />
</intent-filter>
</activity>
<activity
android:name=".ppg.PPGActivity"
android:exported="false"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar" />
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar"
android:screenOrientation="portrait"/>
<activity
android:name=".MainActivity"
android:exported="true">
android:exported="true"
android:theme="@style/Theme.HRMAA_PROTOTYPE.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

Expand Down
26 changes: 18 additions & 8 deletions app/src/main/java/com/devsoc/hrmaa/MainActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package com.devsoc.hrmaa

import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
import androidx.databinding.DataBindingUtil
import com.devsoc.hrmaa.bluetooth.AvailableDevicesActivity
import androidx.health.connect.client.HealthConnectClient
import com.devsoc.hrmaa.bluetooth.ECGHome
import com.devsoc.hrmaa.databinding.ActivityMainBinding
import com.devsoc.hrmaa.fitbit.FitbitActivity
Expand All @@ -21,20 +22,29 @@ class MainActivity : AppCompatActivity() {
installSplashScreen()
binding = DataBindingUtil.setContentView(this, R.layout.activity_main)


binding.hcCvMa.setOnClickListener{
startActivity(Intent(this,HealthConnectActivity::class.java))
binding.hcCvMa.setOnClickListener {
//launch only if Health Connect is installed on device
if (HealthConnectClient.isAvailable(this)) {
startActivity(Intent(this, HealthConnectActivity::class.java))
} else {
Toast.makeText(
this,
"Please install the Google Health Connect App first.",
Toast.LENGTH_SHORT
).show()
}
}
binding.fitbitCvMa.setOnClickListener{
startActivity(Intent(this,FitbitActivity::class.java))
binding.fitbitCvMa.setOnClickListener {
startActivity(Intent(this, FitbitActivity::class.java))
}
binding.ppgCvMa.setOnClickListener{
binding.ppgCvMa.setOnClickListener {
startActivity(Intent(this, PPGActivity::class.java))
}
binding.ecgCvMa.setOnClickListener{
startActivity(Intent(this,ECGHome::class.java))
startActivity(Intent(this, ECGHome::class.java))
}


}

}
108 changes: 57 additions & 51 deletions app/src/main/java/com/devsoc/hrmaa/bluetooth/ECGHome.kt
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ class ECGHome : AppCompatActivity() {
}
apnaSocket?.close()
bluetoothAdapter?.cancelDiscovery()

btDevice?.let {
apnaSocket = it.createInsecureRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"))
try {
Expand All @@ -251,72 +252,77 @@ class ECGHome : AppCompatActivity() {
Toast.makeText(this@ECGHome, e.message, Toast.LENGTH_SHORT).show()
}
}
}

inStream =apnaSocket?.inputStream
outStream=apnaSocket?.outputStream

try{
outStream?.write(0)
if(outStream==null){
Log.d(TAG,"outStream is null")
}
}
catch (e: IOException) {
Log.e(TAG, "Error occurred when sending data", e)
}

val reader = BufferedReader(InputStreamReader(inStream))
inStream =apnaSocket?.inputStream
outStream=apnaSocket?.outputStream

var beforeLoopTime = System.currentTimeMillis()
while (true) {
try{
currStr = reader.readLine()
withContext(Dispatchers.Main) {
val compositeData = currStr.toLong()
ECGDataList.add((compositeData % 10000).toInt())
timeStampList.add(compositeData / 10000)
outStream?.write(0)
if(outStream==null){
Log.d(TAG,"outStream is null")
}
}
catch(e: java.lang.NumberFormatException){

}
catch (e: IOException) {
Log.d(TAG, "Input stream was disconnected", e)
withContext(Dispatchers.Main){
Toast.makeText(this@ECGHome,e.message, Toast.LENGTH_LONG).show()
}
break
Log.e(TAG, "Error occurred when sending data", e)
}

if( (System.currentTimeMillis() - beforeLoopTime) > 20000 ){
Log.d("HeartList",ECGDataList.toString())
Log.d("TimeList",timeStampList.toString())

try {
val reader = BufferedReader(InputStreamReader(inStream))

var beforeLoopTime = System.currentTimeMillis()
while (true) {
try{
currStr = reader.readLine()
withContext(Dispatchers.Main) {
val dataList = module.callAttr(
"get_bpm_metric",
ECGDataList.toIntArray(),
timeStampList.toLongArray()
).asList()
binding.tvHeartRate.text = dataList.get(0).toString()
Log.d("Contents of List", dataList.toString())
ECGDataList.clear()
timeStampList.clear()
val compositeData = currStr.toLong()
ECGDataList.add((compositeData % 10000).toInt())
timeStampList.add(compositeData / 10000)
}
}
catch(e: PyException){
withContext(Dispatchers.Main) {
Toast.makeText(this@ECGHome, e.message, Toast.LENGTH_SHORT).show()
Log.e("Error in python script",e.message + "\n" + e.cause + "\n" + e.toString())
}
catch(e: java.lang.NumberFormatException){

}
finally {
beforeLoopTime = System.currentTimeMillis()
catch (e: IOException) {
Log.d(TAG, "Input stream was disconnected", e)
withContext(Dispatchers.Main){
Toast.makeText(this@ECGHome,e.message, Toast.LENGTH_LONG).show()
}
break
}

if( (System.currentTimeMillis() - beforeLoopTime) > 20000 ){
Log.d("HeartList",ECGDataList.toString())
Log.d("TimeList",timeStampList.toString())

try {

withContext(Dispatchers.Main) {
val dataList = module.callAttr(
"get_bpm_metric",
ECGDataList.toIntArray(),
timeStampList.toLongArray()
).asList()
binding.tvHeartRate.text = dataList.get(0).toString()
Log.d("Contents of List", dataList.toString())
ECGDataList.clear()
timeStampList.clear()
}
}
catch(e: PyException){
withContext(Dispatchers.Main) {
Toast.makeText(this@ECGHome, e.message, Toast.LENGTH_SHORT).show()
Log.e("Error in python script",e.message + "\n" + e.cause + "\n" + e.toString())
}
}
finally {
beforeLoopTime = System.currentTimeMillis()
}

}
}
}
if( btDevice == null){
withContext(Dispatchers.Main){
Toast.makeText(this@ECGHome,"No Bluetooth Device Selected", Toast.LENGTH_SHORT).show()
}
}
}
Expand Down
Loading

0 comments on commit 05cf036

Please sign in to comment.