diff --git a/app/build.gradle b/app/build.gradle
index def0375..2e9068d 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -14,13 +14,13 @@ android {
compileSdk 34
namespace 'in.sminnovations.hpostesting'
- // dev - development, quality - qc, uat - User Acceptance Test, preprod - preproduction, prod - production
+ // dev -> development, quality -> qc, uat -> User Acceptance Testing, preprod -> preproduction, prod -> production, iocl -> iocl-iisc production
defaultConfig {
applicationId "in.sminnovations.hpostesting.dev"
minSdk 21
targetSdk 34
- versionCode 101
- versionName "2.1.101"
+ versionCode 114
+ versionName "2.1.114"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
@@ -157,7 +157,7 @@ dependencies {
implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation "androidx.preference:preference-ktx:1.2.1"
- implementation 'io.nats:jnats:2.11.2'
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
implementation("androidx.work:work-runtime-ktx:2.9.0")
@@ -165,4 +165,6 @@ dependencies {
implementation 'com.google.android.play:core:1.10.3'
implementation fileTree(dir: 'libs', include: ['*.aar'])
+ implementation 'io.nats:jnats:2.11.4'
+
}
\ No newline at end of file
diff --git a/app/release/hpos-app.apk b/app/release/hpos-app.apk
deleted file mode 100644
index b9d6528..0000000
Binary files a/app/release/hpos-app.apk and /dev/null differ
diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json
index acfe21e..14fde68 100644
--- a/app/release/output-metadata.json
+++ b/app/release/output-metadata.json
@@ -4,15 +4,15 @@
"type": "APK",
"kind": "Directory"
},
- "applicationId": "com.example.hpos",
+ "applicationId": "in.sminnovations.hpostesting.quality",
"variantName": "release",
"elements": [
{
"type": "SINGLE",
"filters": [],
"attributes": [],
- "versionCode": 1,
- "versionName": "1.0",
+ "versionCode": 101,
+ "versionName": "2.1.101",
"outputFile": "app-release.apk"
}
],
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a5b66b6..6a31cea 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -48,6 +48,10 @@
android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" />
+
@@ -118,9 +123,8 @@
android:noHistory="true"
android:theme="@style/AppTheme.NoActionBar">
-
-
-
+
+
>> = mapOf(
"HC-V1-005" to listOf(
listOf(1.5,0.0),
diff --git a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt
index 7cb221a..fcfc0cc 100644
--- a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt
+++ b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt
@@ -8,7 +8,7 @@ import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
-@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], version = 24, exportSchema = false)
+@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], version = 26, exportSchema = false)
@TypeConverters(Converters::class)
abstract class MyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
diff --git a/app/src/main/java/com/example/hpostesting/data/model/deviceprovision/ProvisionData.kt b/app/src/main/java/com/example/hpostesting/data/model/deviceprovision/ProvisionData.kt
new file mode 100644
index 0000000..179ea33
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/data/model/deviceprovision/ProvisionData.kt
@@ -0,0 +1,8 @@
+package com.example.hpostesting.data.model.deviceprovision
+
+data class ProvisionData(
+val username: String?,
+val password: String?,
+val natsToken: String?
+)
+
diff --git a/app/src/main/java/com/example/hpostesting/data/model/diagnostics/DiagnosticsData.kt b/app/src/main/java/com/example/hpostesting/data/model/diagnostics/DiagnosticsData.kt
index c84cdc4..d482597 100644
--- a/app/src/main/java/com/example/hpostesting/data/model/diagnostics/DiagnosticsData.kt
+++ b/app/src/main/java/com/example/hpostesting/data/model/diagnostics/DiagnosticsData.kt
@@ -5,5 +5,8 @@ data class DiagnosticsData (
var appVersion: String? = "",
var deviceType: String = "HEMOCUBE",
var deviceData: String = "",
+ var devicePassword: String = "",
+ var deviceNatsToken: String = "",
+ var accessToken: String = "",
var runTime: String = ""
)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/data/model/jig/JigData.kt b/app/src/main/java/com/example/hpostesting/data/model/jig/JigData.kt
new file mode 100644
index 0000000..91426b2
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/data/model/jig/JigData.kt
@@ -0,0 +1,9 @@
+package com.example.hpostesting.data.model.jig
+
+data class JigData (
+ var deviceId: String = "",
+ var appVersion: String? = "",
+ var deviceType: String = "JIG",
+ var scanData: String = "",
+ var createdAt: String = ""
+)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/data/model/molbioresult/MolbioV2Result.kt b/app/src/main/java/com/example/hpostesting/data/model/molbioresult/MolbioV2Result.kt
index 3e3c698..ab01bec 100644
--- a/app/src/main/java/com/example/hpostesting/data/model/molbioresult/MolbioV2Result.kt
+++ b/app/src/main/java/com/example/hpostesting/data/model/molbioresult/MolbioV2Result.kt
@@ -4,7 +4,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
data class MolbioV2Result(
val age: Int? = 31,
- val analysisDate: String? = "",
+ val analysisDate: String? = "2024-02-08 16:33:56",
val analysisId: String? = "",
val analysisStatus: String? = "",
val analysisType: String? = "HPOS",
@@ -12,11 +12,11 @@ data class MolbioV2Result(
val bloodGroup: String? = "",
val coefficients: List? = listOf(22, 22),
val collectionLocation: List? = listOf(),
- val collectionTime: String? = "",
+ val collectionTime: String? = "2024-02-08 16:33:56",
val collector: String? = "",
val curveFitting: String? = "Linear",
val deviceName: String? = "HPOS",
- val expiryTime: String? = "",
+ val expiryTime: String? = "2024-02-08 16:33:56",
val gender: String? = "",
val interpretation: String? = "",
val `operator`: String? = "",
@@ -30,7 +30,7 @@ data class MolbioV2Result(
val testId: String? = "",
val testResult: String? = "",
val testStatus: String? = "",
- val testTime: String? = "",
+ val testTime: String? = "2024-02-08 16:33:56",
val testType: String? = "",
val thresholds: String? = "",
val underMedication: Boolean? = false,
diff --git a/app/src/main/java/com/example/hpostesting/data/model/patient/DeviceData.kt b/app/src/main/java/com/example/hpostesting/data/model/patient/DeviceData.kt
index cefc5b9..79b3834 100644
--- a/app/src/main/java/com/example/hpostesting/data/model/patient/DeviceData.kt
+++ b/app/src/main/java/com/example/hpostesting/data/model/patient/DeviceData.kt
@@ -15,5 +15,15 @@ data class DeviceData(
@get:PropertyName("coefficients") @set:PropertyName("coefficients")
var coefficients: List = emptyList(),
@get:PropertyName("calibratedAt") @set:PropertyName("calibratedAt")
- var calibratedAt: String = ""
+ var calibratedAt: String = "" ,
+ @get:PropertyName("deviceProvisionResponse") @set:PropertyName("deviceProvisionResponse")
+ var deviceProvisionResponse: String = "" ,
+ @get:PropertyName("username") @set:PropertyName("username")
+ var username: String = "",
+ @get:PropertyName("password") @set:PropertyName("password")
+ var password: String = "",
+ @get:PropertyName("natsToken") @set:PropertyName("natsToken")
+ var natsToken: String = "",
+ @get:PropertyName("natsTokenExpiry") @set:PropertyName("natsTokenExpiry")
+ var natsTokenExpiry: String = ""
)
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt b/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt
index cb279fd..acb2755 100644
--- a/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt
+++ b/app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt
@@ -11,6 +11,7 @@ import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRes
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
+import com.example.hpostesting.data.model.jig.JigData
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
@@ -140,6 +141,16 @@ class DatabaseRepository @Inject constructor(
}
}
+ override suspend fun addTestJigData(data: JigData?): Response {
+ return try {
+ db.collection("jigs").add(data!!).await()
+ Response.Success(data.deviceId)
+ } catch (e: Exception) {
+ Firebase.crashlytics.recordException(e)
+ Response.Error(e)
+ }
+ }
+
override suspend fun uploadFileToStorage(
patientID: String, filePath: String
): Response {
@@ -209,7 +220,28 @@ class DatabaseRepository @Inject constructor(
return allDeviceDataList.find { it.deviceId == deviceId }
}
+ override suspend fun getDeviceResponse(data: DeviceData?): Response {
+ return try {
+ db.collection("devices").add(data!!).await()
+ Response.Success(data.deviceProvisionResponse)
+ } catch (e: Exception) {
+ Firebase.crashlytics.recordException(e)
+ Response.Error(e)
+ }
+ }
+
+ override suspend fun uploadDeviceId(data: DeviceData): Response? {
+ return try {
+ db.collection("devices").add(data!!).await()
+ Response.Success(data.deviceId)
+ } catch (e: Exception) {
+ Firebase.crashlytics.recordException(e)
+ Response.Error(e)
+ }
+ }
+
override fun addTestToDatabase(testDetails: UserData): Any {
TODO("Not yet implemented")
}
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt
index dfb5d33..243c494 100644
--- a/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt
+++ b/app/src/main/java/com/example/hpostesting/data/repository/Repository.kt
@@ -7,6 +7,7 @@ import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRes
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
+import com.example.hpostesting.data.model.jig.JigData
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
@@ -31,9 +32,13 @@ interface Repository {
suspend fun addDiagnostics(data: DiagnosticsData?): Response
+ suspend fun addTestJigData(data: JigData?): Response
+
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response
suspend fun getDeviceDataById(deviceId: String): DeviceData?
+ suspend fun getDeviceResponse(data: DeviceData?): Response
+ suspend fun uploadDeviceId(data: DeviceData): Response?
abstract fun addTestToDatabase(testDetails: UserData): Any
// suspend fun addToDatabase(data: PatientDetails)
diff --git a/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt
index 4aafcc7..f5b87e4 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt
@@ -229,7 +229,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
} else {
Toast.makeText(this,"Error", Toast.LENGTH_LONG).show()
}
-
}
private fun pullTrigger() {
@@ -271,7 +270,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
return sharedPreference.getString(Constants.KIT_NUMBER, "")
?.isNotBlank() == true && sharedPreference.getInt(
Constants.KIT_COUNT, 0
- ) > 0 && sharedPreference.getInt(Constants.KIT_COUNT, 0) < 35
+ ) > 0 && sharedPreference.getInt(Constants.KIT_COUNT, 0) < Constants.KIT_CAPACITY
}
private fun isSerialValid(s: String): Boolean {
diff --git a/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt
index dfd8997..f1d0992 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt
@@ -149,6 +149,15 @@ class MainActivity : AppCompatActivity() {
Constants.DEVICE_TYPE_HEMOCUBE
}
+ device.productId == 4614 && device.vendorId == 7111 -> {
+ binding.cvItem1.visibility = View.VISIBLE
+ binding.cvItem3.visibility = View.VISIBLE
+ binding.cvItem2.visibility = View.GONE
+ binding.cvItem4.visibility = View.GONE
+ DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HEMOCUBE)
+ Constants.DEVICE_TYPE_HEMOCUBE
+ }
+
device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> {
Log.d(
TAG,
diff --git a/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt b/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt
index 4c8f3dc..36cd967 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt
@@ -1,6 +1,10 @@
package com.example.hpostesting.presentation
+import android.content.Context
+import android.os.Build
import android.util.Log
+import androidx.annotation.RequiresApi
+import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import io.nats.client.AuthHandler
import io.nats.client.Connection
@@ -8,9 +12,17 @@ import io.nats.client.Message
import io.nats.client.NKey
import io.nats.client.Nats
import io.nats.client.Options
+import io.nats.client.support.SSLUtils
+import java.io.FileInputStream
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.security.GeneralSecurityException
+import java.security.KeyStore
+import java.security.SecureRandom
+import java.security.cert.CertificateFactory
+import javax.net.ssl.KeyManagerFactory
+import javax.net.ssl.SSLContext
+import javax.net.ssl.TrustManagerFactory
class NatsManager(datacollector: DashboardActivity) {
@@ -19,103 +31,160 @@ class NatsManager(datacollector: DashboardActivity) {
var nc: Connection? = null
val datacollector = datacollector
var connect = false
+ var sharedPreferences = datacollector.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
+ private fun createSSLContext(): SSLContext {
+ val keyStorePassword = "prime24".toCharArray() // Change as necessary
+ val clientCertPath = "/storage/sdcard0/Download/client.p12"
+
+ // Load client certificate and key
+ val keyStore = KeyStore.getInstance("PKCS12")
+ FileInputStream(clientCertPath).use { keyStoreInputStream ->
+ keyStore.load(keyStoreInputStream, keyStorePassword)
+ }
+ val caCertPath =
+ "/storage/sdcard0/Android/data/in.sminnovations.hpostesting.quality/files/NATS/clientCertificate/client-cert.pem"
+ val caCert = FileInputStream(caCertPath).use { inputStream ->
+ val certificateFactory = CertificateFactory.getInstance("X.509")
+ certificateFactory.generateCertificate(inputStream)
+ }
+
+ val trustStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
+ load(null, null) // Initialize the keystore
+ setCertificateEntry("caCert", caCert) // Add the CA certificate
+ }
+
+ // Initialize key manager factory
+ val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
+ kmf.init(keyStore, keyStorePassword)
+
+ // Initialize trust manager factory
+ val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
+ tmf.init(trustStore)
+
+ // Initialize SSLContext
+ val sslContext = SSLContext.getInstance("TLS")
+ sslContext.init(kmf.keyManagers, tmf.trustManagers, SecureRandom())
+
+ return sslContext
+ }
+
+ @RequiresApi(Build.VERSION_CODES.O)
fun connect() {
Log.d(TAG, "TRY TO CONNECT")
Thread {
- val seedString = "SUAEB5PUWNS6C2HUV3MFI6HUDEAPGPFPBHMI73NHIQATCDD2BWALVEZXZ4"
- val seedBytes = seedString.toCharArray()
-
- val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere
-
- val options = Options.Builder()
- .server("nats://192.168.10.117:4222")
- .authHandler(object : AuthHandler {
- override fun getID(): CharArray? {
- return try {
- theNKey?.publicKey
- } catch (ex: GeneralSecurityException) {
- null
- } catch (ex: IOException) {
- null
- } catch (ex: NullPointerException) {
- null
- }
- }
-
- override fun sign(nonce: ByteArray): ByteArray? {
- return try {
- theNKey?.sign(nonce)
- } catch (ex: GeneralSecurityException) {
- null
- } catch (ex: IOException) {
- null
- } catch (ex: NullPointerException) {
- null
- }
- }
-
- override fun getJWT(): CharArray? {
- return null
- }
- })
- .build()
-
try {
+
+ val seedString = sharedPreferences.getString(Constants.NATS_TOKEN, "")
+ val deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "")
+ Log.e("seedString", seedString.toString())
+ Log.d("nats deviceId", deviceId.toString())
+ val seedBytes = seedString?.toCharArray()
+
+ val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere
+
+ val options = Options.Builder()
+ .server("nats://nanodgx.in:4222")
+ .sslContext(SSLUtils.createOpenTLSContext())
+ .authHandler(object : AuthHandler {
+ override fun getID(): CharArray? {
+ return try {
+ theNKey?.publicKey
+ } catch (ex: GeneralSecurityException) {
+ null
+ } catch (ex: IOException) {
+ null
+ } catch (ex: NullPointerException) {
+ null
+ }
+ }
+
+ override fun sign(nonce: ByteArray): ByteArray? {
+ return try {
+ theNKey?.sign(nonce)
+ } catch (ex: GeneralSecurityException) {
+ null
+ } catch (ex: IOException) {
+ null
+ } catch (ex: NullPointerException) {
+ null
+ }
+ }
+
+ override fun getJWT(): CharArray? {
+ return null
+ }
+ })
+ .build()
+
nc = Nats.connect(options)
Log.d(TAG, "Connected to Nats server ${options.servers.first()}")
connect = true
datacollector.setConnect(true)
+ if (nc?.status == Connection.Status.CONNECTED) {
+ Log.d("NATSCONNECTION", "NATS is successfully connected.")
- nc?.publish(
- "server.hpos.HCV-000-3001.ping",
- "ALIVE".toByteArray(StandardCharsets.UTF_8)
- )
- nc?.publish(
- "server.hpos.HCV-000-3001.health",
- "ALIVE".toByteArray(StandardCharsets.UTF_8)
- )
- Log.d(TAG, "Published msg server.hpos.HCV-000-3001.ping on topic Testing")
- val d = nc?.createDispatcher { msg: Message? ->
- println("PRITIMOI SARKAR $msg")
- }
+ val d = nc?.createDispatcher { msg: Message? ->
+ println("Nats dispatcher $msg")
+ }
- d?.subscribe("device.hpos.HCV-000-3001.update") { msg ->
- val response = String(msg.data, StandardCharsets.UTF_8)
- datacollector. setResponse(response)
- println("Message received (up to 100 times): $response")
- }
+ nc?.subscribe("device.hpos.${deviceId}.ping")
- d?.subscribe("device.hpos.HCV-000-3001.uploadlogs") { msg ->
- val response = String(msg.data, StandardCharsets.UTF_8)
- datacollector.setResponse(response + "uPLOAD")
- println("Message received (up to 100 times): $response")
- }
+ nc?.publish(
+ "server.hpos.${deviceId}.ping",
+ "ALIVE".toByteArray(StandardCharsets.UTF_8)
+ )
+ nc?.publish(
+ "server.hpos.${deviceId}.health",
+ "ALIVE".toByteArray(StandardCharsets.UTF_8)
+ )
- d?.subscribe("device.hpos.HCV-000-3001.disable") { msg ->
- val response = String(msg.data, StandardCharsets.UTF_8)
- datacollector.setResponse(response)
- println("Message received (up to 100 times): $response")
- }
+ d?.subscribe("device.hpos.${deviceId}.ping") { msg ->
+ val response = String(msg.data, StandardCharsets.UTF_8)
+ datacollector.setResponse(response)
+ println("Message received (up to 100 times): $response")
+ Log.d(TAG, "subscribed msg ${msg} on topic ping")
+ }
- d?.subscribe("device.hpos.HCV-000-3001.updatecustomer") { msg ->
- val response = String(msg.data, StandardCharsets.UTF_8)
- datacollector.setResponse(response)
- println("Message received (up to 100 times): $response")
- }
+ d?.subscribe("device.hpos.${deviceId}.update") { msg ->
+ val response = String(msg.data, StandardCharsets.UTF_8)
+ datacollector.setResponse(response)
+ println("Message received (up to 100 times): $response")
+ }
- d?.subscribe("device.hpos.HCV-000-3001.checkupdate") { msg ->
- val response = String(msg.data, StandardCharsets.UTF_8)
- datacollector.setResponse(response)
- println("Message received (up to 100 times): $response")
+ d?.subscribe("device.hpos.${deviceId}.uploadlogs") { msg ->
+ val response = String(msg.data, StandardCharsets.UTF_8)
+ datacollector.setResponse(response + "UPLOAD")
+ println("Message received (up to 100 times): $response")
+ }
+
+ d?.subscribe("device.hpos.${deviceId}.disable") { msg ->
+ val response = String(msg.data, StandardCharsets.UTF_8)
+ datacollector.setResponse(response)
+ println("Message received (up to 100 times): $response")
+ }
+
+ d?.subscribe("device.hpos.${deviceId}.updatecustomer") { msg ->
+ val response = String(msg.data, StandardCharsets.UTF_8)
+ datacollector.setResponse(response)
+ println("Message received (up to 100 times): $response")
+ }
+
+ d?.subscribe("device.hpos.${deviceId}.checkupdate") { msg ->
+ val response = String(msg.data, StandardCharsets.UTF_8)
+ datacollector.setResponse(response)
+ println("Message received (up to 100 times): $response")
+ }
+ } else {
+ Log.d("NATSCONNECTION", "NATS is not connected. Current status: ${nc?.status}")
}
} catch (exp: Exception) {
println(exp.printStackTrace())
connect = false
- datacollector.setConnect(true)
+ datacollector.setConnect(false)
}
}.start()
@@ -126,6 +195,16 @@ class NatsManager(datacollector: DashboardActivity) {
Log.d(TAG, "Published msg ${msg} on topic ${topic}")
}
+ fun sub(topic: String) {
+ val d = nc?.createDispatcher { msg: Message? ->
+ val response = String(msg?.data ?: ByteArray(0), StandardCharsets.UTF_8)
+ datacollector.onMessageReceived(topic, response)
+ Log.d(TAG, "Subscribed msg $msg on topic $topic")
+ }
+
+ d?.subscribe(topic)
+ }
+
fun close() {
nc?.close()
Log.d(TAG, "Nats connection close")
diff --git a/app/src/main/java/com/example/hpostesting/presentation/assurance/AssuranceControlsFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/assurance/AssuranceControlsFragment.kt
index 4043938..250bea2 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/assurance/AssuranceControlsFragment.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/assurance/AssuranceControlsFragment.kt
@@ -12,6 +12,7 @@ import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
+import android.widget.Toast
import androidx.fragment.app.Fragment
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
@@ -30,6 +31,9 @@ class AssuranceControlsFragment: Fragment() {
binding = FragmentAssuranceControlsBinding.inflate(inflater, container, false)
sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
+
+ DataHolder.hemoCubeTestData!!.solution = ""
+ DataHolder.hemoCubeTestData!!.volume = ""
return binding.root
}
@@ -42,7 +46,7 @@ class AssuranceControlsFragment: Fragment() {
// binding.btnSubmit.visibility = View.GONE
val solutionSpinner: Spinner = binding.spinnerSolutions
- val solutionOptions = arrayOf("Select solution", "Tartrazine", "AR")
+ val solutionOptions = arrayOf("Select solution", "Tartrazine", "Acid Red")
val solutionAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, solutionOptions)
solutionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
solutionSpinner.adapter = solutionAdapter
@@ -121,6 +125,13 @@ class AssuranceControlsFragment: Fragment() {
volumeSpinner.setSelection(volumePosition)
binding.btnSubmit.setOnClickListener {
+ val selectedSolution = DataHolder.hemoCubeTestData!!.solution
+ val selectedVolume = DataHolder.hemoCubeTestData!!.volume
+ if (selectedSolution == "Select solution" || selectedVolume == "Select volume") {
+ Toast.makeText(requireContext(), "Please select both solution and volume", Toast.LENGTH_SHORT).show()
+ return@setOnClickListener
+ }
+
DataHolder.hemoCubeTestData!!.quickCapture = true
val currentUnixTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Instant.now().epochSecond
diff --git a/app/src/main/java/com/example/hpostesting/presentation/autodac/AutoDacFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/autodac/AutoDacFragment.kt
index 71f4d2c..2cc3a6a 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/autodac/AutoDacFragment.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/autodac/AutoDacFragment.kt
@@ -105,8 +105,6 @@ class AutoDacFragment: Fragment() {
HemoCubeCommands.AUTO_DAC_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
-
-
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
@@ -148,6 +146,9 @@ class AutoDacFragment: Fragment() {
autoDacViewModel.addAutoDacDataToDb(
DiagnosticsData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
+ devicePassword = sharedPreferences.getString(Constants.DEVICE_PASSWORD_API, "").toString(),
+ deviceNatsToken = sharedPreferences.getString(Constants.NATS_TOKEN, "").toString(),
+ accessToken = sharedPreferences.getString(Constants.ACCESS_TOKEN, "").toString(),
deviceData = resultData,
runTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
@@ -169,7 +170,6 @@ class AutoDacFragment: Fragment() {
}
}
-
fun parseData(inputData: List): List> {
val pattern = Regex("([A-Z]+)\\s(\\d+)")
val parsedData = mutableListOf>()
diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt
index 63b7cd9..3153f95 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt
@@ -4,7 +4,9 @@ import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
+import android.content.SharedPreferences
import android.net.Uri
+import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.Menu
@@ -19,9 +21,11 @@ import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.data.Result
+import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.NatsManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
+import com.example.hpostesting.presentation.jig.JigActivity
import com.google.android.material.navigation.NavigationView
import com.google.firebase.appdistribution.FirebaseAppDistribution
import com.google.firebase.appdistribution.FirebaseAppDistributionException
@@ -32,15 +36,22 @@ import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import okhttp3.ResponseBody
import java.io.File
-open interface IDataCollector {
+interface NatsMessageCallback {
+ fun onMessageReceived(topic: String, message: String)
+}
+
+open interface IDataCollector: NatsMessageCallback {
fun setConnect(connect: Boolean)
fun setResponse(response: String)
}
+
@AndroidEntryPoint
class DashboardActivity : AppCompatActivity(), IDataCollector {
+ val TAG = "DashboardActivity"
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDashboardBinding
+ lateinit var sharedPreferences: SharedPreferences
var responses: String = ""
lateinit var nats: NatsManager
private var downloadId: Long = 0
@@ -53,15 +64,27 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
super.attachBaseContext(newBase)
}
+ override fun onMessageReceived(topic: String, message: String) {
+ // Handle incoming messages from NATS
+ Log.d(TAG, "Received message on topic $topic: $message")
+ }
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDashboardBinding.inflate(layoutInflater)
+ sharedPreferences = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar)
nats = NatsManager(this)
- nats.connect()
- nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ nats.connect()
+ }
+
+ val deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "")
+
+ nats.sub("server.hpos.${deviceId}.ping")
+ nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG")
hemocubeViewModel.deviceUpdate.observe(this) { result ->
when (result) {
@@ -71,11 +94,11 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
// val apkUrl = "https://dl.dropboxusercontent.com/s/fi/1c3nn7t0co431hicl3hrt/app-debug.apk?rlkey=e4uf13ty1dpcked614vy1aaqp&dl=0"
initiateUpdate(apkUrl.toString())
Log.d("ApI", "APK URL: $apkUrl")
- Toast.makeText(
- this,
- "APK UPLOAD ${result.data}",
- Toast.LENGTH_SHORT
- ).show()
+// Toast.makeText(
+// this,
+// "APK UPLOAD ${result.data}",
+// Toast.LENGTH_SHORT
+// ).show()
}
is Result.Error -> {
@@ -105,6 +128,11 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
+
+ if (Constants.NAVIGATE_TO_TEST_JIG_DIRECTLY) {
+ startActivity(Intent(this, JigActivity::class.java))
+ finish()
+ }
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -156,9 +184,10 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
val file = File(getExternalFilesDir("Updates"), "update.apk")
file.setReadable(true, false) // Ensure the file is readable
+ val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
val uri: Uri = FileProvider.getUriForFile(
this,
- "com.example.hpostesting.fileprovider",
+ "${pInfo}.fileprovider",
file
)
diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt
index 387324c..539b6e8 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt
@@ -1,6 +1,7 @@
package com.example.hpostesting.presentation.dashboard
import android.annotation.SuppressLint
+import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
@@ -14,12 +15,13 @@ import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.autodac.AutoDacActivity
import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity
import com.example.hpostesting.presentation.calibration.CalibrationActivity
-import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity
import com.example.hpostesting.presentation.deviceinfo.DeviceActivity
+import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
+
class GalleryFragment : Fragment() {
private var _binding: FragmentGalleryBinding? = null
@@ -55,7 +57,7 @@ class GalleryFragment : Fragment() {
) {
binding.btnDeviceProvision.visibility = View.VISIBLE
} else {
- binding.btnDeviceProvision.visibility = View.GONE
+ binding.btnDeviceProvision.visibility = View.VISIBLE
}
binding.btnDeviceProvision.setOnClickListener {
@@ -82,6 +84,19 @@ class GalleryFragment : Fragment() {
startActivity(Intent(requireContext(), DeviceActivity::class.java))
}
+ binding.btnFirefox.setOnClickListener {
+ val intent = Intent(Intent.ACTION_VIEW)
+ intent.component = ComponentName("org.mozilla.firefox", "org.mozilla.gecko.BrowserApp")
+ startActivity(intent)
+ }
+
+ binding.btnFiles.setOnClickListener {
+ val intent = Intent(Intent.ACTION_GET_CONTENT)
+ intent.type = "file/*"
+ startActivity(intent)
+
+ }
+
userid = sharedPreferences.getString(Constants.USER_ID, "").toString()
binding.tvSubtitle4.text = "Login ID : ${userid}"
diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt
index 97d6094..49359b7 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt
@@ -19,16 +19,20 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.Result
+import com.example.hpostesting.data.api.DeviceCommunicationHandler
import com.example.hpostesting.data.constant.Constants
+import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2Result
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
+import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.KitScanActivity
+import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
@@ -43,11 +47,19 @@ import com.google.firebase.perf.ktx.performance
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
+import okhttp3.ResponseBody
import org.json.JSONObject
+import java.io.BufferedOutputStream
+import java.io.File
+import java.io.FileInputStream
+import java.io.FileOutputStream
+import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale
+import java.util.zip.ZipEntry
+import java.util.zip.ZipInputStream
@AndroidEntryPoint
class HomeFragment : Fragment() {
@@ -62,6 +74,9 @@ class HomeFragment : Fragment() {
private val homeViewModel: HemoCubeViewModel by activityViewModels()
private var isTokenAvailable = false
+ private var natsToken: String = ""
+ private var deviceId: String = ""
+
private lateinit var sharedPreference: SharedPreferences
override fun onCreateView(
@@ -89,7 +104,7 @@ class HomeFragment : Fragment() {
binding.labelQuickCapture.visibility = View.VISIBLE
binding.btnQuickCapture.visibility = View.VISIBLE
}
-
+ getDeviceId()
checkUnprocessedCSVData()
viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteIncompleteRegistrations(userData)
@@ -110,15 +125,55 @@ class HomeFragment : Fragment() {
binding.rvOrderOffline.adapter = adapter
}
}
+ hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) { deviceData ->
+ val devicelist = mutableListOf()
+ if (deviceData != null) {
+ devicelist.add(DeviceData(deviceData.deviceId))
+ }
+
+ }
viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected ->
if (isConnected) {
-
binding.internetAvailableCL.visibility = View.VISIBLE
binding.internetNotAvailableCL.visibility = View.GONE
loadUserData()
setSearch()
checkForLocalDBData()
checkForTokenAndUpdate()
+
+ hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
+ val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
+ userDataList.forEach { userData ->
+ if (!userData.molbioFlag && isTokenAvailable) {
+ resultList.results?.add(
+ MolbioV2Result(
+ rawData = userData,
+ analysisId = userData._id,
+ analysisDate = "2024-02-08 16:33:56",
+ analysisStatus = userData.classificationResult,
+ thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(),
+ interpretation = userData.classificationResult,
+ testId = userData._id,
+ testTime = userData.testTime,
+ collectionTime = "2024-02-08 16:33:56",//userData.testTime,
+ expiryTime = "2024-02-08 16:33:56"//userData.testTime,
+ )
+ )
+ }
+ if (!userData.molbioFlag && isTokenAvailable) {
+ userData.molbioFlag = true
+ hemoCubeViewModel.uploadResult(resultList)
+ }
+ if (!userData.localFlag) {
+ userData.localFlag = true
+ hemoCubeViewModel.bulkAddResultTestToDb(userData)
+ }
+
+ }
+
+ }
+
+
} else {
binding.internetAvailableCL.visibility = View.GONE
binding.internetNotAvailableCL.visibility = View.VISIBLE
@@ -149,9 +204,9 @@ class HomeFragment : Fragment() {
val btnSaveLocalVisibility =
if (userData.any { it.testStatus == true }) View.VISIBLE else View.GONE
- binding.btnSaveLocal.visibility = btnSaveLocalVisibility
+ binding.downloadCSV.visibility = btnSaveLocalVisibility
- binding.btnSaveLocal.setOnClickListener {
+ binding.downloadCSV.setOnClickListener {
if (btnSaveLocalVisibility == View.VISIBLE) {
// Execute the action when the button is visible (testStatus is true for at least one user)
showDownloadDialog(requireContext())
@@ -165,6 +220,8 @@ class HomeFragment : Fragment() {
}
}
}
+
+
binding.btnNewKit.setOnClickListener {
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "")
@@ -186,32 +243,55 @@ class HomeFragment : Fragment() {
binding.downloadCSV.setOnClickListener {
showDownloadDialog(requireContext())
}
+
}
private fun checkForTokenAndUpdate() {
- val accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
- val password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
- val userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
+ var accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
+ var password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
+ var userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
+ deviceId = sharedPreference.getString(Constants.DEVICE_ID, "").toString()
+ Log.e("idpass", userID)
+ Log.e("idpass", password)
+ Log.e("idpass", deviceId)
if (userID.isNotEmpty() && password.isNotEmpty()) {
- if (accessToken.isEmpty()) {
+ if (!isTokenAvailable) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
if (isTokenExpired(accessToken)) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
isTokenAvailable = true
+
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.startPeriodicCheckUpdate()
+ hemoCubeViewModel.downloadClientCertificate()
}
}
- } else {
+ }else if (deviceId.isNotEmpty()) {
+ fetchDeviceCredentials()
+ // This code will execute after credentials have been successfully fetched and stored.
+ userID = sharedPreference.getString("username", "").toString()
+ password = sharedPreference.getString("password", "").toString()
+ accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
+ if (accessToken.isEmpty()) {
+ hemoCubeViewModel.login(createLoginRequestData(userID, password))
+ } else {
+ // Continue with your existing logic if the token is not empty.
+ isTokenAvailable = true
+ hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
+ hemoCubeViewModel.uploadLogs()
+ hemoCubeViewModel.startPeriodicCheckUpdate()
+ }
+ } else {
Toast.makeText(
requireContext(),
"Contact Help and get your device provision done",
Toast.LENGTH_SHORT
).show()
}
+
hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
@@ -240,11 +320,11 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.uploadLogs.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
- Toast.makeText(
- requireContext(),
- "Log uploaded ${response.data.data?.filename}",
- Toast.LENGTH_SHORT
- ).show()
+// Toast.makeText(
+// requireContext(),
+// "Log uploaded ${response.data.data?.filename}",
+// Toast.LENGTH_SHORT
+// ).show()
}
is Result.Error -> {
@@ -266,6 +346,41 @@ class HomeFragment : Fragment() {
}
}
+
+
+ hemoCubeViewModel.downloadcertificate.observe(viewLifecycleOwner) { response ->
+ when (response) {
+ is Result.Success -> {
+ val url = response.data
+
+ val fileName = "nats_certificate.zip"
+ val downloadDirectory = "NATS"
+ val file = downloadFile(url, requireContext(), fileName, downloadDirectory)
+ Toast.makeText(requireContext(), "NATS certificate Downloaded", Toast.LENGTH_SHORT).show()
+
+ val unzipDirectoryPath = requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory"
+ unzip(file.absolutePath, unzipDirectoryPath)
+ Toast.makeText(requireContext(), "NATS certificate Extracted", Toast.LENGTH_SHORT).show()
+ }
+ is Result.Error -> {
+ response.exception.let { message ->
+ Toast.makeText(
+ activity,
+ "An error occurred in nats download: $message",
+ Toast.LENGTH_LONG
+ )
+ .show()
+ }
+ }
+
+ is Result.Loading -> {
+
+ }
+
+ else -> {}
+ }
+ }
+
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) {
is Result.Success -> {
@@ -290,8 +405,11 @@ class HomeFragment : Fragment() {
else -> {}
}
}
+
+
}
+
private fun isTokenExpired(token: String): Boolean {
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
@@ -341,6 +459,60 @@ class HomeFragment : Fragment() {
)
}
+ private fun downloadFile(responseBody: ResponseBody, context: Context, fileName: String, downloadDirectory: String): File {
+ // Ensure the download directory exists
+ val fileDir = File(context.getExternalFilesDir(null), downloadDirectory)
+ if (!fileDir.exists()) {
+ fileDir.mkdirs()
+ }
+ val file = File(fileDir, fileName)
+ Log.d("Download", "Starting download to $file")
+ responseBody.byteStream().use { inputStream ->
+ FileOutputStream(file).use { outputStream ->
+ inputStream.copyTo(outputStream)
+ }
+ }
+
+// After download
+ Log.d("Download", "Download completed to ${file.absolutePath}")
+
+ return file
+ }
+
+
+
+
+ private fun unzip(zipFilePath: String, destDirectory: String) {
+ val destDir = File(destDirectory)
+ if (!destDir.exists()) {
+ destDir.mkdir()
+ }
+ ZipInputStream(FileInputStream(zipFilePath)).use { zipIn ->
+ var entry: ZipEntry? = zipIn.nextEntry
+ while (entry != null) {
+ val filePath = destDirectory + File.separator + entry.name
+ if (!entry.isDirectory) {
+ extractFile(zipIn, filePath)
+ } else {
+ val dir = File(filePath)
+ dir.mkdir()
+ }
+ zipIn.closeEntry()
+ entry = zipIn.nextEntry
+ }
+ }
+ }
+
+ private fun extractFile(zipIn: ZipInputStream, filePath: String) {
+ BufferedOutputStream(FileOutputStream(filePath)).use { bos ->
+ val bytesIn = ByteArray(4096)
+ var read: Int
+ while (zipIn.read(bytesIn).also { read = it } != -1) {
+ bos.write(bytesIn, 0, read)
+ }
+ }
+ }
+
private fun setUserId() {
binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString()
@@ -366,6 +538,48 @@ class HomeFragment : Fragment() {
}
}
+
+ private fun fetchDeviceCredentials() {
+ try {
+ val db = Firebase.firestore
+ // Ensure deviceId is not null or empty
+ val deviceId = sharedPreference.getString(Constants.DEVICE_ID, "").takeIf { it!!.isNotBlank() }
+ ?: throw IllegalStateException("Device ID is missing or blank.")
+
+ val deviceRef = db.collection("devices").whereEqualTo("deviceId", deviceId)
+
+ deviceRef.get()
+ .addOnSuccessListener { documentSnapshot ->
+ if (!documentSnapshot.isEmpty) {
+ val deviceData = documentSnapshot.documents[0].toObject(DeviceData::class.java)
+ deviceData?.let { data ->
+ val username = data.username
+ val password = data.password
+ val natsToken = data.natsToken
+ // Log for debugging
+ Log.d("fetchDeviceCredentials", "Username: $username, Password: $password")
+ // Save credentials in SharedPreferences
+ with(sharedPreference.edit()) {
+ putString("username", username)
+ putString("password", password)
+ putString(Constants.NATS_TOKEN, natsToken)
+ apply()
+ }
+ hemoCubeViewModel.login(createLoginRequestData(username, password))
+ } ?: Log.e("fetchDeviceCredentials", "Failed to parse device data.")
+ } else {
+ Log.e("fetchDeviceCredentials", "Document does not exist.")
+ }
+ }
+ .addOnFailureListener { exception ->
+ Log.e("fetchDeviceCredentials", "Error fetching device data", exception)
+ }
+ } catch (e: Exception) {
+ Log.e("fetchDeviceCredentials", "Error in fetchDeviceCredentials", e)
+ }
+ }
+
+
private fun loadUserData() {
try {
val dateFormat = SimpleDateFormat("yyyy-MM-dd")
@@ -593,29 +807,32 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
userDataList.forEach { userData ->
- if (!userData.localFlag) {
- userData.localFlag = true
- hemoCubeViewModel.bulkAddResultTestToDb(userData)
if (!userData.molbioFlag && isTokenAvailable) {
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
- analysisDate = userData.testTime,
+ analysisDate = "2024-02-08 16:33:56", //userData.reportUploadTime,
analysisStatus = userData.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(),
interpretation = userData.classificationResult,
testId = userData._id,
testTime = userData.testTime,
- collectionTime = userData.testTime,
- expiryTime = userData.testTime,
+ collectionTime = "2024-02-08 16:33:56",//userData.testTime,
+ expiryTime = "2024-02-08 16:33:56",//userData.testTime,
)
)
- }
+
+ }
+
+ if(!userData.localFlag){
+ userData.localFlag = true
+ hemoCubeViewModel.bulkAddResultTestToDb(userData)
+ }
+ if (!userData.molbioFlag && isTokenAvailable) {
+ userData.molbioFlag = true
+ hemoCubeViewModel.uploadResult(resultList)
}
- }
- if (isTokenAvailable) {
- hemoCubeViewModel.uploadResult(resultList)
}
dialog.dismiss()
}
@@ -748,4 +965,44 @@ class HomeFragment : Fragment() {
}
}
}
-}
\ No newline at end of file
+
+ private fun getDeviceId() {
+ val handler = activity as? DeviceCommunicationHandler
+ handler?.sendAndListenToDevice(
+ HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
+ object : UsbServiceListener {
+ override fun onUsbRead(data: ByteArray?) {
+ data?.let {
+ val receivedData = String(it, Charset.forName("UTF-8"))
+ // Assuming the device ID is the full content of the received data. Adjust if needed.
+ deviceId =
+ extractDeviceId(receivedData) // Implement this method based on your data format.
+ if (deviceId.isNotEmpty()) {
+ // Store the deviceId in SharedPreferences
+ with(sharedPreference.edit()) {
+ putString(Constants.DEVICE_ID, deviceId)
+ apply()
+ }
+ // Optionally, you can update UI or proceed with further logic now that you have the device ID
+ activity?.runOnUiThread {
+ // Update your UI or trigger next steps here
+ }
+ }
+ }
+ }
+
+ override fun onUsbError(e: Exception?) {
+ // Handle USB communication error
+ }
+
+ })
+ }
+
+ fun extractDeviceId(receivedData: String): String {
+ // Example based on the format "SNS HPP1-3038 SNE"
+ val regex = "SNS (\\w+) SNE".toRegex()
+ val matchResult = regex.find(receivedData)
+ return matchResult?.groups?.get(1)?.value ?: ""
+ }
+
+}
diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceActivity.kt
index 60db0cd..53fd89c 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceActivity.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceActivity.kt
@@ -22,8 +22,11 @@ import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
+import com.example.hpostesting.data.api.DeviceCommunicationHandler
import com.example.hpostesting.data.constant.Constants
+import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager
+import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -33,7 +36,7 @@ import `in`.sminnovations.hpostesting.databinding.ActivityDeviceBinding
@Suppress("MemberVisibilityCanBePrivate")
@AndroidEntryPoint
-class DeviceActivity : AppCompatActivity() {
+class DeviceActivity : AppCompatActivity(), DeviceCommunicationHandler {
private lateinit var binding: ActivityDeviceBinding
private val deviceViewModel by viewModels()
private var myMenu: Menu? = null
@@ -177,4 +180,8 @@ class DeviceActivity : AppCompatActivity() {
deviceViewModel.isServiceConnected = false
}
}
+
+ override fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener) {
+ mService.sendAndListenToHemoCube(command = HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND, listener)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceViewModel.kt
index 4f43ca8..0d2e5d8 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceViewModel.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceViewModel.kt
@@ -20,6 +20,7 @@ class DeviceViewModel @Inject constructor(
val deviceData = MutableLiveData()
// val networkStatusLiveData: LiveData
// get() = _networkStatusLiveData
- val fireBaseUpload = MutableLiveData()
+val fireBaseUpload = MutableLiveData()
+ val fireBaseBulkUpload = MutableLiveData()
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionActivity.kt
index 1e316ff..1e2c5bd 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionActivity.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionActivity.kt
@@ -21,8 +21,11 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
+import com.example.hpostesting.data.api.DeviceCommunicationHandler
import com.example.hpostesting.data.constant.Constants
+import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager
+import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -31,7 +34,7 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityAutoDacBinding
@AndroidEntryPoint
-class DeviceProvisionActivity : AppCompatActivity() {
+class DeviceProvisionActivity : AppCompatActivity(), DeviceCommunicationHandler {
private lateinit var binding: ActivityAutoDacBinding
val viewModel: DeviceProvisionViewModel by viewModels()
private var myMenu: Menu? = null
@@ -180,4 +183,8 @@ class DeviceProvisionActivity : AppCompatActivity() {
viewModel.isServiceConnected = false
}
}
+
+ override fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener) {
+ mService.sendAndListenToHemoCube(command = HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND, listener)
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt
index 5ebc428..c15bda0 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt
@@ -4,16 +4,19 @@ import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
+import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
+import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.firebase.crashlytics.ktx.crashlytics
@@ -21,11 +24,14 @@ import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding
class DeviceProvisionFragment : Fragment() {
-
private var resultData: String = ""
private lateinit var binding: FragmentDeviceProvisionBinding
private val viewModel: DeviceProvisionViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
+ private lateinit var deviceProvisionResponse: String
+ private var currentDeviceData: DeviceData? = null
+ private var isOnline = false
+ val deviceData = MutableLiveData()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
@@ -33,13 +39,11 @@ class DeviceProvisionFragment : Fragment() {
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
-
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
}
-
private fun initViews() {
listenToHemoCube()
getDeviceId()
@@ -55,7 +59,11 @@ class DeviceProvisionFragment : Fragment() {
}
}
+
private fun observeViewModel() {
+ viewModel.deviceData.observe(viewLifecycleOwner) {
+ currentDeviceData = it
+ }
viewModel.deviceProvisionResponse.observe(viewLifecycleOwner) { response ->
when (response) {
@@ -74,20 +82,44 @@ class DeviceProvisionFragment : Fragment() {
Constants.NATS_TOKEN,
response.data.data?.device?.deviceUser?.natsToken
)
+ response.data.data?.device?.deviceUser?.natsToken?.let {
+ Log.e("natstoken",
+ it
+ )
+ }
putString(
Constants.NATS_TOKEN_EXPIRE_DATE,
response.data.data?.device?.deviceUser?.natsTokenExpiry
)
apply()
}
- startActivity(Intent(requireContext(), DashboardActivity::class.java))
+ startActivity(
+ Intent(
+ requireContext(),
+ DashboardActivity::class.java
+ )
+ )
Toast.makeText(
activity, "Device registered successfully", Toast.LENGTH_LONG
).show()
+ viewModel.addDeviceProvisionDataToDb(
+ DeviceData(
+ deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
+ username = response.data.data?.credentials?.username.toString(),
+ password = response.data.data?.credentials?.password.toString(),
+ deviceProvisionResponse = response.data.data.toString(),
+ natsToken = response.data.data?.device?.deviceUser?.natsToken.toString(),
+ natsTokenExpiry = response.data.data?.device?.deviceUser?.natsTokenExpiry.toString()
+ )
+ )
+// viewModel.addDeviceId(DeviceData(deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()))
+ Log.e("idpass",response.toString())
+ Log.e("idpass",response.data.data?.credentials?.username.toString())
+ Log.e("idpass",deviceProvisionResponse)
} else {
Toast.makeText(
activity,
- "An error occurred in device provision: ${response.data.message}",
+ "An error in device provision: ${response.data.message}",
Toast.LENGTH_LONG
).show()
binding.btnSubmit.visibility = View.VISIBLE
@@ -112,9 +144,15 @@ class DeviceProvisionFragment : Fragment() {
else -> {}
}
}
+ viewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
+ if (result == "Success") {
+ Toast.makeText(
+ activity, "Device provision successfully uploaded to firebase", Toast.LENGTH_LONG
+ ).show()
+ }
+ }
}
-
private fun getDeviceId() {
(activity as DeviceProvisionActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
@@ -129,7 +167,8 @@ class DeviceProvisionFragment : Fragment() {
val fullReadOutput = StringBuilder()
try {
- (activity as DeviceProvisionActivity).mService.listenToHemoCube(object : UsbServiceListener {
+ (activity as DeviceProvisionActivity).mService.listenToHemoCube(object :
+ UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)
@@ -146,14 +185,19 @@ class DeviceProvisionFragment : Fragment() {
}
}
+ fun extractV2HardwareId(input: String): String? {
+ val pattern = Regex("SNS\\s*(.*?)\\s*SNE")
+ val matchResult: MatchResult? = pattern.find(input)
+
+ return matchResult?.groups?.get(1)?.value
+ }
+
private fun handleUsbData() {
when {
resultData.contains("SNE") -> {
- val pattern = Regex("HPP1-\\d{4}")
- val matchResult = pattern.find(resultData)
- val hardwareId = matchResult?.value
+ val hardwareId = extractV2HardwareId(resultData)
- if (hardwareId.toString().length == 9) {
+ if (!hardwareId.isNullOrBlank()) {
with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId)
apply()
diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionViewModel.kt
index b64a2a9..466e0d5 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionViewModel.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionViewModel.kt
@@ -4,8 +4,10 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.Result
+import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
+import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
@@ -13,17 +15,54 @@ import javax.inject.Inject
@HiltViewModel
class DeviceProvisionViewModel @Inject constructor(
- private val databaseRepository: Repository
+ private val repository: Repository,
) : ViewModel() {
-
var isServiceConnected = false
-
val deviceProvisionResponse = MutableLiveData>()
+ val fireBaseUpload = MutableLiveData()
+ val fireBaseBulkUpload = MutableLiveData()
+ val deviceData = MutableLiveData()
fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
deviceProvisionResponse.postValue(Result.Loading())
- databaseRepository.deviceProvision(deviceProvisionRequest).let {
+ repository.deviceProvision(deviceProvisionRequest).let {
deviceProvisionResponse.postValue(it)
}
}
+
+
+ fun addDeviceId(data: DeviceData) {
+ viewModelScope.launch {
+ try {
+ repository.uploadDeviceId(data)
+ fireBaseUpload.postValue("Successfully device Id uploaded to firebase")
+ } catch (e: Exception) {
+// Log.e("Testdb", "Exception during data upload: ${e.message}")
+ fireBaseUpload.postValue("Error")
+ }
+ }
+ }
+
+ fun addDeviceProvisionDataToDb(data: DeviceData) {
+ viewModelScope.launch {
+ try {
+ when (val response = repository.getDeviceResponse(data)) {
+ is Response.Success -> {
+// Log.i("Testdb", "Data uploaded to Firestore successfully")
+ fireBaseUpload.postValue("Successfully device response uploaded to firebase")
+ }
+
+ is Response.Error -> {
+// Log.e("Testdb", "Error uploading data to Firestore: $response")
+ fireBaseUpload.postValue("Error")
+ }
+
+ else -> {}
+ }
+ } catch (e: Exception) {
+// Log.e("Testdb", "Exception during data upload: ${e.message}")
+ fireBaseUpload.postValue("Error")
+ }
+ }
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt
index b536cad..3d1cec1 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt
@@ -212,6 +212,9 @@ class DiagnosticsFragment : Fragment() {
if (resultData.contains("END") || fullReadOutput.contains("END")) {
diagnosticsViewModel.addDiagnosticsDataToDb(DiagnosticsData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
+ devicePassword = sharedPreferences.getString(Constants.DEVICE_PASSWORD_API, "").toString(),
+ deviceNatsToken = sharedPreferences.getString(Constants.NATS_TOKEN, "").toString(),
+ accessToken = sharedPreferences.getString(Constants.ACCESS_TOKEN, "").toString(),
deviceData = resultData,
runTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt
index 70bb256..2878d75 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt
@@ -643,10 +643,10 @@ class HemoCubeFragment : Fragment() {
if (!Constants.DEVICE_CONFIGURATION.containsKey(deviceHardwareId)) {
assignDefaultDevice(resultData)
- testState.allErrorMessages += "Calibration configuration for this device id is not found\n"
+// testState.allErrorMessages += "Calibration configuration for this device id is not found\n"
}
if (!Constants.BUFFER_INTENSITY_THRESHOLDS.containsKey(deviceHardwareId)) {
- testState.allErrorMessages += "ADC thresholds for this device id are not found\n"
+// testState.allErrorMessages += "ADC thresholds for this device id are not found\n"
}
}
@@ -743,9 +743,9 @@ class HemoCubeFragment : Fragment() {
)?.get(0)!!
) {
// validationError = true
- testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)"
+// testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)"
activity?.runOnUiThread {
- binding.errorMessage.text = getString(R.string.error_improper_buffer_low)
+// binding.errorMessage.text = getString(R.string.error_improper_buffer_low)
// binding.errorMessage.visibility = View.VISIBLE
}
}
@@ -763,11 +763,11 @@ class HemoCubeFragment : Fragment() {
)?.get(1)!!
) {
// validationError = true
- testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n"
+// testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n"
activity?.runOnUiThread {
- binding.errorMessage.text =
+// binding.errorMessage.text =
getString(R.string.error_improper_buffer_high)
- binding.errorMessage.visibility = View.VISIBLE
+// binding.errorMessage.visibility = View.VISIBLE
}
}
@@ -811,9 +811,9 @@ class HemoCubeFragment : Fragment() {
if (fittedAbs1 <= fittedAbs2) {
// validationError = true
- testState.allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n"
+// testState.allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n"
activity?.runOnUiThread {
- binding.errorMessage.text = getString(R.string.error_invalid_test)
+// binding.errorMessage.text = getString(R.string.error_invalid_test)
// binding.errorMessage.visibility = View.VISIBLE
}
}
@@ -837,9 +837,9 @@ class HemoCubeFragment : Fragment() {
if (fittedAbs3 < 0.1) {
// validationError = true
- testState.allErrorMessages += "Error: Low Hb. Repeat test" + "\n"
+// testState.allErrorMessages += "Error: Low Hb. Repeat test" + "\n"
activity?.runOnUiThread {
- binding.errorMessage.text = "Error: Low Hb. Repeat test"
+// binding.errorMessage.text = "Error: Low Hb. Repeat test"
// binding.errorMessage.visibility = View.VISIBLE
}
}
@@ -874,8 +874,8 @@ class HemoCubeFragment : Fragment() {
this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio)
this.deviceRatioClass = deviceRatioClassification(deviceRatio)
this.slopeRatioClass = slopeClass
- this.classificationResult = findResultWithAdditionalMethods(deviceRatio, deviceRatioClass, slopeRatio)
- hemoCubeViewModel.messages.postValue("${this.classificationResult} ")
+ this.classificationResult = deviceRatioClass
+ hemoCubeViewModel.messages.postValue("${this.classificationResult} \n Device Ratio: ${"%.3f".format(this.deviceRatio)}")
if (DataHolder.hemoCubeTestData?.testType == "HB")
hemoCubeViewModel.messages.postValue("Hb: $calculatedHb4")
this.errorMessages = testState.allErrorMessages
@@ -914,7 +914,7 @@ class HemoCubeFragment : Fragment() {
// hemoCubeViewModel.messages.postValue("post classification checks")
if (deviceRatio != null) {
if (slopeRatio != null) {
- if (deviceRatioClass == "Normal" && slopeRatio > 60.0)
+ if (deviceRatioClass == "Normal" && slopeRatio > 45.0)
return "Negative Borderline, Repeat Test"
}
}
@@ -928,17 +928,17 @@ class HemoCubeFragment : Fragment() {
fun deviceRatioClassification(ratio: Double?): String {
try {
if (ratio != null) {
- if (ratio in 0.001..0.23) {
+ if (ratio in 0.016..0.22) {
// setSubtitleTextColor(R.color.green_2)
return "Normal"
}
- if (ratio in 0.23..0.24)
- return "Negative Borderline, Repeat Test"
- if (ratio in 0.24..0.29)
+ if (ratio in 0.22..0.24)
+ return "Negative Borderline"
+ if (ratio in 0.24..0.32)
return "Sickle Cell Trait"
- if (ratio in 0.29..0.32)
+ if (ratio in 0.32..0.37)
return "Positive for Sickle Cell. HPLC for Confirmation"
- if (ratio in 0.32..Double.POSITIVE_INFINITY)
+ if (ratio in 0.37..0.56)
return "Sickle Cell Disease"
} else {
return "Invalid"
diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt
index 79ad9e0..e733d97 100644
--- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt
+++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt
@@ -79,6 +79,7 @@ class HemoCubeViewModel @Inject constructor(
val checkUpdate = MutableLiveData>()
val deviceUpdate = MutableLiveData>()
+ val downloadcertificate = MutableLiveData>()
val uploadLogs = MutableLiveData?>()
@@ -155,6 +156,13 @@ class HemoCubeViewModel @Inject constructor(
}
}
+ fun downloadClientCertificate() = viewModelScope.launch {
+ downloadcertificate.postValue(Result.Loading())
+ repository.downloadClientCertificate().let {
+ downloadcertificate.postValue(it)
+ }
+ }
+
fun startPeriodicCheckUpdate() {
val periodicRequest = PeriodicWorkRequestBuilder(
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES
diff --git a/app/src/main/java/com/example/hpostesting/presentation/jig/JigActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/jig/JigActivity.kt
new file mode 100644
index 0000000..53950f0
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/presentation/jig/JigActivity.kt
@@ -0,0 +1,183 @@
+package com.example.hpostesting.presentation.jig
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.ServiceConnection
+import android.content.pm.ActivityInfo
+import android.hardware.usb.UsbDevice
+import android.hardware.usb.UsbDeviceConnection
+import android.hardware.usb.UsbManager
+import android.os.Bundle
+import android.os.IBinder
+import android.util.Log
+import android.view.Menu
+import android.widget.Toast
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.core.view.get
+import com.example.hpostesting.data.DataHolder
+import com.example.hpostesting.data.constant.Constants
+import com.example.hpostesting.data.constant.LanguageManager
+import com.example.hpostesting.presentation.testRight.UsbService
+import com.hoho.android.usbserial.driver.UsbSerialDriver
+import com.hoho.android.usbserial.driver.UsbSerialProber
+import dagger.hilt.android.AndroidEntryPoint
+import `in`.sminnovations.hpostesting.R
+import `in`.sminnovations.hpostesting.databinding.ActivityJigBinding
+
+@AndroidEntryPoint
+class JigActivity: AppCompatActivity(){
+ private lateinit var binding: ActivityJigBinding
+ val viewModel: JigViewModel by viewModels()
+ private var myMenu: Menu? = null
+
+ private lateinit var mDriver: UsbSerialDriver
+ private var mConnection: UsbDeviceConnection? = null
+ lateinit var mService: UsbService
+
+ private val TAG = "JIG"
+
+ private val broadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+
+ synchronized(this) {
+ val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
+
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ device?.apply {
+ connectUsb(true)
+ DataHolder.usbConnected.postValue(true)
+ }
+ } else {
+ onErrorReported("permission denied for device")
+ DataHolder.usbConnected.postValue(true)
+ }
+ }
+ }
+ }
+
+ private val connection = object : ServiceConnection {
+ override fun onServiceConnected(className: ComponentName, service: IBinder) {
+ val binder = service as UsbService.UsbServiceBinder
+ mService = binder.getService()
+ viewModel.isServiceConnected = true
+ mConnection.let { mService.connect(mDriver, mConnection!!) }
+ moveToNext()
+ }
+
+ override fun onServiceDisconnected(arg0: ComponentName) {
+ viewModel.isServiceConnected = false
+ }
+ }
+
+ override fun attachBaseContext(newBase: Context?) {
+ val languageCode = LanguageManager.getSavedLanguage(newBase!!)
+ LanguageManager.setLocale(newBase, languageCode)
+ super.attachBaseContext(newBase)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityJigBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+// setSupportActionBar(binding.myToolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+// setupListener()
+// connectUsb(false)
+
+ this.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE)
+
+ moveToNext()
+ }
+
+ private fun setupListener() {
+ DataHolder.usbConnected.observe(this) {
+ Log.d("USB OBSERVE", "HemoCube called -> $it")
+ if (it) {
+ myMenu?.get(0)?.icon =
+ ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
+ } else {
+ myMenu?.get(0)?.icon =
+ ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
+ Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ open fun connectUsb(permissionGranted: Boolean) {
+ Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
+ val manager = getSystemService(Context.USB_SERVICE) as UsbManager
+ val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
+
+ if (availableDrivers.isEmpty()) {
+ onErrorReported("No Device is Connected")
+ } else {
+ mDriver = availableDrivers[0]
+ mConnection = manager.openDevice(mDriver.device)
+
+ if (mConnection == null) {
+ requestUserPermission(manager, mDriver.device)
+ } else {
+ setupService()
+ }
+ }
+ }
+
+ fun onErrorReported(msg: String) {
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
+ if (!isFinishing) onBackPressed()
+ }
+
+ private fun moveToNext() {
+ if (supportFragmentManager.isDestroyed) return
+
+ supportFragmentManager.beginTransaction().replace(binding.fgJig.id, JigFragment())
+ .commit()
+ }
+
+ @SuppressLint("MutableImplicitPendingIntent")
+ private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
+ val mPendingIntent: PendingIntent
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+ mPendingIntent = PendingIntent.getBroadcast(
+ this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
+ )
+ } else {
+ mPendingIntent = PendingIntent.getBroadcast(
+ this,
+ 0,
+ Intent(Constants.HEMOCUBE_USB_PERMISSION),
+ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+
+ val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
+ registerReceiver(broadcastReceiver, filter)
+ manager.requestPermission(device, mPendingIntent)
+ }
+
+ fun setupService() {
+ val intent = Intent(this, UsbService::class.java)
+ bindService(intent, connection, Context.BIND_AUTO_CREATE)
+ }
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.my_menu, menu)
+ return true
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (viewModel.isServiceConnected) {
+ mService.disconnect()
+ unbindService(connection)
+ viewModel.isServiceConnected = false
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/presentation/jig/JigFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/jig/JigFragment.kt
new file mode 100644
index 0000000..9a7204a
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/presentation/jig/JigFragment.kt
@@ -0,0 +1,241 @@
+package com.example.hpostesting.presentation.jig
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.SharedPreferences
+import android.content.pm.PackageManager
+import android.os.Bundle
+import android.text.Editable
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.EditText
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import androidx.lifecycle.MutableLiveData
+import com.example.hpostesting.data.constant.Constants
+import com.example.hpostesting.data.model.jig.JigData
+import com.example.hpostesting.data.model.patient.DeviceData
+import com.journeyapps.barcodescanner.ScanContract
+import com.journeyapps.barcodescanner.ScanIntentResult
+import com.zebra.barcode.sdk.sms.ConfigurationUpdateEvent
+import com.zebra.scannercontrol.DCSSDKDefs
+import com.zebra.scannercontrol.DCSScannerInfo
+import com.zebra.scannercontrol.FirmwareUpdateEvent
+import com.zebra.scannercontrol.IDcsSdkApiDelegate
+import com.zebra.scannercontrol.SDKHandler
+import `in`.sminnovations.hpostesting.databinding.FragmentJigBinding
+import java.text.SimpleDateFormat
+import java.util.Calendar
+import java.util.Locale
+
+class JigFragment : Fragment(), IDcsSdkApiDelegate {
+ private lateinit var binding: FragmentJigBinding
+ private val jigViewModel: JigViewModel by activityViewModels()
+ private lateinit var sharedPreferences: SharedPreferences
+ private var currentDeviceData: DeviceData? = null
+ private var resultData: String = ""
+ private val messages = MutableLiveData()
+ private var startListening = MutableLiveData(false)
+
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
+ ): View {
+ binding = FragmentJigBinding.inflate(inflater, container, false)
+ sharedPreferences =
+ requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ initScanner()
+ initViews()
+ observeViewModel()
+ }
+
+ private fun initScanner() {
+ //Setting up the SDK handler
+ sdkHandler = SDKHandler(requireContext())
+ //Registers a particular object which conforms to IDcsSdkApiDelegate interface as a receiver of SDK notifications.
+ sdkHandler!!.dcssdkSetDelegate(this)
+ //this command is telling the sdk that we're going to be connecting to the scanner via USB
+ sdkHandler!!.dcssdkSetOperationalMode(DCSSDKDefs.DCSSDK_MODE.DCSSDK_OPMODE_SNAPI)
+
+ //deciding what kind of notifications we want to receive. Explained more in the function
+ //first we use bitmapping to set these values into the notifications_mask.
+ var notifications_mask = 0
+ // We would like to subscribe to all barcode events
+ notifications_mask =
+ notifications_mask or DCSSDKDefs.DCSSDK_EVENT.DCSSDK_EVENT_BARCODE.value
+ sdkHandler!!.dcssdkSubsribeForEvents(notifications_mask)
+ mScannerInfoList.addAll(sdkHandler!!.dcssdkGetAvailableScannersList())
+ Log.e("scannersize", sdkHandler!!.dcssdkGetAvailableScannersList().size.toString())
+ if (mScannerInfoList.isNotEmpty()) {
+ sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
+ } else {
+ Toast.makeText(requireContext(), "Scanner Error", Toast.LENGTH_LONG).show()
+ }
+ }
+
+ @SuppressLint("SetTextI18n")
+ private fun initViews() {
+ binding.btnScanNow.setOnClickListener {
+ pullTrigger()
+ }
+
+ binding.btnRefresh.setOnClickListener {
+ activity?.recreate()
+ initScanner()
+
+ activity?.runOnUiThread {
+ binding.tvScanText.text = ""
+ }
+ }
+
+ activity?.runOnUiThread {
+ binding.tvAppVersion.text =
+ getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + " ]"
+ }
+ }
+
+ private fun observeViewModel() {
+
+ jigViewModel.deviceData.observe(viewLifecycleOwner) {
+ currentDeviceData = it
+ }
+
+ messages.observe(viewLifecycleOwner) {
+ binding.tvScanText.text = it
+ }
+
+ jigViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
+ if (result == "Success") {
+ showToast("Data uploaded successfully")
+ }
+ if (result == "Local") {
+ showToast("Data uploading failed, note it down manually")
+ }
+
+ binding.progressBar.visibility = View.GONE
+ }
+ }
+
+ private fun getAppVersion(context: Context): String {
+ return try {
+ val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
+ pInfo.versionName
+ } catch (e: PackageManager.NameNotFoundException) {
+ "N/A"
+ }
+ }
+
+ private fun getAppEnvironment(context: Context): String {
+ return try {
+ val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
+ pInfo.packageName.substringAfterLast('.')
+ } catch (e: PackageManager.NameNotFoundException) {
+ "N/A"
+ }
+ }
+
+ private fun showToast(message: String) {
+ Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
+ }
+
+ var sdkHandler: SDKHandler? = null
+ var editBarcode: EditText? = null
+ var mScannerInfoList = ArrayList()
+
+ private val barcodeLauncher = registerForActivityResult(
+ ScanContract()
+ ) { result: ScanIntentResult ->
+ if (result.contents.isNullOrEmpty()) {
+// Toast.makeText(this, R.string.cancelled_unable_scan, Toast.LENGTH_LONG).show()
+ } else {
+// Log.d(TAG, result.contents)
+ processScannedData(result.contents)
+ }
+ }
+
+ private fun processScannedData(contents: String) {
+ binding.tvScanText.setText(contents)
+ }
+
+ private fun pullTrigger() {
+ // Check if the list is not empty before accessing its elements
+ if (mScannerInfoList.isNotEmpty()) {
+ // Only proceed if the scanner is not active
+ if (!mScannerInfoList[0].isActive) {
+ sdkHandler?.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
+ }
+ val inXML = " 1 "
+ val outXML = StringBuilder()
+ val result: DCSSDKDefs.DCSSDK_RESULT =
+ sdkHandler!!.dcssdkExecuteCommandOpCodeInXMLForScanner(
+ DCSSDKDefs.DCSSDK_COMMAND_OPCODE.DCSSDK_DEVICE_PULL_TRIGGER,
+ inXML,
+ outXML,
+ mScannerInfoList[0].scannerID // Ensure you're using the correct scanner ID
+ )
+ if (result == DCSSDKDefs.DCSSDK_RESULT.DCSSDK_RESULT_SUCCESS) {
+ Log.d("Scanning", "Success")
+ } else if (result == DCSSDKDefs.DCSSDK_RESULT.DCSSDK_RESULT_FAILURE) {
+ Log.d("Scanning", "Failed")
+ }
+ } else {
+ // Handle the case where the list is empty, perhaps notify the user or log an error
+ Log.e("ScannerError", "No scanners are connected or available.")
+ }
+ }
+
+ override fun dcssdkEventBarcode(barcodeData: ByteArray?, barcodeType: Int, fromScannerID: Int) {
+ val result = String(barcodeData!!)
+ Log.d("BARCODE", result)
+ activity?.runOnUiThread {
+ val editableResult: Editable = Editable.Factory.getInstance().newEditable(result)
+ binding.tvScanText.text = result
+
+ jigViewModel.addScanDataToDb(
+ JigData(
+ deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
+ scanData = result,
+ createdAt = SimpleDateFormat(
+ "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
+ ).format(Calendar.getInstance().time)
+ )
+ )
+ }
+ }
+
+ override fun dcssdkEventScannerAppeared(dcsScannerInfo: DCSScannerInfo?) {}
+
+ override fun dcssdkEventScannerDisappeared(i: Int) {}
+
+ override fun dcssdkEventCommunicationSessionEstablished(dcsScannerInfo: DCSScannerInfo?) {}
+
+ override fun dcssdkEventCommunicationSessionTerminated(i: Int) {}
+// override fun dcssdkEventBarcode(p0: ByteArray?, p1: Int, p2: Int) {
+// TODO("Not yet implemented")
+// }
+
+
+ override fun dcssdkEventImage(bytes: ByteArray?, i: Int) {}
+
+ override fun dcssdkEventVideo(bytes: ByteArray?, i: Int) {}
+
+ override fun dcssdkEventBinaryData(bytes: ByteArray?, i: Int) {}
+
+ override fun dcssdkEventFirmwareUpdate(firmwareUpdateEvent: FirmwareUpdateEvent?) {}
+
+ override fun dcssdkEventAuxScannerAppeared(
+ dcsScannerInfo: DCSScannerInfo?,
+ dcsScannerInfo1: DCSScannerInfo?,
+ ) {
+ }
+
+ override fun dcssdkEventConfigurationUpdate(configurationUpdateEvent: ConfigurationUpdateEvent?) {}
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/presentation/jig/JigViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/jig/JigViewModel.kt
new file mode 100644
index 0000000..c51678c
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/presentation/jig/JigViewModel.kt
@@ -0,0 +1,49 @@
+package com.example.hpostesting.presentation.jig
+
+import android.content.Context
+import android.content.SharedPreferences
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.hpostesting.data.dao.HemoCubeDao
+import com.example.hpostesting.data.model.Response
+import com.example.hpostesting.data.model.jig.JigData
+import com.example.hpostesting.data.model.patient.DeviceData
+import com.example.hpostesting.data.repository.Repository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class JigViewModel @Inject constructor(
+ private val hemoCubeDao: HemoCubeDao,
+ private val repository: Repository,
+ context: Context
+) : ViewModel() {
+ var isServiceConnected = false
+ val progressBar = MutableLiveData(false)
+ val messages = MutableLiveData()
+ private val sharedPreference: SharedPreferences =
+ context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
+
+ val deviceData = MutableLiveData()
+ val fireBaseUpload = MutableLiveData()
+
+ fun addScanDataToDb(data: JigData) {
+ viewModelScope.launch {
+ try {
+ when (val response = repository.addTestJigData(data)) {
+ is Response.Success -> {
+ fireBaseUpload.postValue("Success")
+ }
+
+ is Response.Error -> {
+ fireBaseUpload.postValue("Error")
+ }
+ }
+ } catch (e: Exception) {
+ fireBaseUpload.postValue("Error")
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/drawable/downloads.xml b/app/src/main/res/drawable/downloads.xml
new file mode 100644
index 0000000..37f8230
--- /dev/null
+++ b/app/src/main/res/drawable/downloads.xml
@@ -0,0 +1,5 @@
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_jig.xml b/app/src/main/res/layout/activity_jig.xml
new file mode 100644
index 0000000..a0884e4
--- /dev/null
+++ b/app/src/main/res/layout/activity_jig.xml
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_gallery.xml b/app/src/main/res/layout/fragment_gallery.xml
index fd82fc3..2f2075f 100644
--- a/app/src/main/res/layout/fragment_gallery.xml
+++ b/app/src/main/res/layout/fragment_gallery.xml
@@ -77,13 +77,13 @@
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@id/btn_auto_dac" />
+ app:layout_constraintTop_toBottomOf="@id/btn_deviceProvision" />
+ app:layout_constraintTop_toBottomOf="@id/btn_auto_dac" />
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml
index df38b54..7343952 100644
--- a/app/src/main/res/layout/fragment_home.xml
+++ b/app/src/main/res/layout/fragment_home.xml
@@ -115,15 +115,15 @@
tools:listitem="@layout/offline_user_list_view" />
-
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_jig.xml b/app/src/main/res/layout/fragment_jig.xml
new file mode 100644
index 0000000..74caab0
--- /dev/null
+++ b/app/src/main/res/layout/fragment_jig.xml
@@ -0,0 +1,126 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/nav_header_dashboard.xml b/app/src/main/res/layout/nav_header_dashboard.xml
index cca7f24..1743b21 100644
--- a/app/src/main/res/layout/nav_header_dashboard.xml
+++ b/app/src/main/res/layout/nav_header_dashboard.xml
@@ -12,6 +12,12 @@
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
+
+
+
Quality Assurance
Calibration
Device Provision
+ Firefox
+ Files
Device Information
Start
Start Sample
diff --git a/app/src/test/java/com/example/hpostesting/HemoCubeFragmentTest.kt b/app/src/test/java/com/example/hpostesting/HemoCubeFragmentTest.kt
index e3c425f..d8e2a7e 100644
--- a/app/src/test/java/com/example/hpostesting/HemoCubeFragmentTest.kt
+++ b/app/src/test/java/com/example/hpostesting/HemoCubeFragmentTest.kt
@@ -327,7 +327,7 @@ class HemoCubeFragmentTest {
fun testDeviceRatioClassificationNegativeBorderline() {
val ratio = 0.235
val result = hemoCubeFragment.deviceRatioClassification(ratio)
- assertEquals("Negative Borderline, Repeat Test", result)
+ assertEquals("Negative Borderline", result)
}
@Test
@@ -339,7 +339,7 @@ class HemoCubeFragmentTest {
@Test
fun testDeviceRatioClassificationPositiveForSickleCell() {
- val ratio = 0.31
+ val ratio = 0.37
val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Positive for Sickle Cell. HPLC for Confirmation", result)
}
@@ -366,9 +366,37 @@ class HemoCubeFragmentTest {
}
@Test
- fun findResultWithAdditionalMethods_ValidInput_ReturnsDeviceRatioClassToString() {
+ fun findResultWithAdditionalMethods_NormalDeviceRatio_ReturnsNormalBelowSlopeRatioThreshold() {
+// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Normal", 70.0)).thenReturn("Negative Borderline, Repeat Test")
+ val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Normal", 30.0)
+ assertEquals("Normal", result)
+ }
+
+ @Test
+ fun findResultWithAdditionalMethods_NBL_ReturnsNBL() {
// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid")
- val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)
- assertEquals("Abnormal", result)
+ val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Negative Borderline, Repeat Test", 70.0)
+ assertEquals("Negative Borderline, Repeat Test", result)
+ }
+
+ @Test
+ fun findResultWithAdditionalMethods_SCT_ReturnsSCT() {
+// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid")
+ val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Sickle Cell Trait", 70.0)
+ assertEquals("Sickle Cell Trait", result)
+ }
+
+ @Test
+ fun findResultWithAdditionalMethods_PBL_ReturnsPBL() {
+// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid")
+ val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Positive for Sickle Cell. HPLC for Confirmation", 70.0)
+ assertEquals("Positive for Sickle Cell. HPLC for Confirmation", result)
+ }
+
+ @Test
+ fun findResultWithAdditionalMethods_SCD_ReturnsSCD() {
+// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid")
+ val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Sickle Cell Disease", 70.0)
+ assertEquals("Sickle Cell Disease", result)
}
}
\ No newline at end of file