Compare commits
8 Commits
2.1.119
...
device-pro
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
80eb658b07 | ||
|
|
9314b155cd | ||
|
|
7f47e1dff8 | ||
|
|
d5b6910408 | ||
|
|
89dc7f7234 | ||
|
|
c5cb8a0983 | ||
|
|
6ddb491bc8 | ||
|
|
c5c0467e42 |
@@ -16,11 +16,11 @@ android {
|
||||
|
||||
// dev - development, quality - qc, uat - User Acceptance Test, preprod - preproduction, prod - production
|
||||
defaultConfig {
|
||||
applicationId "in.sminnovations.hpostesting.quality"
|
||||
applicationId "in.sminnovations.hpostesting.dev"
|
||||
minSdk 21
|
||||
targetSdk 34
|
||||
versionCode 106
|
||||
versionName "2.1.106"
|
||||
versionCode 111
|
||||
versionName "2.1.111"
|
||||
|
||||
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 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
|
||||
implementation 'io.nats:jnats:2.11.2'
|
||||
|
||||
implementation("androidx.work:work-runtime-ktx:2.9.0")
|
||||
|
||||
@@ -165,6 +165,4 @@ dependencies {
|
||||
implementation 'com.google.android.play:core:1.10.3'
|
||||
|
||||
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
||||
implementation 'io.nats:jnats:2.11.4'
|
||||
|
||||
}
|
||||
@@ -1,45 +1,205 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "1004619739289",
|
||||
"project_id": "hpos-qa",
|
||||
"storage_bucket": "hpos-qa.appspot.com"
|
||||
"project_number": "650071678820",
|
||||
"project_id": "hpos-af3cc",
|
||||
"storage_bucket": "hpos-af3cc.appspot.com"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:1004619739289:android:f669b47552748433e5c808",
|
||||
"mobilesdk_app_id": "1:650071678820:android:f1435a1c07f710036c6471",
|
||||
"android_client_info": {
|
||||
"package_name": "in.sminnovations.hposregistration.quality"
|
||||
"package_name": "com.example.hposconsentform"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs"
|
||||
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:1004619739289:android:8397cd1f0357bd89e5c808",
|
||||
"mobilesdk_app_id": "1:650071678820:android:7865bef608cdee6f6c6471",
|
||||
"android_client_info": {
|
||||
"package_name": "in.sminnovations.hpostesting.quality"
|
||||
"package_name": "com.smi.counselling"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs"
|
||||
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:650071678820:android:2925e9ce3417d2386c6471",
|
||||
"android_client_info": {
|
||||
"package_name": "in.sminnovations.hemocube"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-srhm9spm9hjn4frcd3r6o02gdhdbtd15.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "in.sminnovations.hemocube",
|
||||
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:650071678820:android:7569c1cad4fc99916c6471",
|
||||
"android_client_info": {
|
||||
"package_name": "in.sminnovations.hposregistration"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-70kp5jvjda4r5diqch2kn4lc40p4f42g.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "in.sminnovations.hposregistration",
|
||||
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:650071678820:android:f96be19e5d43102b6c6471",
|
||||
"android_client_info": {
|
||||
"package_name": "in.sminnovations.hpostesting"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-l87dnr0bdj95get0khgnvfv2an1k6ogq.apps.googleusercontent.com",
|
||||
"client_type": 1,
|
||||
"android_info": {
|
||||
"package_name": "in.sminnovations.hpostesting",
|
||||
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:650071678820:android:a53292637abb7c0d6c6471",
|
||||
"android_client_info": {
|
||||
"package_name": "in.sminnovations.hpostesting.dev"
|
||||
}
|
||||
},
|
||||
"oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": [
|
||||
{
|
||||
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
|
||||
"client_type": 3
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
app/release/hpos-app.apk
Normal file
BIN
app/release/hpos-app.apk
Normal file
Binary file not shown.
@@ -4,15 +4,15 @@
|
||||
"type": "APK",
|
||||
"kind": "Directory"
|
||||
},
|
||||
"applicationId": "in.sminnovations.hpostesting.quality",
|
||||
"applicationId": "com.example.hpos",
|
||||
"variantName": "release",
|
||||
"elements": [
|
||||
{
|
||||
"type": "SINGLE",
|
||||
"filters": [],
|
||||
"attributes": [],
|
||||
"versionCode": 101,
|
||||
"versionName": "2.1.101",
|
||||
"versionCode": 1,
|
||||
"versionName": "1.0",
|
||||
"outputFile": "app-release.apk"
|
||||
}
|
||||
],
|
||||
|
||||
@@ -95,7 +95,6 @@
|
||||
android:exported="false"
|
||||
android:label="@string/title_activity_dashboard"
|
||||
android:theme="@style/Theme.HPOS.NoActionBar"
|
||||
android:screenOrientation="portrait"
|
||||
tools:ignore="AppLinkUrlError,MissingClass">
|
||||
|
||||
<intent-filter>
|
||||
@@ -119,13 +118,8 @@
|
||||
android:noHistory="true"
|
||||
android:theme="@style/AppTheme.NoActionBar">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
<category android:name="android.intent.category.HOME" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.MONKEY"/>
|
||||
<category android:name="android.intent.category.LAUNCHER_APP" />
|
||||
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
@@ -165,7 +159,7 @@
|
||||
|
||||
<provider
|
||||
android:name="androidx.core.content.FileProvider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:authorities="com.example.hpostesting.dev.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
|
||||
@@ -7,11 +7,8 @@ import com.example.hpostesting.data.model.updates.CheckUpdateRequest
|
||||
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
|
||||
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.Response
|
||||
import okhttp3.ResponseBody
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.GET
|
||||
import retrofit2.http.Header
|
||||
import retrofit2.http.Multipart
|
||||
import retrofit2.http.POST
|
||||
import retrofit2.http.PUT
|
||||
@@ -34,10 +31,6 @@ interface MolbioResultApi {
|
||||
@Body deviceUpdateRequest: DeviceUpdateRequest
|
||||
): ResponseBody
|
||||
|
||||
@GET("deviceService/device/getClientCertificate")
|
||||
suspend fun downloadClientCertificate(
|
||||
): ResponseBody
|
||||
|
||||
@Multipart
|
||||
@POST("deviceService/device/uploadLogs")
|
||||
suspend fun uploadLogs(
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
package com.example.hpostesting.data.api
|
||||
|
||||
import com.example.hpostesting.data.constant.HemoCubeCommands
|
||||
import com.example.hpostesting.presentation.UsbServiceListener
|
||||
|
||||
interface PropertyProvider {
|
||||
|
||||
fun getProperty(key: String): String
|
||||
}
|
||||
}
|
||||
|
||||
interface DeviceCommunicationHandler {
|
||||
fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener)
|
||||
}
|
||||
|
||||
@@ -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 = 25, exportSchema = false)
|
||||
@TypeConverters(Converters::class)
|
||||
abstract class MyDatabase : RoomDatabase() {
|
||||
abstract fun userDao(): UserDao
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.hpostesting.data.model.deviceprovision
|
||||
|
||||
data class ProvisionData(
|
||||
val username: String?,
|
||||
val password: String?,
|
||||
val natsToken: String?
|
||||
)
|
||||
|
||||
@@ -5,8 +5,5 @@ 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 = ""
|
||||
)
|
||||
@@ -2,6 +2,7 @@ package com.example.hpostesting.data.model.patient
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
|
||||
import com.google.firebase.firestore.PropertyName
|
||||
|
||||
@Entity(tableName = "device_table")
|
||||
@@ -15,5 +16,12 @@ data class DeviceData(
|
||||
@get:PropertyName("coefficients") @set:PropertyName("coefficients")
|
||||
var coefficients: List<Double> = 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 = ""
|
||||
|
||||
)
|
||||
@@ -77,9 +77,6 @@ class DatabaseRepository @Inject constructor(
|
||||
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) }
|
||||
}
|
||||
|
||||
override suspend fun downloadClientCertificate(): Result<ResponseBody> {
|
||||
return safeApiCall { molbioResultApi.downloadClientCertificate() }
|
||||
}
|
||||
override suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> {
|
||||
return safeApiCall { molbioResultApi.uploadLogs(logFile) }
|
||||
}
|
||||
@@ -206,7 +203,31 @@ class DatabaseRepository @Inject constructor(
|
||||
return allDeviceDataList.find { it.deviceId == deviceId }
|
||||
}
|
||||
|
||||
override suspend fun getDeviceResponse(data: DeviceData?): Response<String> {
|
||||
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<String>? {
|
||||
return try {
|
||||
db.collection("devices").add(data!!).await()
|
||||
Response.Success(data.deviceId)
|
||||
} catch (e: Exception) {
|
||||
Firebase.crashlytics.recordException(e)
|
||||
Response.Error(e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <UserData> addTestToDatabase(testDetails: UserData): Any {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,8 @@ interface Repository {
|
||||
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean>
|
||||
|
||||
suspend fun getDeviceDataById(deviceId: String): DeviceData?
|
||||
suspend fun getDeviceResponse(data: DeviceData?): Response<String>
|
||||
suspend fun uploadDeviceId(data: DeviceData): Response<String>?
|
||||
abstract fun <UserData> addTestToDatabase(testDetails: UserData): Any
|
||||
// suspend fun addToDatabase(data: PatientDetails)
|
||||
|
||||
@@ -45,6 +47,5 @@ interface Repository {
|
||||
|
||||
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody>
|
||||
|
||||
suspend fun downloadClientCertificate(): Result<ResponseBody>
|
||||
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse>
|
||||
}
|
||||
@@ -1,9 +1,6 @@
|
||||
package com.example.hpostesting.presentation
|
||||
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import androidx.annotation.RequiresApi
|
||||
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
|
||||
import com.example.hpostesting.presentation.dashboard.DashboardActivity
|
||||
import io.nats.client.AuthHandler
|
||||
import io.nats.client.Connection
|
||||
@@ -11,22 +8,9 @@ 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.BufferedInputStream
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.IOException
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Paths
|
||||
import java.security.GeneralSecurityException
|
||||
import java.security.KeyStore
|
||||
import java.security.SecureRandom
|
||||
import java.security.cert.CertificateFactory
|
||||
import javax.net.ssl.KeyManager
|
||||
import javax.net.ssl.KeyManagerFactory
|
||||
import javax.net.ssl.SSLContext
|
||||
import javax.net.ssl.TrustManager
|
||||
import javax.net.ssl.TrustManagerFactory
|
||||
|
||||
|
||||
class NatsManager(datacollector: DashboardActivity) {
|
||||
@@ -36,57 +20,17 @@ class NatsManager(datacollector: DashboardActivity) {
|
||||
val datacollector = datacollector
|
||||
var connect = false
|
||||
|
||||
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 = "SUAJH5VMO6GDRQA6QTXCLIJMS74IWIUTU3NJVYIOTZF2LBWUPD77DA2ZEA"
|
||||
Log.e("seedString",seedString)
|
||||
val seedString = "SUAEB5PUWNS6C2HUV3MFI6HUDEAPGPFPBHMI73NHIQATCDD2BWALVEZXZ4"
|
||||
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())
|
||||
.server("nats://192.168.10.117:4222")
|
||||
.authHandler(object : AuthHandler {
|
||||
override fun getID(): CharArray? {
|
||||
return try {
|
||||
@@ -124,11 +68,6 @@ class NatsManager(datacollector: DashboardActivity) {
|
||||
connect = true
|
||||
datacollector.setConnect(true)
|
||||
|
||||
if (nc?.status == Connection.Status.CONNECTED) {
|
||||
Log.e("NATSCONNECTION", "NATS is successfully connected.")
|
||||
} else {
|
||||
Log.e("NATSCONNECTION", "NATS is not connected. Current status: ${nc?.status}")
|
||||
}
|
||||
|
||||
nc?.publish(
|
||||
"server.hpos.HCV-000-3001.ping",
|
||||
@@ -143,10 +82,9 @@ class NatsManager(datacollector: DashboardActivity) {
|
||||
println("PRITIMOI SARKAR $msg")
|
||||
}
|
||||
|
||||
|
||||
d?.subscribe("device.hpos.HCV-000-3001.update") { msg ->
|
||||
val response = String(msg.data, StandardCharsets.UTF_8)
|
||||
datacollector.setResponse(response)
|
||||
datacollector. setResponse(response)
|
||||
println("Message received (up to 100 times): $response")
|
||||
}
|
||||
|
||||
@@ -177,7 +115,7 @@ class NatsManager(datacollector: DashboardActivity) {
|
||||
} catch (exp: Exception) {
|
||||
println(exp.printStackTrace())
|
||||
connect = false
|
||||
datacollector.setConnect(false)
|
||||
datacollector.setConnect(true)
|
||||
}
|
||||
}.start()
|
||||
|
||||
|
||||
@@ -3,19 +3,14 @@ package com.example.hpostesting.presentation.assurance
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import com.example.hpostesting.presentation.NatsManager
|
||||
import com.example.hpostesting.presentation.dashboard.IDataCollector
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import `in`.sminnovations.hpostesting.databinding.ActivityAssuranceControlsBinding
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AssuranceControlsActivity: AppCompatActivity(), IDataCollector {
|
||||
class AssuranceControlsActivity: AppCompatActivity() {
|
||||
lateinit var binding: ActivityAssuranceControlsBinding
|
||||
lateinit var sharedPreference: SharedPreferences
|
||||
lateinit var nats: NatsManager
|
||||
var responses: String = ""
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
@@ -29,21 +24,5 @@ class AssuranceControlsActivity: AppCompatActivity(), IDataCollector {
|
||||
.replace(binding.fgAssuranceControls.id, AssuranceControlsFragment())
|
||||
.commit()
|
||||
}
|
||||
|
||||
// nats = NatsManager(this)
|
||||
// nats.connect()
|
||||
// nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
|
||||
}
|
||||
|
||||
override fun setConnect(connect: Boolean) {
|
||||
if(connect){
|
||||
Log.i("NATS Connection", connect.toString())
|
||||
}
|
||||
}
|
||||
|
||||
override fun setResponse(response: String) {
|
||||
|
||||
responses = responses+response+"\n"
|
||||
println(responses)
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ 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
|
||||
@@ -31,9 +30,6 @@ 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
|
||||
}
|
||||
|
||||
@@ -46,7 +42,7 @@ class AssuranceControlsFragment: Fragment() {
|
||||
// binding.btnSubmit.visibility = View.GONE
|
||||
|
||||
val solutionSpinner: Spinner = binding.spinnerSolutions
|
||||
val solutionOptions = arrayOf("Select solution", "Tartrazine", "Acid Red")
|
||||
val solutionOptions = arrayOf("Select solution", "Tartrazine", "AR")
|
||||
val solutionAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, solutionOptions)
|
||||
solutionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
solutionSpinner.adapter = solutionAdapter
|
||||
@@ -125,13 +121,6 @@ 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
|
||||
|
||||
@@ -105,6 +105,8 @@ class AutoDacFragment: Fragment() {
|
||||
HemoCubeCommands.AUTO_DAC_COMMAND,
|
||||
object : UsbServiceListener {
|
||||
override fun onUsbRead(data: ByteArray?) {
|
||||
|
||||
|
||||
}
|
||||
override fun onUsbError(e: Exception?) {
|
||||
autoDacViewModel.progressBar.postValue(false)
|
||||
@@ -146,9 +148,6 @@ 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()
|
||||
@@ -170,6 +169,7 @@ class AutoDacFragment: Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun parseData(inputData: List<String>): List<Pair<String, String>> {
|
||||
val pattern = Regex("([A-Z]+)\\s(\\d+)")
|
||||
val parsedData = mutableListOf<Pair<String, String>>()
|
||||
|
||||
@@ -19,9 +19,13 @@ 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.api.DeviceCommunicationHandler
|
||||
import com.example.hpostesting.data.constant.HemoCubeCommands
|
||||
import com.example.hpostesting.data.constant.LanguageManager
|
||||
import com.example.hpostesting.presentation.NatsManager
|
||||
import com.example.hpostesting.presentation.UsbServiceListener
|
||||
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
|
||||
import com.example.hpostesting.presentation.testRight.UsbService
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
import com.google.firebase.appdistribution.FirebaseAppDistribution
|
||||
import com.google.firebase.appdistribution.FirebaseAppDistributionException
|
||||
@@ -156,10 +160,9 @@ 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,
|
||||
"${pInfo}.fileprovider",
|
||||
"com.example.hpostesting.dev.fileprovider",
|
||||
file
|
||||
)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
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
|
||||
@@ -15,13 +14,12 @@ 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.deviceinfo.DeviceActivity
|
||||
import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity
|
||||
import com.example.hpostesting.presentation.deviceinfo.DeviceActivity
|
||||
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
|
||||
@@ -57,7 +55,7 @@ class GalleryFragment : Fragment() {
|
||||
) {
|
||||
binding.btnDeviceProvision.visibility = View.VISIBLE
|
||||
} else {
|
||||
binding.btnDeviceProvision.visibility = View.GONE
|
||||
binding.btnDeviceProvision.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
binding.btnDeviceProvision.setOnClickListener {
|
||||
@@ -84,19 +82,6 @@ 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}"
|
||||
|
||||
|
||||
@@ -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,19 +47,12 @@ 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.net.URL
|
||||
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() {
|
||||
@@ -70,6 +67,10 @@ 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(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
|
||||
@@ -96,7 +97,7 @@ class HomeFragment : Fragment() {
|
||||
binding.labelQuickCapture.visibility = View.VISIBLE
|
||||
binding.btnQuickCapture.visibility = View.VISIBLE
|
||||
}
|
||||
|
||||
getDeviceId()
|
||||
checkUnprocessedCSVData()
|
||||
viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
|
||||
deleteIncompleteRegistrations(userData)
|
||||
@@ -117,9 +118,15 @@ class HomeFragment : Fragment() {
|
||||
binding.rvOrderOffline.adapter = adapter
|
||||
}
|
||||
}
|
||||
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) { deviceData ->
|
||||
val devicelist = mutableListOf<DeviceData>()
|
||||
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()
|
||||
@@ -193,12 +200,17 @@ 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()) {
|
||||
hemoCubeViewModel.login(createLoginRequestData(userID, password))
|
||||
@@ -210,21 +222,30 @@ class HomeFragment : Fragment() {
|
||||
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 -> {
|
||||
@@ -279,41 +300,6 @@ 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 -> {
|
||||
@@ -338,11 +324,8 @@ 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))
|
||||
@@ -392,60 +375,6 @@ 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()
|
||||
@@ -471,6 +400,46 @@ 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
|
||||
// Log for debugging
|
||||
Log.d("fetchDeviceCredentials", "Username: $username, Password: $password")
|
||||
// Save credentials in SharedPreferences
|
||||
with(sharedPreference.edit()) {
|
||||
putString("username", username)
|
||||
putString("password", password)
|
||||
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")
|
||||
@@ -853,4 +822,44 @@ class HomeFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 ?: ""
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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<DeviceViewModel>()
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ class DeviceViewModel @Inject constructor(
|
||||
val deviceData = MutableLiveData<DeviceData?>()
|
||||
// val networkStatusLiveData: LiveData<Boolean>
|
||||
// get() = _networkStatusLiveData
|
||||
val fireBaseUpload = MutableLiveData<String>()
|
||||
val fireBaseUpload = MutableLiveData<String>()
|
||||
val fireBaseBulkUpload = MutableLiveData<String>()
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -11,22 +11,28 @@ 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
|
||||
import com.google.firebase.ktx.Firebase
|
||||
import `in`.sminnovations.hpostesting.R
|
||||
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<DeviceData?>()
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
|
||||
): View {
|
||||
@@ -34,13 +40,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()
|
||||
@@ -56,7 +60,11 @@ class DeviceProvisionFragment : Fragment() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun observeViewModel() {
|
||||
viewModel.deviceData.observe(viewLifecycleOwner) {
|
||||
currentDeviceData = it
|
||||
}
|
||||
|
||||
viewModel.deviceProvisionResponse.observe(viewLifecycleOwner) { response ->
|
||||
when (response) {
|
||||
@@ -75,25 +83,37 @@ 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()
|
||||
)
|
||||
)
|
||||
// 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
|
||||
@@ -118,8 +138,16 @@ 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,
|
||||
@@ -134,7 +162,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)
|
||||
@@ -150,20 +179,14 @@ class DeviceProvisionFragment : Fragment() {
|
||||
Firebase.crashlytics.recordException(e)
|
||||
}
|
||||
}
|
||||
|
||||
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 hardwareId = extractV2HardwareId(resultData)
|
||||
val pattern = Regex("HCV-\\d{3}-\\d{4}")
|
||||
val matchResult = pattern.find(resultData)
|
||||
val hardwareId = matchResult?.value
|
||||
|
||||
if (!hardwareId.isNullOrBlank()) {
|
||||
if (hardwareId.toString().length == 12) {
|
||||
with(sharedPreferences.edit()) {
|
||||
putString(Constants.DEVICE_ID, hardwareId)
|
||||
apply()
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
package com.example.hpostesting.presentation.deviceprovision
|
||||
|
||||
import android.content.Context
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.MutableLiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.example.hpostesting.data.NetworkStatusLiveData
|
||||
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.diagnostics.DiagnosticsData
|
||||
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 +19,57 @@ import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
class DeviceProvisionViewModel @Inject constructor(
|
||||
private val databaseRepository: Repository
|
||||
private val databaseRepository: Repository,
|
||||
private val repository: Repository,
|
||||
context: Context,
|
||||
) : ViewModel() {
|
||||
|
||||
private val _networkStatusLiveData = NetworkStatusLiveData(context)
|
||||
var isServiceConnected = false
|
||||
|
||||
val networkStatusLiveData: LiveData<Boolean> get() = _networkStatusLiveData
|
||||
val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>()
|
||||
|
||||
val fireBaseUpload = MutableLiveData<String>()
|
||||
val fireBaseBulkUpload = MutableLiveData<String>()
|
||||
val deviceData = MutableLiveData<DeviceData?>()
|
||||
fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
|
||||
deviceProvisionResponse.postValue(Result.Loading())
|
||||
databaseRepository.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")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,9 +148,6 @@ 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()
|
||||
|
||||
@@ -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 = deviceRatioClass
|
||||
hemoCubeViewModel.messages.postValue("${this.classificationResult} \n Device Ratio: ${"%.3f".format(this.deviceRatio)}")
|
||||
this.classificationResult = findResultWithAdditionalMethods(deviceRatio, deviceRatioClass, slopeRatio)
|
||||
hemoCubeViewModel.messages.postValue("${this.classificationResult} ")
|
||||
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 > 45.0)
|
||||
if (deviceRatioClass == "Normal" && slopeRatio > 60.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.016..0.22) {
|
||||
if (ratio in 0.001..0.23) {
|
||||
// setSubtitleTextColor(R.color.green_2)
|
||||
return "Normal"
|
||||
}
|
||||
if (ratio in 0.22..0.24)
|
||||
return "Negative Borderline"
|
||||
if (ratio in 0.24..0.32)
|
||||
if (ratio in 0.23..0.24)
|
||||
return "Negative Borderline, Repeat Test"
|
||||
if (ratio in 0.24..0.29)
|
||||
return "Sickle Cell Trait"
|
||||
if (ratio in 0.32..0.37)
|
||||
if (ratio in 0.29..0.32)
|
||||
return "Positive for Sickle Cell. HPLC for Confirmation"
|
||||
if (ratio in 0.37..0.56)
|
||||
if (ratio in 0.32..Double.POSITIVE_INFINITY)
|
||||
return "Sickle Cell Disease"
|
||||
} else {
|
||||
return "Invalid"
|
||||
|
||||
@@ -79,7 +79,6 @@ class HemoCubeViewModel @Inject constructor(
|
||||
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
|
||||
|
||||
val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
|
||||
val downloadcertificate = MutableLiveData<Result<ResponseBody>>()
|
||||
|
||||
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
|
||||
|
||||
@@ -142,9 +141,6 @@ class HemoCubeViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
|
||||
checkUpdate.postValue(Result.Loading())
|
||||
repository.checkUpdate(checkUpdateRequest).let {
|
||||
@@ -159,17 +155,6 @@ class HemoCubeViewModel @Inject constructor(
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun downloadClientCertificate() = viewModelScope.launch {
|
||||
downloadcertificate.postValue(Result.Loading())
|
||||
repository.downloadClientCertificate().let {
|
||||
downloadcertificate.postValue(it)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
fun startPeriodicCheckUpdate() {
|
||||
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
|
||||
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES
|
||||
|
||||
@@ -11,14 +11,12 @@ import android.content.ServiceConnection
|
||||
import android.hardware.usb.UsbDevice
|
||||
import android.hardware.usb.UsbDeviceConnection
|
||||
import android.hardware.usb.UsbManager
|
||||
import android.os.Build
|
||||
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.annotation.RequiresApi
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.get
|
||||
@@ -45,7 +43,6 @@ open class HemocubeActivity : AppCompatActivity() {
|
||||
private val TAG = "HemoCube"
|
||||
|
||||
private val broadcastReceiver = object : BroadcastReceiver() {
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
|
||||
synchronized(this) {
|
||||
@@ -84,7 +81,6 @@ open class HemocubeActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
binding = ActivityHemocubeBinding.inflate(layoutInflater)
|
||||
@@ -109,7 +105,6 @@ open class HemocubeActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
open fun connectUsb(permissionGranted: Boolean) {
|
||||
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
|
||||
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
|
||||
@@ -130,40 +125,32 @@ open class HemocubeActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
@SuppressLint("UnspecifiedImmutableFlag")
|
||||
@SuppressLint("MutableImplicitPendingIntent")
|
||||
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
|
||||
val mPendingIntent: PendingIntent
|
||||
val pendingIntentFlags = when {
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
}
|
||||
else -> {
|
||||
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
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
mPendingIntent = PendingIntent.getBroadcast(
|
||||
this,
|
||||
0,
|
||||
Intent(Constants.HEMOCUBE_USB_PERMISSION),
|
||||
pendingIntentFlags
|
||||
)
|
||||
|
||||
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
|
||||
registerReceiver(broadcastReceiver, filter, RECEIVER_EXPORTED)
|
||||
|
||||
// Request permission
|
||||
registerReceiver(broadcastReceiver, filter)
|
||||
manager.requestPermission(device, mPendingIntent)
|
||||
}
|
||||
|
||||
|
||||
fun setupService() {
|
||||
val intent = Intent(this, UsbService::class.java)
|
||||
bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
||||
}
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.O)
|
||||
open fun reconnectDevice() {
|
||||
mService.disconnect()
|
||||
unbindService(connection)
|
||||
|
||||
@@ -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" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_deviceProvision"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
android:visibility="visible"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:clickable="false"
|
||||
@@ -92,7 +92,7 @@
|
||||
app:cornerRadius="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_deviceInfo" />
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_auto_dac" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_deviceInfo"
|
||||
@@ -108,33 +108,4 @@
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_calibration" />
|
||||
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_firefox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:clickable="false"
|
||||
android:text="@string/Firefox"
|
||||
android:textColor="@color/white"
|
||||
app:cornerRadius="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_deviceProvision" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btn_files"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="16dp"
|
||||
android:layout_marginTop="24dp"
|
||||
android:clickable="false"
|
||||
android:text="@string/Files"
|
||||
android:textColor="@color/white"
|
||||
app:cornerRadius="16dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/btn_firefox" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -115,8 +115,6 @@
|
||||
<string name="assurance_controls">Quality Assurance</string>
|
||||
<string name="calibration">Calibration</string>
|
||||
<string name="deviceProvision">Device Provision</string>
|
||||
<string name="Firefox">Firefox</string>
|
||||
<string name="Files">Files</string>
|
||||
<string name="deviceinfo">Device Information</string>
|
||||
<string name="place_buffer">Start</string>
|
||||
<string name="Start_Sample">Start Sample</string>
|
||||
|
||||
@@ -327,7 +327,7 @@ class HemoCubeFragmentTest {
|
||||
fun testDeviceRatioClassificationNegativeBorderline() {
|
||||
val ratio = 0.235
|
||||
val result = hemoCubeFragment.deviceRatioClassification(ratio)
|
||||
assertEquals("Negative Borderline", result)
|
||||
assertEquals("Negative Borderline, Repeat Test", result)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -339,7 +339,7 @@ class HemoCubeFragmentTest {
|
||||
|
||||
@Test
|
||||
fun testDeviceRatioClassificationPositiveForSickleCell() {
|
||||
val ratio = 0.37
|
||||
val ratio = 0.31
|
||||
val result = hemoCubeFragment.deviceRatioClassification(ratio)
|
||||
assertEquals("Positive for Sickle Cell. HPLC for Confirmation", result)
|
||||
}
|
||||
@@ -366,37 +366,9 @@ class HemoCubeFragmentTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
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() {
|
||||
fun findResultWithAdditionalMethods_ValidInput_ReturnsDeviceRatioClassToString() {
|
||||
// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid")
|
||||
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)
|
||||
val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)
|
||||
assertEquals("Abnormal", result)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user