Compare commits

...

69 Commits

Author SHA1 Message Date
sanjay
e5e03e3fab added some log.d calls for testing 2024-02-27 12:29:42 +05:30
Mariya
a97fd86c86 Duplication related changes offline data testing, removed unwanted code 2024-02-24 18:27:01 +05:30
sanjay
41a66766d1 Experimenting with Uploads 2024-02-23 17:52:09 +05:30
sanjay
3f9d1d110f Added code for encrypting username and password during device registration 2024-02-23 12:47:24 +05:30
Mariya
af3f152e26 duplicate data coming issue got resolved for molbio and firebase 2024-02-20 23:07:06 +05:30
Mariya
339a2d0d70 Added changes for solution and concentration 2024-02-19 11:49:22 +05:30
Mariya
8fd91e0961 updated date format for molbio result 2024-02-16 22:18:50 +05:30
Pritimay Sarkar
515d154e50 remove a state check 2024-02-16 20:48:48 +05:30
Pritimay Sarkar
09d4bb56fc call print once 2024-02-16 18:51:57 +05:30
Pritimay Sarkar
d502e88da4 fix state atutomation 2024-02-16 14:50:39 +05:30
Pritimay Sarkar
6e46c31bfc typo 2024-02-16 09:49:04 +05:30
Pritimay Sarkar
7986f22da1 fix pipeline 2024-02-16 09:48:20 +05:30
Pritimay Sarkar
b3726d8a9b Merge remote-tracking branch 'origin/Diagnostics' into dev 2024-02-16 09:33:53 +05:30
Pritimay Sarkar
cf899c187e Merge remote-tracking branch 'origin/dev-Issue-Fix-Branch' into dev 2024-02-16 09:30:52 +05:30
Pritimay Sarkar
e2bf442651 Merge remote-tracking branch 'origin/dev-assurance-empty-check' into dev 2024-02-16 09:28:48 +05:30
Pritimay Sarkar
3e8542e309 fix 2024-02-16 09:23:01 +05:30
Pritimay Sarkar
8c3b63390c show messages 2024-02-16 08:53:33 +05:30
Pritimay Sarkar
a984e6bf29 add device ids 2024-02-16 08:28:29 +05:30
Pritimay Sarkar
e227289cd9 fix eprom set command 2024-02-16 08:14:24 +05:30
Pritimay Sarkar
7aae2295a3 fix button 2024-02-15 23:34:32 +05:30
Pritimay Sarkar
582f08f8da add command to read current dac values 2024-02-15 23:27:14 +05:30
Pritimay Sarkar
efe60ab172 add command to set DAC values to eprom 2024-02-15 23:19:56 +05:30
Pritimay Sarkar
b53e20682d pipeline related change 2024-02-15 23:00:49 +05:30
Pritimay Sarkar
dc2a0849b9 add EPROM retrival 2024-02-15 22:56:07 +05:30
Mariya
4ba3b98d2d updated date format, to check is getting null values 2024-02-15 20:55:34 +05:30
Mariya
c379d68679 errors fixed in Repository file 2024-02-15 20:49:29 +05:30
Mariya
0858fc5da0 errors fixed in Repository file 2024-02-14 18:06:25 +05:30
Mariya Varghese
db317bf126 Merge branch 'dev' into 'Diagnostics'
# Conflicts:
#   app/src/main/java/com/example/hpostesting/data/repository/DatabaseRepository.kt
#   app/src/main/java/com/example/hpostesting/data/repository/Repository.kt
2024-02-14 11:40:46 +00:00
Mariya
fe3f17b71d Message format is changed 2024-02-14 17:01:30 +05:30
Mariya
b5f605157e Device Diagnostics Api structure done successfully Added, 2024-02-14 17:00:18 +05:30
Mariya
ab1208d9ee Device Diagnostics Api structure done successfully 2024-02-14 15:53:38 +05:30
Pritimay Sarkar
b0bbae7cfa clean code 2024-02-14 14:13:00 +05:30
Pritimay Sarkar
a4ae03a2a7 refactoring 2024-02-14 12:47:39 +05:30
Mariya
8e5294f564 Disable Download Csv button 2024-02-13 18:54:04 +05:30
Pritimay Sarkar
f5068c70c2 build file change for pipeline 2024-02-13 17:59:26 +05:30
Pritimay Sarkar
8019ed2c30 add refresh and qr code scan - jig 2024-02-13 17:57:38 +05:30
Pritimay Sarkar
6afee91d27 add test jig screen 2024-02-13 14:30:21 +05:30
Mariya
547cf714a4 Toast message changed in KitScanActivity if the Scanner is not available 2024-02-13 13:02:21 +05:30
Mariya
fd5fb6db22 text view removed of "all registers are tested" for offline, its its only display if the internet is available 2024-02-13 12:57:41 +05:30
Mariya
9b2b64f248 Added Scroll view for the panel screen 2024-02-13 12:47:57 +05:30
Pritimay Sarkar
830eb525fd add kit capacity in constants 2024-02-13 12:44:02 +05:30
Pritimay Sarkar
06241008f1 rounded corners logo 2024-02-13 09:00:29 +05:30
Pritimay Sarkar
0721be0114 save nats token in backend 2024-02-13 08:59:28 +05:30
Pritimay Sarkar
23cf38445f handle method and dynamic config for NATS 2024-02-13 08:59:03 +05:30
Pritimay Sarkar
6577842ba9 add dynamic topic based on deviceId 2024-02-13 00:07:05 +05:30
Pritimay Sarkar
c52d9835cd refactor and fix pipeline 2024-02-12 22:16:17 +05:30
Pritimay Sarkar
9f04125f68 fix conflict 2024-02-12 18:07:19 +05:30
Pritimay Sarkar
2b2c16df22 Merge remote-tracking branch 'origin/device-provision-response-store' into dev 2024-02-12 18:04:58 +05:30
Pritimay Sarkar
727040fabf Merge remote-tracking branch 'origin/dev-bulk-upload' into dev 2024-02-12 18:01:38 +05:30
Mariya
80eb658b07 changes when we tested 2024-02-12 17:56:37 +05:30
Mariya
9314b155cd Device provision fetching code is added 2024-02-12 13:56:05 +05:30
Mariya
7f47e1dff8 Device provision username and password stored in firebase store separately 2024-02-12 12:01:10 +05:30
Pritimay Sarkar
be21430d0a Merge remote-tracking branch 'origin/nats_certificate_download' into dev 2024-02-11 14:08:00 +05:30
Mariya
d5b6910408 Device provision response storing 2024-02-10 17:37:07 +05:30
Pritimay Sarkar
3609d728c1 release 2.1.110 2024-02-10 12:18:52 +05:30
Pritimay Sarkar
7302ad669f release 2.1.108 2024-02-10 11:10:06 +05:30
Pritimay Sarkar
ef98b09eaf release 2.1.107 2024-02-10 10:46:54 +05:30
Mariya
89dc7f7234 Added code related to device provision fetching fromfirestore 2024-02-09 16:39:02 +05:30
Pritimay Sarkar
f631a273d7 TLS impleamentation on NATS server 2024-02-09 13:50:33 +05:30
Pritimay Sarkar
de74da3135 add package name dynamically in provider 2024-02-09 13:49:16 +05:30
Mariya
c5cb8a0983 Added code for fetching response of device provision api from firebase 2024-02-08 14:24:34 +05:30
Mariya
6ddb491bc8 Added code to send response of device provision api into firebase 2024-02-08 12:18:31 +05:30
Mariya
c5c0467e42 code added to store device provision response 2024-02-08 11:48:35 +05:30
Mariya
466d0e2afc code added related to nats 2024-02-07 16:33:57 +05:30
Mariya
45fd4861f4 nats code 2024-02-07 12:49:31 +05:30
Mariya
1a3bb67dce nats 2024-02-06 16:23:33 +05:30
Mariya
8bc9b1449f Added code for Device Diagnostics 2024-02-06 15:17:46 +05:30
Mariya
7e5228bb35 Added code for Device Diagnostics 2024-02-06 14:53:35 +05:30
Mariya
3dd247b15d Nats Certificate Download API is completed 2024-02-06 13:25:06 +05:30
112 changed files with 2456 additions and 602 deletions

View File

@@ -14,13 +14,13 @@ android {
compileSdk 34 compileSdk 34
namespace 'in.sminnovations.hpostesting' 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 { defaultConfig {
applicationId "in.sminnovations.hpostesting.dev" applicationId "in.sminnovations.hpostesting.dev"
minSdk 21 minSdk 21
targetSdk 34 targetSdk 34
versionCode 111 versionCode 114
versionName "2.1.111" versionName "2.1.114"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -157,7 +157,7 @@ dependencies {
implementation("com.squareup.okhttp3:okhttp:4.9.3") implementation("com.squareup.okhttp3:okhttp:4.9.3")
implementation "androidx.preference:preference-ktx:1.2.1" 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") implementation("androidx.work:work-runtime-ktx:2.9.0")
@@ -165,4 +165,6 @@ dependencies {
implementation 'com.google.android.play:core:1.10.3' implementation 'com.google.android.play:core:1.10.3'
implementation fileTree(dir: 'libs', include: ['*.aar']) implementation fileTree(dir: 'libs', include: ['*.aar'])
implementation 'io.nats:jnats:2.11.4'
} }

Binary file not shown.

View File

@@ -4,15 +4,15 @@
"type": "APK", "type": "APK",
"kind": "Directory" "kind": "Directory"
}, },
"applicationId": "com.example.hpos", "applicationId": "in.sminnovations.hpostesting.quality",
"variantName": "release", "variantName": "release",
"elements": [ "elements": [
{ {
"type": "SINGLE", "type": "SINGLE",
"filters": [], "filters": [],
"attributes": [], "attributes": [],
"versionCode": 1, "versionCode": 101,
"versionName": "1.0", "versionName": "2.1.101",
"outputFile": "app-release.apk" "outputFile": "app-release.apk"
} }
], ],

View File

@@ -48,6 +48,10 @@
android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity" android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" /> android:theme="@style/Theme.HPOS.NoActionBar" />
<activity
android:name="com.example.hpostesting.presentation.jig.JigActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" />
<activity <activity
android:name="com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity" android:name="com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity"
android:exported="false" android:exported="false"
@@ -112,15 +116,18 @@
android:name="com.example.hpostesting.presentation.testRight.UsbService" android:name="com.example.hpostesting.presentation.testRight.UsbService"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<activity <activity
android:name="com.example.hpostesting.presentation.SplashActivity" android:name="com.example.hpostesting.presentation.SplashActivity"
android:exported="true" android:exported="true"
android:noHistory="true" android:noHistory="true"
android:theme="@style/AppTheme.NoActionBar"> android:theme="@style/AppTheme.NoActionBar">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN"/> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER"/> <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" />-->
</intent-filter> </intent-filter>
</activity> </activity>
<activity <activity
@@ -160,7 +167,7 @@
<provider <provider
android:name="androidx.core.content.FileProvider" android:name="androidx.core.content.FileProvider"
android:authorities="com.example.hpostesting.qa.fileprovider" android:authorities="${applicationId}.fileprovider"
android:exported="false" android:exported="false"
android:grantUriPermissions="true"> android:grantUriPermissions="true">
<meta-data <meta-data

View File

@@ -1,20 +1,15 @@
package com.example.hpostesting package com.example.hpostesting
import android.app.Application import android.app.Application
import android.content.Context
import androidx.room.Room
import com.example.hpostesting.data.dao.MyDatabase
import com.google.android.datatransport.runtime.dagger.Provides
import com.google.firebase.firestore.FirebaseFirestore import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.FirebaseFirestoreSettings import com.google.firebase.firestore.FirebaseFirestoreSettings
import dagger.hilt.android.HiltAndroidApp import dagger.hilt.android.HiltAndroidApp
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
import javax.inject.Singleton
@HiltAndroidApp @HiltAndroidApp
class HPOSTestingApplication: Application() { class HPOSTestingApplication : Application() {
val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO) val applicationScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
override fun onCreate() { override fun onCreate() {

View File

@@ -1,5 +1,7 @@
package com.example.hpostesting.data.api package com.example.hpostesting.data.api
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRequest
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsResponse
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.login.LoginRequest import com.example.hpostesting.data.model.login.LoginRequest
@@ -11,11 +13,12 @@ interface MolbioAuthApi {
@POST("deviceManagement/device/provision") @POST("deviceManagement/device/provision")
suspend fun deviceProvision( suspend fun deviceProvision(
@Body deviceProvisionRequest: DeviceProvisionRequest @Body deviceProvisionRequest: DeviceProvisionRequest,
): DeviceProvisionResponse ): DeviceProvisionResponse
@POST("deviceService/device/login") @POST("deviceService/device/login")
suspend fun login( suspend fun login(
@Body loginRequest: LoginRequest @Body loginRequest: LoginRequest,
): LoginResponse ): LoginResponse
} }

View File

@@ -1,5 +1,7 @@
package com.example.hpostesting.data.api package com.example.hpostesting.data.api
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRequest
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsResponse
import com.example.hpostesting.data.model.log.UploadLogsResponse import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultResponse
@@ -9,6 +11,7 @@ import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import okhttp3.MultipartBody import okhttp3.MultipartBody
import okhttp3.ResponseBody import okhttp3.ResponseBody
import retrofit2.http.Body import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Multipart import retrofit2.http.Multipart
import retrofit2.http.POST import retrofit2.http.POST
import retrofit2.http.PUT import retrofit2.http.PUT
@@ -18,22 +21,32 @@ interface MolbioResultApi {
@PUT("deviceService/results/HPOS") @PUT("deviceService/results/HPOS")
suspend fun uploadResults( suspend fun uploadResults(
@Body molbioV2ResultRequest: MolbioV2ResultRequest @Body molbioV2ResultRequest: MolbioV2ResultRequest,
): MolbioV2ResultResponse ): MolbioV2ResultResponse
@POST("deviceService/device/checkUpdate") @POST("deviceService/device/checkUpdate")
suspend fun checkUpdate( suspend fun checkUpdate(
@Body checkUpdateRequest: CheckUpdateRequest @Body checkUpdateRequest: CheckUpdateRequest,
): CheckUpdateResponse ): CheckUpdateResponse
@POST("deviceService/device/getUpdate") @POST("deviceService/device/getUpdate")
suspend fun deviceUpdate( suspend fun deviceUpdate(
@Body deviceUpdateRequest: DeviceUpdateRequest @Body deviceUpdateRequest: DeviceUpdateRequest,
): ResponseBody
@GET("deviceService/device/getClientCertificate")
suspend fun downloadClientCertificate(
): ResponseBody ): ResponseBody
@Multipart @Multipart
@POST("deviceService/device/uploadLogs") @POST("deviceService/device/uploadLogs")
suspend fun uploadLogs( suspend fun uploadLogs(
@Part logFile: MultipartBody.Part @Part logFile: MultipartBody.Part,
): UploadLogsResponse ): UploadLogsResponse
@PUT("deviceService/device/uploadDeviceDiagnostics")
suspend fun deviceDiagnostics(
@Body deviceDiagnosticsRequest: DeviceDiagnosticsRequest
): DeviceDiagnosticsResponse
} }

View File

@@ -1,6 +1,13 @@
package com.example.hpostesting.data.api package com.example.hpostesting.data.api
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.presentation.UsbServiceListener
interface PropertyProvider { interface PropertyProvider {
fun getProperty(key: String): String fun getProperty(key: String): String
} }
interface DeviceCommunicationHandler {
fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener)
}

View File

@@ -8,7 +8,7 @@ object Constants {
const val ABHA_APP_PACKAGE = "in.ndhm.phr" const val ABHA_APP_PACKAGE = "in.ndhm.phr"
const val MOLBIO_INTEGRATION = false const val MOLBIO_INTEGRATION = true
const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in" const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in"
const val deviceProvisionPassword = "f2ab0e7f9d69" const val deviceProvisionPassword = "f2ab0e7f9d69"
const val DEVICE_ID_API = "deviceIDAPI" const val DEVICE_ID_API = "deviceIDAPI"
@@ -61,6 +61,9 @@ object Constants {
const val BLANK_EVERY_TEST = false const val BLANK_EVERY_TEST = false
// jig
const val NAVIGATE_TO_TEST_JIG_DIRECTLY = false
val STATICID = listOf( val STATICID = listOf(
"FACTORY", "FACTORY",
"ADMIN", "ADMIN",
@@ -167,12 +170,64 @@ object Constants {
"HPP1-0124-0048", "HPP1-0124-0048",
"HPP1-0124-0049", "HPP1-0124-0049",
"HPP1-0124-0050", "HPP1-0124-0050",
"HCV-001-0001",
"HCV-001-0002",
"HCV-001-0003",
"HCV-001-0004",
"HCV-001-0005",
"HCV-001-0006",
"HCV-001-0007",
"HCV-001-0008",
"HCV-001-0009",
"HCV-001-0010",
"HCV-001-0011",
"HCV-001-0012",
"HCV-001-0013",
"HCV-001-0014",
"HCV-001-0015",
"HCV-001-0016",
"HCV-001-0017",
"HCV-001-0018",
"HCV-001-0019",
"HCV-001-0020",
"HCV-001-0021",
"HCV-001-0022",
"HCV-001-0023",
"HCV-001-0024",
"HCV-001-0025",
"HCV-001-0026",
"HCV-001-0027",
"HCV-001-0028",
"HCV-001-0029",
"HCV-001-0030",
"HCV-001-0031",
"HCV-001-0032",
"HCV-001-0033",
"HCV-001-0034",
"HCV-001-0003",
"HCV-001-0035",
"HCV-001-0036",
"HCV-001-0037",
"HCV-001-0038",
"HCV-001-0039",
"HCV-001-0040",
"HCV-001-0041",
"HCV-001-0042",
"HCV-001-0043",
"HCV-001-0044",
"HCV-001-0045",
"HCV-001-0046",
"HCV-001-0047",
"HCV-001-0048",
"HCV-001-0049",
"HCV-001-0050",
) )
const val password = "SMI@12345" const val password = "SMI@12345"
const val KIT_NUMBER = "KitNumber" const val KIT_NUMBER = "KitNumber"
const val KIT_COUNT = "KitCount" const val KIT_COUNT = "KitCount"
const val KIT_CAPACITY = Int.MAX_VALUE // Enforceable
const val BUFFER_VALUE_1 = "BufferValue1" const val BUFFER_VALUE_1 = "BufferValue1"
const val BUFFER_VALUE_2 = "BufferValue2" const val BUFFER_VALUE_2 = "BufferValue2"
const val BUFFER_VALUE_3 = "BufferValue3" const val BUFFER_VALUE_3 = "BufferValue3"
@@ -182,19 +237,6 @@ object Constants {
const val BUFFER_LED_LOWER_BOUND = 21000 const val BUFFER_LED_LOWER_BOUND = 21000
const val BUFFER_LED_UPPER_BOUND = 23500 const val BUFFER_LED_UPPER_BOUND = 23500
const val TEST_STATUS_CODE_TEST_STARTED = 1.0
const val TEST_STATUS_CODE_CONFIG_STARTED = 2.0
const val TEST_STATUS_CODE_CONFIG_COMPLETED = 3.0
const val TEST_STATUS_CODE_BUFFER_STARTED = 4.0
const val TEST_STATUS_CODE_BUFFER_COMPLETED = 5.0
const val TEST_STATUS_CODE_BUFFER_PRINT_STARTED = 6.0
const val TEST_STATUS_CODE_BUFFER_PRINT_COMPLETED = 7.0
const val TEST_STATUS_CODE_SAMPLE_STARTED = 8.0
const val TEST_STATUS_CODE_SAMPLE_COMPLETED = 9.0
const val TEST_STATUS_CODE_SAMPLE_PRINT_STARTED = 10.0
const val TEST_STATUS_CODE_SAMPLE_PRINT_COMPLETED = 11.0
const val TEST_STATUS_CODE_TEST_COMPLETED = 12.0
val DEVICE_CONFIGURATION: Map<String, List<List<Double>>> = mapOf<String, List<List<Double>>>( val DEVICE_CONFIGURATION: Map<String, List<List<Double>>> = mapOf<String, List<List<Double>>>(
"HCV-000-3001" to listOf( "HCV-000-3001" to listOf(
listOf(1.0, 0.0), // LED1, 435nm listOf(1.0, 0.0), // LED1, 435nm
@@ -1659,11 +1701,10 @@ object Constants {
) )
) )
val COEFFICIENTS: Map<String, List<List<Double>>> = mapOf( val COEFFICIENTS: Map<String, List<List<Double>>> = mapOf(
"HC-V1-005" to listOf( "HC-V1-005" to listOf(
listOf(1.5,0.0), listOf(1.5, 0.0),
listOf(0.0,0.0) listOf(0.0, 0.0)
) )
) )

View File

@@ -3,12 +3,14 @@ package com.example.hpostesting.data.constant
enum class HemoCubeCommands(val command: String) { enum class HemoCubeCommands(val command: String) {
START_BUFFER_COMMAND("B\r"), START_BUFFER_COMMAND("B\r"),
AUTO_DAC_COMMAND("C\r"), AUTO_DAC_COMMAND("C\r"),
SET_AUTO_DAC_TO_EPROM_COMMAND("G\r"),
DIAGNOSTICS_COMMAND("D\r"), DIAGNOSTICS_COMMAND("D\r"),
FIRMWARE_INFO_COMMAND("F\r"), FIRMWARE_INFO_COMMAND("F\r"),
START_SAMPLE("S\r"), START_SAMPLE("S\r"),
PRINT_COMMAND("P\r"), PRINT_COMMAND("P\r"),
READ_DAC_COMMAND("R\r"), READ_DAC_COMMAND("R\r"),
DEVICE_CONFIGURATION_COMMAND("I\r"), DEVICE_CONFIGURATION_COMMAND("I\r"),
LOAD_DAC_VALUES("E\r"),
FIRST_GAIN_COMMAND("T\r"), FIRST_GAIN_COMMAND("T\r"),
SECOND_GAIN_COMMAND("U\r"), SECOND_GAIN_COMMAND("U\r"),
THIRD_GAIN_COMMAND("V\r"), THIRD_GAIN_COMMAND("V\r"),

View File

@@ -19,12 +19,14 @@ object LanguageManager {
} }
fun persistLanguagePreference(context: Context, languageCode: String) { fun persistLanguagePreference(context: Context, languageCode: String) {
val prefs: SharedPreferences = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE) val prefs: SharedPreferences =
context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
prefs.edit().putString(LANGUAGE_PREF_KEY, languageCode).apply() prefs.edit().putString(LANGUAGE_PREF_KEY, languageCode).apply()
} }
fun getSavedLanguage(context: Context): String { fun getSavedLanguage(context: Context): String {
val prefs: SharedPreferences = context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE) val prefs: SharedPreferences =
context.getSharedPreferences("AppPrefs", Context.MODE_PRIVATE)
return prefs.getString(LANGUAGE_PREF_KEY, "en") ?: "en" return prefs.getString(LANGUAGE_PREF_KEY, "en") ?: "en"
} }
} }

View File

@@ -8,7 +8,9 @@ enum class TestStatus(val code: Double) {
FIRST_EMPTY_AIR_READING_COMPLETED(4.2), FIRST_EMPTY_AIR_READING_COMPLETED(4.2),
FIRST_EMPTY_AIR_READING_PRINT_STARTED(4.3), FIRST_EMPTY_AIR_READING_PRINT_STARTED(4.3),
FIRST_EMPTY_AIR_READING_PRINT_COMPLETED(4.4), FIRST_EMPTY_AIR_READING_PRINT_COMPLETED(4.4),
BUFFER_STARTED(4.0), EPROM_ADC_RETRIEVAL_STARTED(4.5),
EPROM_ADC_RETRIEVAL_COMPLETED(4.6),
BUFFER_STARTED(4.7),
BUFFER_COMPLETED(5.0), BUFFER_COMPLETED(5.0),
BUFFER_PRINT_STARTED(6.0), BUFFER_PRINT_STARTED(6.0),
BUFFER_PRINT_COMPLETED(7.0), BUFFER_PRINT_COMPLETED(7.0),

View File

@@ -16,6 +16,7 @@ class Converters {
null null
} }
} }
@TypeConverter @TypeConverter
fun toString(location: UserData.Location?): String? { fun toString(location: UserData.Location?): String? {
return if (location != null) { return if (location != null) {

View File

@@ -7,7 +7,7 @@ import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
@Dao @Dao
interface DeviceDao { interface DeviceDao {
@Query("SELECT * from device_table") @Query("SELECT * from device_table")

View File

@@ -8,7 +8,11 @@ import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData 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) @TypeConverters(Converters::class)
abstract class MyDatabase : RoomDatabase() { abstract class MyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao abstract fun userDao(): UserDao

View File

@@ -1,11 +1,6 @@
package com.example.hpostesting.data.datasource package com.example.hpostesting.data.datasource
import android.os.Environment
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.opencsv.CSVWriter
import java.io.File
import java.io.FileWriter
import java.io.IOException
interface LocalFileDataSource { interface LocalFileDataSource {
@@ -14,6 +9,6 @@ interface LocalFileDataSource {
fun saveTextToDisk(filepath: String, contents: String) fun saveTextToDisk(filepath: String, contents: String)
fun exportDataToCSV( fun exportDataToCSV(
fileName: String, dataList: List<HemoCubeTestData> fileName: String, dataList: List<HemoCubeTestData>,
): Boolean ): Boolean
} }

View File

@@ -8,7 +8,7 @@ import java.io.FileWriter
import java.io.IOException import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
class LocalFileDataSourceImpl @Inject constructor(): LocalFileDataSource { class LocalFileDataSourceImpl @Inject constructor() : LocalFileDataSource {
override fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) { override fun saveCsvToDisk(filepath: String, contents: ArrayList<Array<String>>) {
val writer = CSVWriter(FileWriter(filepath)) val writer = CSVWriter(FileWriter(filepath))
@@ -25,10 +25,13 @@ class LocalFileDataSourceImpl @Inject constructor(): LocalFileDataSource {
} }
override fun exportDataToCSV( override fun exportDataToCSV(
fileName: String, dataList: List<HemoCubeTestData> fileName: String, dataList: List<HemoCubeTestData>,
): Boolean { ): Boolean {
try { try {
val formattedFileName = fileName.replace(Regex("[^a-zA-Z0-9.-]"), "_") // Replace special characters with underscores val formattedFileName = fileName.replace(
Regex("[^a-zA-Z0-9.-]"),
"_"
) // Replace special characters with underscores
val filePath = File(getExternalStorageDirectory(), formattedFileName) val filePath = File(getExternalStorageDirectory(), formattedFileName)
val writer = FileWriter(filePath) val writer = FileWriter(filePath)
val csvWriter = CSVWriter(writer) val csvWriter = CSVWriter(writer)

View File

@@ -0,0 +1,36 @@
package com.example.hpostesting.data.encryption
import android.security.keystore.KeyGenParameterSpec
import android.security.keystore.KeyProperties
import android.util.Base64
import javax.crypto.Cipher
import javax.crypto.KeyGenerator
import javax.crypto.spec.SecretKeySpec
object AESCrypt {
private const val ALGORITHM = "AES"
private const val KEY = "your_secret_key"
@Throws(Exception::class)
fun encrypt(value: String): String {
val keySpec = SecretKeySpec(KEY.toByteArray(), ALGORITHM)
val cipher = Cipher.getInstance(ALGORITHM)
cipher.init(Cipher.ENCRYPT_MODE, keySpec)
val encryptedBytes = cipher.doFinal(value.toByteArray())
return Base64.encodeToString(encryptedBytes, Base64.DEFAULT)
}
@Throws(Exception::class)
fun decrypt(encrypted: String?): String {
val keySpec = SecretKeySpec(KEY.toByteArray(), ALGORITHM)
val cipher = Cipher.getInstance(ALGORITHM)
cipher.init(Cipher.DECRYPT_MODE, keySpec)
val encryptedBytes = Base64.decode(encrypted, Base64.DEFAULT)
val decryptedBytes = cipher.doFinal(encryptedBytes)
return String(decryptedBytes)
}
//generates a secret key for the encryption functions to use
//TODO: Generating keys requires a higher API level. ask someone if this is okay.
}

View File

@@ -0,0 +1,14 @@
package com.example.hpostesting.data.model.devicediagnostics
data class AdditionalDetails(
val batteryLevel: String? = "",
val batteryCapacity: String? = "",
val batteryMaxCapacity: String? = "",
val batteryTemperature: String? = "",
val batteryVoltage: String? = "",
)

View File

@@ -0,0 +1,12 @@
package com.example.hpostesting.data.model.devicediagnostics
data class DeviceDiagnosticsData(
val id: String? = "",
val deviceId: String? = "",
val additionalDetails: AdditionalDetails?= AdditionalDetails(),
val createdBy: String? = "",
val updatedBy: String? = "",
val updatedAt: String? = "",
val createdAt: String? = "",
)

View File

@@ -0,0 +1,5 @@
package com.example.hpostesting.data.model.devicediagnostics
data class DeviceDiagnosticsRequest(
val additionalDetails: AdditionalDetails?= AdditionalDetails()
)

View File

@@ -0,0 +1,11 @@
package com.example.hpostesting.data.model.devicediagnostics
import com.google.gson.annotations.SerializedName
data class DeviceDiagnosticsResponse(
@SerializedName("Data")
val data: DeviceDiagnosticsData? = DeviceDiagnosticsData(),
val message: String? = "",
val result: String? = ""
)

View File

@@ -2,5 +2,5 @@ package com.example.hpostesting.data.model.deviceprovision
data class Credentials( data class Credentials(
val password: String? = "", val password: String? = "",
val username: String? = "" val username: String? = "",
) )

View File

@@ -13,5 +13,5 @@ data class Device(
val serialNumber: String? = "", val serialNumber: String? = "",
val uid: String? = "", val uid: String? = "",
val updatedAt: String? = "", val updatedAt: String? = "",
val updatedBy: Int? = 0 val updatedBy: Int? = 0,
) )

View File

@@ -2,5 +2,5 @@ package com.example.hpostesting.data.model.deviceprovision
data class DeviceProvisionData( data class DeviceProvisionData(
val credentials: Credentials? = Credentials(), val credentials: Credentials? = Credentials(),
val device: Device? = Device() val device: Device? = Device(),
) )

View File

@@ -5,5 +5,5 @@ data class DeviceProvisionRequest(
val email: String? = "", val email: String? = "",
val password: String? = "", val password: String? = "",
val serialNumber: String? = "", val serialNumber: String? = "",
val uid: String? = "" val uid: String? = "",
) )

View File

@@ -8,5 +8,5 @@ data class DeviceProvisionResponse(
@SerializedName("Message") @SerializedName("Message")
val message: String? = "", val message: String? = "",
@SerializedName("Result") @SerializedName("Result")
val result: String? = "" val result: String? = "",
) )

View File

@@ -8,5 +8,5 @@ data class DeviceType(
val id: Int? = 0, val id: Int? = 0,
val name: String? = "", val name: String? = "",
val updatedAt: String? = "", val updatedAt: String? = "",
val updatedBy: Int? = 0 val updatedBy: Int? = 0,
) )

View File

@@ -11,5 +11,5 @@ data class DeviceUser(
val natsTokenExpiry: String? = "", val natsTokenExpiry: String? = "",
val updatedAt: String? = "", val updatedAt: String? = "",
val updatedBy: Int? = 0, val updatedBy: Int? = 0,
val username: String? = "" val username: String? = "",
) )

View File

@@ -0,0 +1,8 @@
package com.example.hpostesting.data.model.deviceprovision
data class ProvisionData(
val username: String?,
val password: String?,
val natsToken: String?,
)

View File

@@ -1,6 +1,6 @@
package com.example.hpostesting.data.model.diagnostics package com.example.hpostesting.data.model.diagnostics
data class DiagnosticsData ( data class DiagnosticsData(
var deviceId: String = "", var deviceId: String = "",
var appVersion: String? = "", var appVersion: String? = "",
var deviceType: String = "HEMOCUBE", var deviceType: String = "HEMOCUBE",
@@ -8,5 +8,5 @@ data class DiagnosticsData (
var devicePassword: String = "", var devicePassword: String = "",
var deviceNatsToken: String = "", var deviceNatsToken: String = "",
var accessToken: String = "", var accessToken: String = "",
var runTime: String = "" var runTime: String = "",
) )

View File

@@ -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 = "",
)

View File

@@ -1,5 +1,5 @@
package com.example.hpostesting.data.model.log package com.example.hpostesting.data.model.log
data class UploadLogsData( data class UploadLogsData(
val filename: String? = "" val filename: String? = "",
) )

View File

@@ -8,5 +8,5 @@ data class UploadLogsResponse(
@SerializedName("Message") @SerializedName("Message")
val message: String? = "", val message: String? = "",
@SerializedName("Result") @SerializedName("Result")
val result: String? = "" val result: String? = "",
) )

View File

@@ -12,5 +12,5 @@ data class Device(
val serialNumber: String? = "", val serialNumber: String? = "",
val uid: String? = "", val uid: String? = "",
val updatedAt: String? = "", val updatedAt: String? = "",
val updatedBy: Int? = 0 val updatedBy: Int? = 0,
) )

View File

@@ -8,5 +8,5 @@ data class DeviceType(
val id: Int? = 0, val id: Int? = 0,
val name: String? = "", val name: String? = "",
val updatedAt: String? = "", val updatedAt: String? = "",
val updatedBy: Int? = 0 val updatedBy: Int? = 0,
) )

View File

@@ -12,5 +12,5 @@ data class DeviceUser(
val natsTokenExpiry: String? = "", val natsTokenExpiry: String? = "",
val updatedAt: String? = "", val updatedAt: String? = "",
val updatedBy: Int? = 0, val updatedBy: Int? = 0,
val username: String? = "" val username: String? = "",
) )

View File

@@ -2,5 +2,5 @@ package com.example.hpostesting.data.model.login
data class LoginData( data class LoginData(
val accessToken: String? = "", val accessToken: String? = "",
val deviceUser: DeviceUser? = DeviceUser() val deviceUser: DeviceUser? = DeviceUser(),
) )

View File

@@ -9,5 +9,5 @@ data class LoginRequest(
val password: String? = "", val password: String? = "",
val serialNumber: String? = "", val serialNumber: String? = "",
val username: String? = "", val username: String? = "",
val version: String? = "" val version: String? = "",
) )

View File

@@ -8,5 +8,5 @@ data class LoginResponse(
@SerializedName("Message") @SerializedName("Message")
val message: String? = "", val message: String? = "",
@SerializedName("Result") @SerializedName("Result")
val result: String? = "" val result: String? = "",
) )

View File

@@ -34,5 +34,5 @@ data class MolbioV2Result(
val testType: String? = "", val testType: String? = "",
val thresholds: String? = "", val thresholds: String? = "",
val underMedication: Boolean? = false, val underMedication: Boolean? = false,
val volume: Int? = 2 val volume: Int? = 2,
) )

View File

@@ -4,20 +4,20 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
data class MolbioV2ResultData( data class MolbioV2ResultData(
val age: Int? = 0, val age: Int? = 0,
val analysisDate: String? = "", val analysisDate: String? = "2024-02-08 16:33:56",
val analysisStatus: String? = "", val analysisStatus: String? = "",
val analysisType: String? = "", val analysisType: String? = "",
val analysisTypeMethod: String? = "", val analysisTypeMethod: String? = "",
val bloodGroup: String? = "", val bloodGroup: String? = "",
val coefficients: List<Int>? = listOf(), val coefficients: List<Int>? = listOf(),
val collectionLocation: List<Any>? = listOf(), val collectionLocation: List<Any>? = listOf(),
val collectionTime: String? = "", val collectionTime: String? = "2024-02-08 16:33:56",
val collector: String? = "", val collector: String? = "",
val createdAt: String? = "", val createdAt: String? = "",
val createdBy: Int? = 0, val createdBy: Int? = 0,
val curveFitting: String? = "", val curveFitting: String? = "",
val deviceId: Int? = 0, val deviceId: Int? = 0,
val expiryTime: String? = "", val expiryTime: String? = "2024-02-08 16:33:56",
val gender: String? = "", val gender: String? = "",
val id: Int? = 0, val id: Int? = 0,
val interpretation: String? = "", val interpretation: String? = "",
@@ -32,11 +32,11 @@ data class MolbioV2ResultData(
val testId: String? = "", val testId: String? = "",
val testResult: String? = "", val testResult: String? = "",
val testStatus: String? = "", val testStatus: String? = "",
val testTime: String? = "", val testTime: String? = "2024-02-08 16:33:56",
val testType: String? = "", val testType: String? = "",
val thresholds: String? = "", val thresholds: String? = "",
val underMedication: Boolean? = false, val underMedication: Boolean? = false,
val updatedAt: String? = "", val updatedAt: String? = "",
val updatedBy: Int? = 0, val updatedBy: Int? = 0,
val volume: Int? = 0 val volume: Int? = 0,
) )

View File

@@ -1,5 +1,5 @@
package com.example.hpostesting.data.model.molbioresult package com.example.hpostesting.data.model.molbioresult
data class MolbioV2ResultRequest( data class MolbioV2ResultRequest(
val results: MutableList<MolbioV2Result>? = mutableListOf() val results: MutableList<MolbioV2Result>? = mutableListOf(),
) )

View File

@@ -8,5 +8,5 @@ data class MolbioV2ResultResponse(
@SerializedName("Message") @SerializedName("Message")
val message: String? = "", val message: String? = "",
@SerializedName("Result") @SerializedName("Result")
val result: String? = "" val result: String? = "",
) )

View File

@@ -19,7 +19,7 @@ data class RawData(
var gender: String = "", var gender: String = "",
var localFlag: Boolean = false, var localFlag: Boolean = false,
var deviceId: String? = "", var deviceId: String? = "",
var appVersion:String? = "", var appVersion: String? = "",
var deviceSerialNumber: String = "", var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE", var deviceType: String = "HEMOCUBE",
var kitSerial: String = "", var kitSerial: String = "",

View File

@@ -9,7 +9,7 @@ data class BufferCheckData(
var _id: String = "", var _id: String = "",
var kitno: String = "", var kitno: String = "",
var deviceId: String? = "", var deviceId: String? = "",
var appVersion:String? = "", var appVersion: String? = "",
var deviceSerialNumber: String = "", var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE", var deviceType: String = "HEMOCUBE",
var localFlag: Boolean = false, var localFlag: Boolean = false,

View File

@@ -15,5 +15,15 @@ data class DeviceData(
@get:PropertyName("coefficients") @set:PropertyName("coefficients") @get:PropertyName("coefficients") @set:PropertyName("coefficients")
var coefficients: List<Double> = emptyList(), var coefficients: List<Double> = emptyList(),
@get:PropertyName("calibratedAt") @set:PropertyName("calibratedAt") @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 = "",
) )

View File

@@ -22,7 +22,7 @@ data class HemoCubeTestData(
var gender: String = "", var gender: String = "",
var localFlag: Boolean = false, var localFlag: Boolean = false,
var deviceId: String? = "", var deviceId: String? = "",
var appVersion:String? = "", var appVersion: String? = "",
var deviceSerialNumber: String = "", var deviceSerialNumber: String = "",
var deviceType: String = "HEMOCUBE", var deviceType: String = "HEMOCUBE",
var kitSerial: String = "", var kitSerial: String = "",
@@ -89,5 +89,5 @@ data class HemoCubeTestData(
var solution: String? = "", var solution: String? = "",
var concentration: String? = "", var concentration: String? = "",
var volume: String? = "", var volume: String? = "",
var isCSVCreated: Boolean = false var isCSVCreated: Boolean = false,
) )

View File

@@ -18,7 +18,7 @@ data class PatientDetails(
var address: Address?, var address: Address?,
var category: Category?, var category: Category?,
var registerDate: Date?, var registerDate: Date?,
var uploadDate: Date? var uploadDate: Date?,
) { ) {
constructor() : this( constructor() : this(
"", "",
@@ -45,7 +45,6 @@ data class PatientDetails(
OTHER OTHER
} }
data class Address( data class Address(
var house: String?, var house: String?,
val street: String?, val street: String?,

View File

@@ -29,7 +29,7 @@ data class UserData(
var reportPath: String = "", var reportPath: String = "",
var result: TestRightResultType? = null, var result: TestRightResultType? = null,
var resultRatio: Double? = null, var resultRatio: Double? = null,
var prdClassification: String = "" var prdClassification: String = "",
) { ) {
enum class Gender { enum class Gender {
MALE, MALE,
@@ -39,7 +39,7 @@ data class UserData(
data class Location( data class Location(
var latitude: Double? = null, var latitude: Double? = null,
var longitude: Double? = null var longitude: Double? = null,
) )
} }

View File

@@ -1,5 +1,5 @@
package com.example.hpostesting.data.model.updates package com.example.hpostesting.data.model.updates
data class CheckUpdateData( data class CheckUpdateData(
val version: String? = "" val version: String? = "",
) )

View File

@@ -1,5 +1,5 @@
package com.example.hpostesting.data.model.updates package com.example.hpostesting.data.model.updates
data class CheckUpdateRequest( data class CheckUpdateRequest(
val currentVersion: String? = "" val currentVersion: String? = "",
) )

View File

@@ -8,5 +8,5 @@ data class CheckUpdateResponse(
@SerializedName("Message") @SerializedName("Message")
val message: String? = "", val message: String? = "",
@SerializedName("Result") @SerializedName("Result")
val result: String? = "" val result: String? = "",
) )

View File

@@ -1,5 +1,5 @@
package com.example.hpostesting.data.model.updates package com.example.hpostesting.data.model.updates
data class DeviceUpdateRequest( data class DeviceUpdateRequest(
val serial_no: String? = "" val serial_no: String? = "",
) )

View File

@@ -6,9 +6,12 @@ import com.example.hpostesting.data.api.MolbioAuthApi
import com.example.hpostesting.data.api.MolbioResultApi import com.example.hpostesting.data.api.MolbioResultApi
import com.example.hpostesting.data.model.PendingUploads import com.example.hpostesting.data.model.PendingUploads
import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRequest
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsResponse
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData 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.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse import com.example.hpostesting.data.model.login.LoginResponse
@@ -37,8 +40,8 @@ import javax.inject.Named
class NetworkException(message: String, cause: Throwable) : Exception(message, cause) class NetworkException(message: String, cause: Throwable) : Exception(message, cause)
class DatabaseRepository @Inject constructor( class DatabaseRepository @Inject constructor(
@Named("Auth")private val molbioAuthApi: MolbioAuthApi, @Named("Auth") private val molbioAuthApi: MolbioAuthApi,
private val molbioResultApi: MolbioResultApi private val molbioResultApi: MolbioResultApi,
) : Repository { ) : Repository {
private val db: FirebaseFirestore = Firebase.firestore private val db: FirebaseFirestore = Firebase.firestore
@@ -77,6 +80,14 @@ class DatabaseRepository @Inject constructor(
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) } return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) }
} }
override suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse> {
return safeApiCall { molbioResultApi.deviceDiagnostics(deviceDiagnosticsRequest) }
}
override suspend fun downloadClientCertificate(): Result<ResponseBody> {
return safeApiCall { molbioResultApi.downloadClientCertificate() }
}
override suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> { override suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> {
return safeApiCall { molbioResultApi.uploadLogs(logFile) } return safeApiCall { molbioResultApi.uploadLogs(logFile) }
} }
@@ -134,8 +145,18 @@ class DatabaseRepository @Inject constructor(
} }
} }
override suspend fun addTestJigData(data: JigData?): Response<String> {
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( override suspend fun uploadFileToStorage(
patientID: String, filePath: String patientID: String, filePath: String,
): Response<Boolean> { ): Response<Boolean> {
try { try {
@@ -203,6 +224,26 @@ class DatabaseRepository @Inject constructor(
return allDeviceDataList.find { it.deviceId == deviceId } 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 { override fun <UserData> addTestToDatabase(testDetails: UserData): Any {
TODO("Not yet implemented") TODO("Not yet implemented")
} }

View File

@@ -2,9 +2,12 @@ package com.example.hpostesting.data.repository
import com.example.hpostesting.data.Result import com.example.hpostesting.data.Result
import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRequest
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsResponse
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData 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.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse import com.example.hpostesting.data.model.login.LoginResponse
@@ -29,9 +32,13 @@ interface Repository {
suspend fun addDiagnostics(data: DiagnosticsData?): Response<String> suspend fun addDiagnostics(data: DiagnosticsData?): Response<String>
suspend fun addTestJigData(data: JigData?): Response<String>
suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean> suspend fun uploadFileToStorage(patientID: String, filePath: String): Response<Boolean>
suspend fun getDeviceDataById(deviceId: String): DeviceData? 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 abstract fun <UserData> addTestToDatabase(testDetails: UserData): Any
// suspend fun addToDatabase(data: PatientDetails) // suspend fun addToDatabase(data: PatientDetails)
@@ -44,6 +51,7 @@ interface Repository {
suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse> suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse>
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody> suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody>
suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse>
suspend fun downloadClientCertificate(): Result<ResponseBody>
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse>
} }

View File

@@ -1,10 +1,10 @@
package com.example.hpostesting.domain package com.example.hpostesting.domain
import android.util.Log import android.util.Log
import com.example.hpostesting.data.repository.LocalFileRepository
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.test.TestRightCalculationData import com.example.hpostesting.data.model.test.TestRightCalculationData
import com.example.hpostesting.data.repository.LocalFileRepository
import java.util.Collections.sort import java.util.Collections.sort
class SaveRawData(private val localFileRepository: LocalFileRepository) { class SaveRawData(private val localFileRepository: LocalFileRepository) {
@@ -98,7 +98,7 @@ class SaveRawData(private val localFileRepository: LocalFileRepository) {
folderPath: String, folderPath: String,
fileName: String, fileName: String,
calculationData: TestRightCalculationData, calculationData: TestRightCalculationData,
testDetails: UserData? testDetails: UserData?,
) { ) {
// val fileObj = File(folderPath, fileName) // val fileObj = File(folderPath, fileName)
// val writer = FileWriter(fileObj) // val writer = FileWriter(fileObj)
@@ -116,7 +116,7 @@ class SaveRawData(private val localFileRepository: LocalFileRepository) {
private fun getLogStringFromObjWithPatientData( private fun getLogStringFromObjWithPatientData(
calculationData: TestRightCalculationData, calculationData: TestRightCalculationData,
testDetails: UserData? testDetails: UserData?,
): String { ): String {
var outputString = "Test calculation logs ==>\n" var outputString = "Test calculation logs ==>\n"
outputString += "Name = ${testDetails?.name}\n" outputString += "Name = ${testDetails?.name}\n"

View File

@@ -87,7 +87,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
override fun dcssdkEventAuxScannerAppeared( override fun dcssdkEventAuxScannerAppeared(
dcsScannerInfo: DCSScannerInfo?, dcsScannerInfo: DCSScannerInfo?,
dcsScannerInfo1: DCSScannerInfo? dcsScannerInfo1: DCSScannerInfo?,
) { ) {
} }
@@ -119,7 +119,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
// } // }
// } // }
try { try {
if (checkHemoCubeKitData()) { if (checkHemoCubeKitData()) {
DataHolder.selectedTest!!.kitSerial = DataHolder.selectedTest!!.kitSerial =
@@ -156,7 +155,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
pullTrigger() pullTrigger()
} }
binding.btnGo.setOnClickListener { binding.btnGo.setOnClickListener {
val serialNumber = binding.nameEditText.text.toString().trim() val serialNumber = binding.nameEditText.text.toString().trim()
if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) { if (serialNumber.isNotEmpty() && isSerialValid(serialNumber)) {
@@ -223,13 +221,12 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
notifications_mask or DCSSDKDefs.DCSSDK_EVENT.DCSSDK_EVENT_BARCODE.value notifications_mask or DCSSDKDefs.DCSSDK_EVENT.DCSSDK_EVENT_BARCODE.value
sdkHandler!!.dcssdkSubsribeForEvents(notifications_mask) sdkHandler!!.dcssdkSubsribeForEvents(notifications_mask)
mScannerInfoList.addAll(sdkHandler!!.dcssdkGetAvailableScannersList()) mScannerInfoList.addAll(sdkHandler!!.dcssdkGetAvailableScannersList())
Log.e("scannersize",sdkHandler!!.dcssdkGetAvailableScannersList().size.toString()) Log.e("scannersize", sdkHandler!!.dcssdkGetAvailableScannersList().size.toString())
if (mScannerInfoList.isNotEmpty()) { if (mScannerInfoList.isNotEmpty()) {
sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID) sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
} else { } else {
Toast.makeText(this,"Error", Toast.LENGTH_LONG).show() Toast.makeText(this,"Scanner Is not available In this device", Toast.LENGTH_LONG).show()
} }
} }
private fun pullTrigger() { private fun pullTrigger() {
@@ -243,7 +240,10 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
val outXML = StringBuilder() val outXML = StringBuilder()
val result: DCSSDK_RESULT = val result: DCSSDK_RESULT =
sdkHandler!!.dcssdkExecuteCommandOpCodeInXMLForScanner( sdkHandler!!.dcssdkExecuteCommandOpCodeInXMLForScanner(
DCSSDK_COMMAND_OPCODE.DCSSDK_DEVICE_PULL_TRIGGER, inXML, outXML, mScannerInfoList[0].scannerID // Ensure you're using the correct scanner ID DCSSDK_COMMAND_OPCODE.DCSSDK_DEVICE_PULL_TRIGGER,
inXML,
outXML,
mScannerInfoList[0].scannerID // Ensure you're using the correct scanner ID
) )
if (result == DCSSDK_RESULT.DCSSDK_RESULT_SUCCESS) { if (result == DCSSDK_RESULT.DCSSDK_RESULT_SUCCESS) {
Log.d("Scanning", "Success") Log.d("Scanning", "Success")
@@ -256,7 +256,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
} }
} }
//this function is called if barcode is detected. //this function is called if barcode is detected.
override fun dcssdkEventBarcode(barcodeData: ByteArray?, barcodeType: Int, fromScannerID: Int) { override fun dcssdkEventBarcode(barcodeData: ByteArray?, barcodeType: Int, fromScannerID: Int) {
val result = String(barcodeData!!) val result = String(barcodeData!!)
@@ -271,7 +270,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
return sharedPreference.getString(Constants.KIT_NUMBER, "") return sharedPreference.getString(Constants.KIT_NUMBER, "")
?.isNotBlank() == true && sharedPreference.getInt( ?.isNotBlank() == true && sharedPreference.getInt(
Constants.KIT_COUNT, 0 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 { private fun isSerialValid(s: String): Boolean {

View File

@@ -111,7 +111,11 @@ class MainActivity : AppCompatActivity() {
val deviceType = when { val deviceType = when {
availableDrivers.isNotEmpty() -> { availableDrivers.isNotEmpty() -> {
val device = availableDrivers[0].device val device = availableDrivers[0].device
Toast.makeText(this, "Connected, productId: ${device.productId}, vendorId: ${device.vendorId}", Toast.LENGTH_SHORT).show() Toast.makeText(
this,
"Connected, productId: ${device.productId}, vendorId: ${device.vendorId}",
Toast.LENGTH_SHORT
).show()
when { when {
device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID -> { device.productId == Constants.HOMO_CUBE_ID && device.vendorId == Constants.VENDOR_ID -> {
binding.cvItem1.visibility = View.VISIBLE binding.cvItem1.visibility = View.VISIBLE
@@ -348,7 +352,7 @@ class MainActivity : AppCompatActivity() {
} }
override fun onRequestPermissionsResult( override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults: IntArray requestCode: Int, permissions: Array<String>, grantResults: IntArray,
) { ) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults) super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) { when (requestCode) {

View File

@@ -1,6 +1,10 @@
package com.example.hpostesting.presentation package com.example.hpostesting.presentation
import android.content.Context
import android.os.Build
import android.util.Log import android.util.Log
import androidx.annotation.RequiresApi
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.presentation.dashboard.DashboardActivity
import io.nats.client.AuthHandler import io.nats.client.AuthHandler
import io.nats.client.Connection import io.nats.client.Connection
@@ -8,9 +12,17 @@ import io.nats.client.Message
import io.nats.client.NKey import io.nats.client.NKey
import io.nats.client.Nats import io.nats.client.Nats
import io.nats.client.Options import io.nats.client.Options
import io.nats.client.support.SSLUtils
import java.io.FileInputStream
import java.io.IOException import java.io.IOException
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import java.security.GeneralSecurityException 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) { class NatsManager(datacollector: DashboardActivity) {
@@ -19,103 +31,160 @@ class NatsManager(datacollector: DashboardActivity) {
var nc: Connection? = null var nc: Connection? = null
val datacollector = datacollector val datacollector = datacollector
var connect = false 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() { fun connect() {
Log.d(TAG, "TRY TO CONNECT") Log.d(TAG, "TRY TO CONNECT")
Thread { 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 { 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) nc = Nats.connect(options)
Log.d(TAG, "Connected to Nats server ${options.servers.first()}") Log.d(TAG, "Connected to Nats server ${options.servers.first()}")
connect = true connect = true
datacollector.setConnect(true) datacollector.setConnect(true)
if (nc?.status == Connection.Status.CONNECTED) {
Log.d("NATSCONNECTION", "NATS is successfully connected.")
nc?.publish( val d = nc?.createDispatcher { msg: Message? ->
"server.hpos.HCV-000-3001.ping", println("Nats dispatcher $msg")
"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")
}
d?.subscribe("device.hpos.HCV-000-3001.update") { msg -> nc?.subscribe("device.hpos.${deviceId}.ping")
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.uploadlogs") { msg -> nc?.publish(
val response = String(msg.data, StandardCharsets.UTF_8) "server.hpos.${deviceId}.ping",
datacollector.setResponse(response + "uPLOAD") "ALIVE".toByteArray(StandardCharsets.UTF_8)
println("Message received (up to 100 times): $response") )
} nc?.publish(
"server.hpos.${deviceId}.health",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
d?.subscribe("device.hpos.HCV-000-3001.disable") { msg -> d?.subscribe("device.hpos.${deviceId}.ping") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8) val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response) datacollector.setResponse(response)
println("Message received (up to 100 times): $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 -> d?.subscribe("device.hpos.${deviceId}.update") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8) val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response) datacollector.setResponse(response)
println("Message received (up to 100 times): $response") println("Message received (up to 100 times): $response")
} }
d?.subscribe("device.hpos.HCV-000-3001.checkupdate") { msg -> d?.subscribe("device.hpos.${deviceId}.uploadlogs") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8) val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response) datacollector.setResponse(response + "UPLOAD")
println("Message received (up to 100 times): $response") 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) { } catch (exp: Exception) {
println(exp.printStackTrace()) println(exp.printStackTrace())
connect = false connect = false
datacollector.setConnect(true) datacollector.setConnect(false)
} }
}.start() }.start()
@@ -126,6 +195,16 @@ class NatsManager(datacollector: DashboardActivity) {
Log.d(TAG, "Published msg ${msg} on topic ${topic}") 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() { fun close() {
nc?.close() nc?.close()
Log.d(TAG, "Nats connection close") Log.d(TAG, "Nats connection close")

View File

@@ -1,6 +1,5 @@
package com.example.hpostesting.presentation package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import android.Manifest import android.Manifest
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
@@ -16,6 +15,7 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.example.hpostesting.util.MyUtils import com.example.hpostesting.util.MyUtils
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
@@ -53,7 +53,10 @@ class SplashActivity : AppCompatActivity() {
private fun setupStaticConstants() { private fun setupStaticConstants() {
DataHolder.mobileUniqueId = DataHolder.mobileUniqueId =
Settings.Secure.getString(applicationContext.contentResolver, Settings.Secure.ANDROID_ID) Settings.Secure.getString(
applicationContext.contentResolver,
Settings.Secure.ANDROID_ID
)
} }
// private fun setupFirestoreCache() { // private fun setupFirestoreCache() {
@@ -98,7 +101,10 @@ class SplashActivity : AppCompatActivity() {
private fun requestPermissionsBelowAndroidR() { private fun requestPermissionsBelowAndroidR() {
val permissionsToRequest = requiredPermissions val permissionsToRequest = requiredPermissions
.filterNot { permission -> .filterNot { permission ->
ContextCompat.checkSelfPermission(this, permission) == PackageManager.PERMISSION_GRANTED ContextCompat.checkSelfPermission(
this,
permission
) == PackageManager.PERMISSION_GRANTED
} }
.toTypedArray() .toTypedArray()
@@ -114,9 +120,18 @@ class SplashActivity : AppCompatActivity() {
val coarseLocationPermission = Manifest.permission.ACCESS_COARSE_LOCATION val coarseLocationPermission = Manifest.permission.ACCESS_COARSE_LOCATION
val cameraPermission = Manifest.permission.CAMERA val cameraPermission = Manifest.permission.CAMERA
val locationPermissionsGranted = val locationPermissionsGranted =
ContextCompat.checkSelfPermission(this, fineLocationPermission) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(
ContextCompat.checkSelfPermission(this, coarseLocationPermission) == PackageManager.PERMISSION_GRANTED this,
val cameraPermissionGranted = ContextCompat.checkSelfPermission(this, cameraPermission) == PackageManager.PERMISSION_GRANTED fineLocationPermission
) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(
this,
coarseLocationPermission
) == PackageManager.PERMISSION_GRANTED
val cameraPermissionGranted = ContextCompat.checkSelfPermission(
this,
cameraPermission
) == PackageManager.PERMISSION_GRANTED
if (locationPermissionsGranted && cameraPermissionGranted) { if (locationPermissionsGranted && cameraPermissionGranted) {
handlePermissionsResult(true) handlePermissionsResult(true)

View File

@@ -1,6 +1,6 @@
package com.example.hpostesting.presentation package com.example.hpostesting.presentation
interface UsbServiceListener { interface UsbServiceListener {
fun onUsbRead(data: ByteArray?) fun onUsbRead(data: ByteArray?)
fun onUsbError(e: Exception?) fun onUsbError(e: Exception?)
} }

View File

@@ -17,13 +17,11 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.OfflineUserListViewBinding import `in`.sminnovations.hpostesting.databinding.OfflineUserListViewBinding
import org.apache.commons.collections4.MapUtils.getString
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
class OfflineUserListAdapter(private val view: View, private val batLevel: Int) : class OfflineUserListAdapter(private val view: View, private val batLevel: Int) :
RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() { RecyclerView.Adapter<OfflineUserListAdapter.OfflineUserListViewHolder>() {
@@ -33,13 +31,13 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
private val differCallback = object : DiffUtil.ItemCallback<HemoCubeTestData>() { private val differCallback = object : DiffUtil.ItemCallback<HemoCubeTestData>() {
override fun areItemsTheSame( override fun areItemsTheSame(
oldItem: HemoCubeTestData, newItem: HemoCubeTestData oldItem: HemoCubeTestData, newItem: HemoCubeTestData,
): Boolean { ): Boolean {
return oldItem._id == newItem._id return oldItem._id == newItem._id
} }
override fun areContentsTheSame( override fun areContentsTheSame(
oldItem: HemoCubeTestData, newItem: HemoCubeTestData oldItem: HemoCubeTestData, newItem: HemoCubeTestData,
): Boolean { ): Boolean {
return oldItem == newItem return oldItem == newItem
} }
@@ -104,20 +102,20 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
).show() ).show()
} else } else
if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) { if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) {
Toast.makeText( Toast.makeText(
view.context, view.context,
view.context.getString(R.string.incubation_crossed_30_minutes), view.context.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} else { } else {
DataHolder.selectedTest = UserData( DataHolder.selectedTest = UserData(
_id = userList._id, _id = userList._id,
bloodGroup = userList.bloodGroup, bloodGroup = userList.bloodGroup,
incubationTime = userList.incubationTime incubationTime = userList.incubationTime
) )
view.findNavController() view.findNavController()
.navigate(R.id.action_nav_home_to_mainActivity) .navigate(R.id.action_nav_home_to_mainActivity)
} }
} else { } else {
Toast.makeText( Toast.makeText(
view.context, view.context,
@@ -143,7 +141,6 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
return diffMillis / (60 * 1000) return diffMillis / (60 * 1000)
} }
private fun showWarningToast(resId: Int) { private fun showWarningToast(resId: Int) {
val contextToUse = view.context ?: return val contextToUse = view.context ?: return

View File

@@ -4,30 +4,28 @@ import android.annotation.SuppressLint
import android.app.AlertDialog import android.app.AlertDialog
import android.content.Context import android.content.Context
import android.content.Context.INPUT_METHOD_SERVICE import android.content.Context.INPUT_METHOD_SERVICE
import android.view.inputmethod.InputMethodManager
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import android.widget.AutoCompleteTextView
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide import com.bumptech.glide.Glide
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.firebase.ui.firestore.FirestoreRecyclerAdapter import com.firebase.ui.firestore.FirestoreRecyclerAdapter
import com.firebase.ui.firestore.FirestoreRecyclerOptions import com.firebase.ui.firestore.FirestoreRecyclerOptions
import com.google.firebase.firestore.FirebaseFirestore
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.UserItemViewBinding import `in`.sminnovations.hpostesting.databinding.UserItemViewBinding
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import android.widget.AutoCompleteTextView
import androidx.core.content.ContextCompat.getSystemService
import androidx.core.content.getSystemService
import androidx.fragment.app.FragmentActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.firebase.firestore.FirebaseFirestore
class UserListAdapter( class UserListAdapter(
@@ -36,7 +34,7 @@ class UserListAdapter(
options: FirestoreRecyclerOptions<UserData>, options: FirestoreRecyclerOptions<UserData>,
private val view: View, private val view: View,
private val batLevel: Int, private val batLevel: Int,
private val requireActivity: FragmentActivity private val requireActivity: FragmentActivity,
) : FirestoreRecyclerAdapter<UserData, UserListAdapter.OrderItemViewHolder>(options) { ) : FirestoreRecyclerAdapter<UserData, UserListAdapter.OrderItemViewHolder>(options) {
class OrderItemViewHolder(val binding: UserItemViewBinding) : class OrderItemViewHolder(val binding: UserItemViewBinding) :
@@ -96,16 +94,21 @@ class UserListAdapter(
.setView(dialogView) .setView(dialogView)
.setTitle(R.string.blood_group) .setTitle(R.string.blood_group)
val etBloodGroup = dialogView.findViewById<AutoCompleteTextView>(R.id.et_blood_group) val etBloodGroup =
dialogView.findViewById<AutoCompleteTextView>(R.id.et_blood_group)
builder.setPositiveButton(R.string.ok) { dialog, which -> builder.setPositiveButton(R.string.ok) { dialog, which ->
val bloodGroup = etBloodGroup.text.toString() val bloodGroup = etBloodGroup.text.toString()
if (bloodGroup.equals("Select Blood Group") ||bloodGroup.equals("ರಕ್ತ ಗುಂಪು ಆಯ್ಕೆಮಾಡಿ") || bloodGroup.isNullOrBlank()) { if (bloodGroup.equals("Select Blood Group") || bloodGroup.equals("ರಕ್ತ ಗುಂಪು ಆಯ್ಕೆಮಾಡಿ") || bloodGroup.isNullOrBlank()) {
if (view != null) { if (view != null) {
etBloodGroup.error =view.context.getString(R.string.blood_group_error) etBloodGroup.error = view.context.getString(R.string.blood_group_error)
} }
if (view != null) { if (view != null) {
Toast.makeText(context, view.context.getString(R.string.blood_group_toast), Toast.LENGTH_SHORT).show() Toast.makeText(
context,
view.context.getString(R.string.blood_group_toast),
Toast.LENGTH_SHORT
).show()
} }
} else { } else {
// Check if hemoCubeViewModel and testDetails are not null // Check if hemoCubeViewModel and testDetails are not null
@@ -119,7 +122,8 @@ class UserListAdapter(
val document = userdata.documents[0] val document = userdata.documents[0]
db.collection("patientData") db.collection("patientData")
.document(document.id) .document(document.id)
.update("bloodGroup", bloodGroup, .update(
"bloodGroup", bloodGroup,
"incubationTime", SimpleDateFormat( "incubationTime", SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time).toString() ).format(Calendar.getInstance().time).toString()

View File

@@ -8,7 +8,7 @@ import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.databinding.ActivityAssuranceControlsBinding import `in`.sminnovations.hpostesting.databinding.ActivityAssuranceControlsBinding
@AndroidEntryPoint @AndroidEntryPoint
class AssuranceControlsActivity: AppCompatActivity() { class AssuranceControlsActivity : AppCompatActivity() {
lateinit var binding: ActivityAssuranceControlsBinding lateinit var binding: ActivityAssuranceControlsBinding
lateinit var sharedPreference: SharedPreferences lateinit var sharedPreference: SharedPreferences

View File

@@ -13,6 +13,7 @@ import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Spinner import android.widget.Spinner
import android.widget.Toast import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
@@ -21,7 +22,7 @@ import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import `in`.sminnovations.hpostesting.databinding.FragmentAssuranceControlsBinding import `in`.sminnovations.hpostesting.databinding.FragmentAssuranceControlsBinding
import java.time.Instant import java.time.Instant
class AssuranceControlsFragment: Fragment() { class AssuranceControlsFragment : Fragment() {
lateinit var binding: FragmentAssuranceControlsBinding lateinit var binding: FragmentAssuranceControlsBinding
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
@@ -47,7 +48,8 @@ class AssuranceControlsFragment: Fragment() {
val solutionSpinner: Spinner = binding.spinnerSolutions val solutionSpinner: Spinner = binding.spinnerSolutions
val solutionOptions = arrayOf("Select solution", "Tartrazine", "Acid Red") val solutionOptions = arrayOf("Select solution", "Tartrazine", "Acid Red")
val solutionAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, solutionOptions) val solutionAdapter =
ArrayAdapter(requireContext(), R.layout.simple_spinner_item, solutionOptions)
solutionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) solutionAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
solutionSpinner.adapter = solutionAdapter solutionSpinner.adapter = solutionAdapter
solutionSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { solutionSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
@@ -55,7 +57,7 @@ class AssuranceControlsFragment: Fragment() {
parent: AdapterView<*>?, parent: AdapterView<*>?,
view: View?, view: View?,
position: Int, position: Int,
id: Long id: Long,
) { ) {
val selectedValue: String = solutionOptions[position] val selectedValue: String = solutionOptions[position]
if (!selectedValue.equals("Select solution")) { if (!selectedValue.equals("Select solution")) {
@@ -68,8 +70,21 @@ class AssuranceControlsFragment: Fragment() {
} }
val concentrationSpinner: Spinner = binding.spinnerConcentration val concentrationSpinner: Spinner = binding.spinnerConcentration
val concentrationOptions = arrayOf("Select concentration", "65umol", "45umol", "22.5umol", "12.25umol", "6.125umol", "75umol", "50umol", "25umol", "12.5umol", "6.25umol") val concentrationOptions = arrayOf(
val concentrationAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, concentrationOptions) "Select concentration",
"65umol",
"45umol",
"22.5umol",
"12.25umol",
"6.125umol",
"75umol",
"50umol",
"25umol",
"12.5umol",
"6.25umol"
)
val concentrationAdapter =
ArrayAdapter(requireContext(), R.layout.simple_spinner_item, concentrationOptions)
concentrationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) concentrationAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
concentrationSpinner.adapter = concentrationAdapter concentrationSpinner.adapter = concentrationAdapter
concentrationSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { concentrationSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
@@ -77,7 +92,7 @@ class AssuranceControlsFragment: Fragment() {
parent: AdapterView<*>?, parent: AdapterView<*>?,
view: View?, view: View?,
position: Int, position: Int,
id: Long id: Long,
) { ) {
val selectedValue: String = concentrationOptions[position] val selectedValue: String = concentrationOptions[position]
if (!selectedValue.equals("Select concentration")) { if (!selectedValue.equals("Select concentration")) {
@@ -91,7 +106,8 @@ class AssuranceControlsFragment: Fragment() {
val volumeSpinner: Spinner = binding.spinnerVolume val volumeSpinner: Spinner = binding.spinnerVolume
val volumeOptions = arrayOf("Select volume", "1uml", "2uml", "4uml", "4.5uml", "5uml") val volumeOptions = arrayOf("Select volume", "1uml", "2uml", "4uml", "4.5uml", "5uml")
val volumeAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, volumeOptions) val volumeAdapter =
ArrayAdapter(requireContext(), R.layout.simple_spinner_item, volumeOptions)
volumeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) volumeAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
volumeSpinner.adapter = volumeAdapter volumeSpinner.adapter = volumeAdapter
volumeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener { volumeSpinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
@@ -99,12 +115,9 @@ class AssuranceControlsFragment: Fragment() {
parent: AdapterView<*>?, parent: AdapterView<*>?,
view: View?, view: View?,
position: Int, position: Int,
id: Long id: Long,
) { ) {
val selectedValue: String = volumeOptions[position] val selectedValue: String = volumeOptions[position]
if (!selectedValue.equals("Select volume")) {
DataHolder.hemoCubeTestData!!.volume = selectedValue
}
} }
override fun onNothingSelected(parent: AdapterView<*>?) { override fun onNothingSelected(parent: AdapterView<*>?) {
@@ -112,12 +125,15 @@ class AssuranceControlsFragment: Fragment() {
} }
// load saved values // load saved values
val savedSolution = sharedPreferences.getString(Constants.QUICK_CAPTURE_SOLUTION, "").toString() val savedSolution =
sharedPreferences.getString(Constants.QUICK_CAPTURE_SOLUTION, "").toString()
val solutionPosition = getPositionOfValue(savedSolution, solutionOptions.toList()) val solutionPosition = getPositionOfValue(savedSolution, solutionOptions.toList())
solutionSpinner.setSelection(solutionPosition) solutionSpinner.setSelection(solutionPosition)
val savedConcentration = sharedPreferences.getString(Constants.QUICK_CAPTURE_CONCENTRATION, "").toString() val savedConcentration =
val concentrationPosition = getPositionOfValue(savedConcentration, concentrationOptions.toList()) sharedPreferences.getString(Constants.QUICK_CAPTURE_CONCENTRATION, "").toString()
val concentrationPosition =
getPositionOfValue(savedConcentration, concentrationOptions.toList())
concentrationSpinner.setSelection(concentrationPosition) concentrationSpinner.setSelection(concentrationPosition)
val savedVolume = sharedPreferences.getString(Constants.QUICK_CAPTURE_VOLUME, "").toString() val savedVolume = sharedPreferences.getString(Constants.QUICK_CAPTURE_VOLUME, "").toString()
@@ -125,13 +141,19 @@ class AssuranceControlsFragment: Fragment() {
volumeSpinner.setSelection(volumePosition) volumeSpinner.setSelection(volumePosition)
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
val selectedSolution = DataHolder.hemoCubeTestData!!.solution val selectedSolution = binding.spinnerSolutions.selectedItem.toString()
val selectedVolume = DataHolder.hemoCubeTestData!!.volume val selectedConcentration = binding.spinnerConcentration.selectedItem.toString()
if (selectedSolution == "Select solution" || selectedVolume == "Select volume") {
Toast.makeText(requireContext(), "Please select both solution and volume", Toast.LENGTH_SHORT).show() // Check if any of the selections are default values
return@setOnClickListener if (selectedSolution == "Select solution") {
Toast.makeText(requireContext(), "Please select a solution", Toast.LENGTH_LONG).show()
return@setOnClickListener // Prevent further execution
} }
if (selectedConcentration == "Select concentration") {
Toast.makeText(requireContext(), "Please select a concentration", Toast.LENGTH_LONG).show()
return@setOnClickListener // Prevent further execution
}
DataHolder.hemoCubeTestData!!.quickCapture = true DataHolder.hemoCubeTestData!!.quickCapture = true
val currentUnixTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val currentUnixTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Instant.now().epochSecond Instant.now().epochSecond
@@ -139,7 +161,9 @@ class AssuranceControlsFragment: Fragment() {
"" ""
} }
DataHolder.hemoCubeTestData!!._id = currentUnixTime.toString() + "SMI" DataHolder.hemoCubeTestData!!._id = currentUnixTime.toString() + "SMI"
DataHolder.hemoCubeTestData!!.name = "${DataHolder.hemoCubeTestData!!.solution} ${DataHolder.hemoCubeTestData!!.concentration} ${DataHolder.hemoCubeTestData!!.volume}" DataHolder.hemoCubeTestData!!.solution = binding.spinnerSolutions.selectedItem.toString()
DataHolder.hemoCubeTestData!!.name = binding.spinnerConcentration.selectedItem.toString()
"${DataHolder.hemoCubeTestData!!.solution} ${DataHolder.hemoCubeTestData!!.concentration} ${DataHolder.hemoCubeTestData!!.volume}"
DataHolder.selectedTest = UserData() DataHolder.selectedTest = UserData()
DataHolder.selectedTest?._id = DataHolder.hemoCubeTestData!!._id DataHolder.selectedTest?._id = DataHolder.hemoCubeTestData!!._id
@@ -147,7 +171,10 @@ class AssuranceControlsFragment: Fragment() {
with(sharedPreferences.edit()) { with(sharedPreferences.edit()) {
putString(Constants.QUICK_CAPTURE_SOLUTION, DataHolder.hemoCubeTestData!!.solution) putString(Constants.QUICK_CAPTURE_SOLUTION, DataHolder.hemoCubeTestData!!.solution)
putString(Constants.QUICK_CAPTURE_CONCENTRATION, DataHolder.hemoCubeTestData!!.concentration) putString(
Constants.QUICK_CAPTURE_CONCENTRATION,
DataHolder.hemoCubeTestData!!.concentration
)
putString(Constants.QUICK_CAPTURE_VOLUME, DataHolder.hemoCubeTestData!!.volume) putString(Constants.QUICK_CAPTURE_VOLUME, DataHolder.hemoCubeTestData!!.volume)
apply() apply()
} }

View File

@@ -31,7 +31,7 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityAutoDacBinding import `in`.sminnovations.hpostesting.databinding.ActivityAutoDacBinding
@AndroidEntryPoint @AndroidEntryPoint
class AutoDacActivity: AppCompatActivity() { class AutoDacActivity : AppCompatActivity() {
private lateinit var binding: ActivityAutoDacBinding private lateinit var binding: ActivityAutoDacBinding
val viewModel: AutoDacViewModel by viewModels() val viewModel: AutoDacViewModel by viewModels()
private var myMenu: Menu? = null private var myMenu: Menu? = null
@@ -58,11 +58,9 @@ class AutoDacActivity: AppCompatActivity() {
DataHolder.usbConnected.postValue(true) DataHolder.usbConnected.postValue(true)
} }
} }
} }
} }
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder val binder = service as UsbService.UsbServiceBinder
@@ -107,6 +105,7 @@ class AutoDacActivity: AppCompatActivity() {
} }
} }
} }
open fun connectUsb(permissionGranted: Boolean) { open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted") Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager val manager = getSystemService(Context.USB_SERVICE) as UsbManager
@@ -126,7 +125,6 @@ class AutoDacActivity: AppCompatActivity() {
} }
} }
fun onErrorReported(msg: String) { fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed() if (!isFinishing) onBackPressed()
@@ -161,17 +159,16 @@ class AutoDacActivity: AppCompatActivity() {
manager.requestPermission(device, mPendingIntent) manager.requestPermission(device, mPendingIntent)
} }
fun setupService() { fun setupService() {
val intent = Intent(this, UsbService::class.java) val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE) bindService(intent, connection, Context.BIND_AUTO_CREATE)
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu) menuInflater.inflate(R.menu.my_menu, menu)
return true return true
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
if (viewModel.isServiceConnected) { if (viewModel.isServiceConnected) {

View File

@@ -22,7 +22,7 @@ import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Locale import java.util.Locale
class AutoDacFragment: Fragment() { class AutoDacFragment : Fragment() {
private lateinit var binding: FragmentAutoDacBinding private lateinit var binding: FragmentAutoDacBinding
private val autoDacViewModel: AutoDacViewModel by activityViewModels() private val autoDacViewModel: AutoDacViewModel by activityViewModels()
@@ -47,7 +47,6 @@ class AutoDacFragment: Fragment() {
observeViewModel() observeViewModel()
} }
private fun initViews() { private fun initViews() {
binding.btnSubmit.visibility = View.GONE binding.btnSubmit.visibility = View.GONE
listenToHemoCube() listenToHemoCube()
@@ -56,9 +55,12 @@ class AutoDacFragment: Fragment() {
binding.btnSubmit.visibility = View.GONE binding.btnSubmit.visibility = View.GONE
runAutoDacCommand() runAutoDacCommand()
} }
binding.btnReadDac.setOnClickListener {
binding.btnReadDac.visibility = View.GONE
readCurrentDACValuesCommand()
}
} }
private fun observeViewModel() { private fun observeViewModel() {
autoDacViewModel.deviceData.observe(viewLifecycleOwner) { autoDacViewModel.deviceData.observe(viewLifecycleOwner) {
@@ -93,6 +95,7 @@ class AutoDacFragment: Fragment() {
binding.tvSubtitle4.text = stringData binding.tvSubtitle4.text = stringData
} }
} }
override fun onUsbError(e: Exception?) { override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false) autoDacViewModel.progressBar.postValue(false)
} }
@@ -106,6 +109,35 @@ class AutoDacFragment: Fragment() {
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) { override fun onUsbRead(data: ByteArray?) {
} }
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
private fun setAutoDacValuesCommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.SET_AUTO_DAC_TO_EPROM_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false)
}
})
}
private fun readCurrentDACValuesCommand() {
autoDacViewModel.progressBar.postValue(true)
(activity as AutoDacActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.READ_DAC_COMMAND,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) { override fun onUsbError(e: Exception?) {
autoDacViewModel.progressBar.postValue(false) autoDacViewModel.progressBar.postValue(false)
} }
@@ -143,12 +175,24 @@ class AutoDacFragment: Fragment() {
} }
if (resultData.contains("#CC")) { if (resultData.contains("#CC")) {
setAutoDacValuesCommand()
autoDacViewModel.addAutoDacDataToDb( autoDacViewModel.addAutoDacDataToDb(
DiagnosticsData( DiagnosticsData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(), deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "")
devicePassword = sharedPreferences.getString(Constants.DEVICE_PASSWORD_API, "").toString(), .toString(),
deviceNatsToken = sharedPreferences.getString(Constants.NATS_TOKEN, "").toString(), devicePassword = sharedPreferences.getString(
accessToken = sharedPreferences.getString(Constants.ACCESS_TOKEN, "").toString(), Constants.DEVICE_PASSWORD_API,
""
).toString(),
deviceNatsToken = sharedPreferences.getString(
Constants.NATS_TOKEN,
""
).toString(),
accessToken = sharedPreferences.getString(
Constants.ACCESS_TOKEN,
""
).toString(),
deviceData = resultData, deviceData = resultData,
runTime = SimpleDateFormat( runTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
@@ -159,6 +203,10 @@ class AutoDacFragment: Fragment() {
binding.ivCheck.visibility = View.VISIBLE binding.ivCheck.visibility = View.VISIBLE
} }
} }
if (resultData.contains("#WC")) {
showToast("DAC Values saved to EPROM")
}
} }
override fun onUsbError(e: Exception?) { override fun onUsbError(e: Exception?) {

View File

@@ -2,12 +2,9 @@ package com.example.hpostesting.presentation.autodac
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.NetworkStatusLiveData
import com.example.hpostesting.data.dao.HemoCubeDao import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
@@ -18,10 +15,10 @@ import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class AutoDacViewModel @Inject constructor( class AutoDacViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao, private val hemoCubeDao: HemoCubeDao,
private val repository: Repository, private val repository: Repository,
context: Context context: Context,
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)

View File

@@ -0,0 +1,4 @@
package com.example.hpostesting.presentation.blank
class BlankActivity {
}

View File

@@ -0,0 +1,4 @@
package com.example.hpostesting.presentation.blank
class BlankFragment {
}

View File

@@ -0,0 +1,4 @@
package com.example.hpostesting.presentation.blank
class BlankViewModel {
}

View File

@@ -142,6 +142,10 @@ class HemoCubeBufferCheckFragment : Fragment() {
hemoCubeViewModel.messages.observe(viewLifecycleOwner) { hemoCubeViewModel.messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it binding.tvSubtitle4.text = it
} }
hemoCubeViewModel.deviceMessages.observe(viewLifecycleOwner) {
binding.tvDeviceMessages.text = it
}
} }
private fun checkAndStartProcess() { private fun checkAndStartProcess() {
@@ -175,6 +179,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
} }
resultData += stringData resultData += stringData
hemoCubeViewModel.deviceMessages.postValue(resultData)
when { when {
stringData.contains("SN") -> { stringData.contains("SN") -> {
@@ -201,8 +206,9 @@ class HemoCubeBufferCheckFragment : Fragment() {
stringData.contains("#BC") -> { stringData.contains("#BC") -> {
activity?.runOnUiThread { activity?.runOnUiThread {
binding.tvSubtitle4.text = "Buffer Completed" binding.tvSubtitle4.text = "Buffer Completed"
binding.btnSamplestart.visibility = View.VISIBLE // binding.btnSamplestart.visibility = View.VISIBLE
} }
fetchResult()
} }
stringData.contains("#SS") -> { stringData.contains("#SS") -> {
@@ -218,9 +224,9 @@ class HemoCubeBufferCheckFragment : Fragment() {
} }
resultData.contains("REND") -> { resultData.contains("REND") -> {
hemoCubeViewModel.messages.postValue( // hemoCubeViewModel.messages.postValue(
"Data collected \n" + " Processing data" // "Data collected \n" + " Processing data"
) // )
val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex()) val resultLines = resultData.split("\\s+(?=LB|LS)".toRegex())
var bufferIntensity = resultLines[1].split(' ')[1].trim() var bufferIntensity = resultLines[1].split(' ')[1].trim()
led1BufferForDevice = bufferIntensity.toDoubleOrNull()!! led1BufferForDevice = bufferIntensity.toDoubleOrNull()!!
@@ -242,7 +248,7 @@ class HemoCubeBufferCheckFragment : Fragment() {
private fun processResult() { private fun processResult() {
try { try {
hemoCubeViewModel.messages.postValue("processing result") // hemoCubeViewModel.messages.postValue("processing result")
val deviceLog = resultData val deviceLog = resultData
val pInfo = requireActivity().packageManager.getPackageInfo( val pInfo = requireActivity().packageManager.getPackageInfo(

View File

@@ -61,6 +61,7 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() {
} }
} }
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder val binder = service as UsbService.UsbServiceBinder
@@ -127,18 +128,19 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() {
@SuppressLint("MutableImplicitPendingIntent") @SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) { private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { val mPendingIntent: PendingIntent =
PendingIntent.getBroadcast( if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE PendingIntent.getBroadcast(
) this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
} else { )
PendingIntent.getBroadcast( } else {
this, PendingIntent.getBroadcast(
0, this,
Intent(Constants.HEMOCUBE_USB_PERMISSION), 0,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE Intent(Constants.HEMOCUBE_USB_PERMISSION),
) PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
} )
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION) val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter) registerReceiver(broadcastReceiver, filter)
@@ -153,7 +155,8 @@ open class HemocubeBufferCheckActivity : AppCompatActivity() {
private fun moveToNext() { private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, HemoCubeBufferCheckFragment()) supportFragmentManager.beginTransaction()
.replace(binding.fghemocube.id, HemoCubeBufferCheckFragment())
.commit() .commit()
} }

View File

@@ -31,7 +31,7 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityCalibrationBinding import `in`.sminnovations.hpostesting.databinding.ActivityCalibrationBinding
@AndroidEntryPoint @AndroidEntryPoint
class CalibrationActivity: AppCompatActivity() { class CalibrationActivity : AppCompatActivity() {
private lateinit var binding: ActivityCalibrationBinding private lateinit var binding: ActivityCalibrationBinding
val viewModel: CalibrationViewModel by viewModels() val viewModel: CalibrationViewModel by viewModels()
private var myMenu: Menu? = null private var myMenu: Menu? = null
@@ -107,6 +107,7 @@ class CalibrationActivity: AppCompatActivity() {
} }
} }
} }
open fun connectUsb(permissionGranted: Boolean) { open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted") Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager val manager = getSystemService(Context.USB_SERVICE) as UsbManager
@@ -136,41 +137,42 @@ class CalibrationActivity: AppCompatActivity() {
private fun moveToNext() { private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fgCalibration.id, CalibrationFragment()) supportFragmentManager.beginTransaction()
.replace(binding.fgCalibration.id, CalibrationFragment())
.commit() .commit()
} }
@SuppressLint("MutableImplicitPendingIntent") @SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) { private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { val mPendingIntent: PendingIntent =
PendingIntent.getBroadcast( if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE PendingIntent.getBroadcast(
) this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
} else { )
PendingIntent.getBroadcast( } else {
this, PendingIntent.getBroadcast(
0, this,
Intent(Constants.HEMOCUBE_USB_PERMISSION), 0,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE Intent(Constants.HEMOCUBE_USB_PERMISSION),
) PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
} )
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION) val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter) registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent) manager.requestPermission(device, mPendingIntent)
} }
fun setupService() { fun setupService() {
val intent = Intent(this, UsbService::class.java) val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE) bindService(intent, connection, Context.BIND_AUTO_CREATE)
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu) menuInflater.inflate(R.menu.my_menu, menu)
return true return true
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
if (viewModel.isServiceConnected) { if (viewModel.isServiceConnected) {

View File

@@ -23,7 +23,7 @@ import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentCalibrationBinding import `in`.sminnovations.hpostesting.databinding.FragmentCalibrationBinding
class CalibrationFragment: Fragment() { class CalibrationFragment : Fragment() {
private lateinit var binding: FragmentCalibrationBinding private lateinit var binding: FragmentCalibrationBinding
private val calibrationViewModel: CalibrationViewModel by activityViewModels() private val calibrationViewModel: CalibrationViewModel by activityViewModels()
@@ -50,7 +50,6 @@ class CalibrationFragment: Fragment() {
loadSavedCalibration() loadSavedCalibration()
} }
private fun initViews() { private fun initViews() {
binding.btnSubmit.visibility = View.GONE binding.btnSubmit.visibility = View.GONE
listenToHemoCube() listenToHemoCube()
@@ -226,6 +225,7 @@ class CalibrationFragment: Fragment() {
binding.tvSubtitle4.text = stringData binding.tvSubtitle4.text = stringData
} }
} }
override fun onUsbError(e: Exception?) { override fun onUsbError(e: Exception?) {
calibrationViewModel.progressBar.postValue(false) calibrationViewModel.progressBar.postValue(false)
} }

View File

@@ -2,21 +2,12 @@ package com.example.hpostesting.presentation.calibration
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.NetworkStatusLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.calibration.CalibrationData import com.example.hpostesting.data.model.calibration.CalibrationData
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@@ -30,12 +21,8 @@ class CalibrationViewModel @Inject constructor(
private val sharedPreference: SharedPreferences = private val sharedPreference: SharedPreferences =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
// private val _networkStatusLiveData = NetworkStatusLiveData(context)
val deviceData = MutableLiveData<DeviceData?>() val deviceData = MutableLiveData<DeviceData?>()
// val networkStatusLiveData: LiveData<Boolean>
// get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>() val fireBaseUpload = MutableLiveData<String>()
val savedCalibrationData = MutableLiveData<String>()
fun loadSavedCalibrationData(): CalibrationData { fun loadSavedCalibrationData(): CalibrationData {
val calibrationData = CalibrationData() val calibrationData = CalibrationData()

View File

@@ -4,7 +4,9 @@ import android.app.DownloadManager
import android.content.BroadcastReceiver import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
@@ -19,9 +21,11 @@ import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.data.Result import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.NatsManager import com.example.hpostesting.presentation.NatsManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.jig.JigActivity
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.appdistribution.FirebaseAppDistribution
import com.google.firebase.appdistribution.FirebaseAppDistributionException import com.google.firebase.appdistribution.FirebaseAppDistributionException
@@ -32,15 +36,22 @@ import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import okhttp3.ResponseBody import okhttp3.ResponseBody
import java.io.File import java.io.File
open interface IDataCollector { interface NatsMessageCallback {
fun onMessageReceived(topic: String, message: String)
}
open interface IDataCollector: NatsMessageCallback {
fun setConnect(connect: Boolean) fun setConnect(connect: Boolean)
fun setResponse(response: String) fun setResponse(response: String)
} }
@AndroidEntryPoint @AndroidEntryPoint
class DashboardActivity : AppCompatActivity(), IDataCollector { class DashboardActivity : AppCompatActivity(), IDataCollector {
val TAG = "DashboardActivity"
private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDashboardBinding private lateinit var binding: ActivityDashboardBinding
lateinit var sharedPreferences: SharedPreferences
var responses: String = "" var responses: String = ""
lateinit var nats: NatsManager lateinit var nats: NatsManager
private var downloadId: Long = 0 private var downloadId: Long = 0
@@ -53,15 +64,28 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
super.attachBaseContext(newBase) 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?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityDashboardBinding.inflate(layoutInflater) binding = ActivityDashboardBinding.inflate(layoutInflater)
sharedPreferences = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar) setSupportActionBar(binding.appBarDashboard.toolbar)
nats = NatsManager(this) nats = NatsManager(this)
nats.connect() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG") 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 -> hemocubeViewModel.deviceUpdate.observe(this) { result ->
when (result) { when (result) {
@@ -71,11 +95,11 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
// val apkUrl = "https://dl.dropboxusercontent.com/s/fi/1c3nn7t0co431hicl3hrt/app-debug.apk?rlkey=e4uf13ty1dpcked614vy1aaqp&dl=0" // val apkUrl = "https://dl.dropboxusercontent.com/s/fi/1c3nn7t0co431hicl3hrt/app-debug.apk?rlkey=e4uf13ty1dpcked614vy1aaqp&dl=0"
initiateUpdate(apkUrl.toString()) initiateUpdate(apkUrl.toString())
Log.d("ApI", "APK URL: $apkUrl") Log.d("ApI", "APK URL: $apkUrl")
Toast.makeText( // Toast.makeText(
this, // this,
"APK UPLOAD ${result.data}", // "APK UPLOAD ${result.data}",
Toast.LENGTH_SHORT // Toast.LENGTH_SHORT
).show() // ).show()
} }
is Result.Error -> { is Result.Error -> {
@@ -93,7 +117,6 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
} }
} }
val drawerLayout: DrawerLayout = binding.drawerLayout val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_dashboard) val navController = findNavController(R.id.nav_host_fragment_content_dashboard)
@@ -105,6 +128,11 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
) )
setupActionBarWithNavController(navController, appBarConfiguration) setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController) navView.setupWithNavController(navController)
if (Constants.NAVIGATE_TO_TEST_JIG_DIRECTLY) {
startActivity(Intent(this, JigActivity::class.java))
finish()
}
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -156,9 +184,10 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
val file = File(getExternalFilesDir("Updates"), "update.apk") val file = File(getExternalFilesDir("Updates"), "update.apk")
file.setReadable(true, false) // Ensure the file is readable file.setReadable(true, false) // Ensure the file is readable
val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
val uri: Uri = FileProvider.getUriForFile( val uri: Uri = FileProvider.getUriForFile(
this, this,
"com.example.hpostesting.qa.fileprovider", "${pInfo}.fileprovider",
file file
) )

View File

@@ -27,6 +27,7 @@ class GalleryFragment : Fragment() {
private var _binding: FragmentGalleryBinding? = null private var _binding: FragmentGalleryBinding? = null
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
private var userid = "" private var userid = ""
// This property is only valid between onCreateView and // This property is only valid between onCreateView and
// onDestroyView. // onDestroyView.
private val binding get() = _binding!! private val binding get() = _binding!!
@@ -37,7 +38,7 @@ class GalleryFragment : Fragment() {
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View { ): View {
// val galleryViewModel = // val galleryViewModel =
// ViewModelProvider(this).get(GalleryViewModel::class.java) // ViewModelProvider(this).get(GalleryViewModel::class.java)
@@ -57,7 +58,7 @@ class GalleryFragment : Fragment() {
) { ) {
binding.btnDeviceProvision.visibility = View.VISIBLE binding.btnDeviceProvision.visibility = View.VISIBLE
} else { } else {
binding.btnDeviceProvision.visibility = View.GONE binding.btnDeviceProvision.visibility = View.VISIBLE
} }
binding.btnDeviceProvision.setOnClickListener { binding.btnDeviceProvision.setOnClickListener {

View File

@@ -19,16 +19,20 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.Result 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.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.login.LoginRequest import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2Result import com.example.hpostesting.data.model.molbioresult.MolbioV2Result
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest 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.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.KitScanActivity 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.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
@@ -43,11 +47,21 @@ import com.google.firebase.perf.ktx.performance
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
import okhttp3.ResponseBody
import org.json.JSONObject 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.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
import java.util.Locale import java.util.Locale
import java.util.concurrent.atomic.AtomicBoolean
import java.util.zip.ZipEntry
import java.util.zip.ZipInputStream
@AndroidEntryPoint @AndroidEntryPoint
class HomeFragment : Fragment() { class HomeFragment : Fragment() {
@@ -62,12 +76,16 @@ class HomeFragment : Fragment() {
private val homeViewModel: HemoCubeViewModel by activityViewModels() private val homeViewModel: HemoCubeViewModel by activityViewModels()
private var isTokenAvailable = false private var isTokenAvailable = false
private var natsToken: String = ""
private var deviceId: String = ""
private lateinit var sharedPreference: SharedPreferences private lateinit var sharedPreference: SharedPreferences
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View? { ): View? {
_binding = FragmentHomeBinding.inflate(inflater, container, false) _binding = FragmentHomeBinding.inflate(inflater, container, false)
Log.d("OnCreate Home Fragment", "HomeFragment calls")
// Check if _binding is null // Check if _binding is null
if (_binding == null) { if (_binding == null) {
@@ -89,7 +107,7 @@ class HomeFragment : Fragment() {
binding.labelQuickCapture.visibility = View.VISIBLE binding.labelQuickCapture.visibility = View.VISIBLE
binding.btnQuickCapture.visibility = View.VISIBLE binding.btnQuickCapture.visibility = View.VISIBLE
} }
getDeviceId()
checkUnprocessedCSVData() checkUnprocessedCSVData()
viewModel.allUserData.observe(viewLifecycleOwner) { userData -> viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteIncompleteRegistrations(userData) deleteIncompleteRegistrations(userData)
@@ -110,51 +128,85 @@ class HomeFragment : Fragment() {
binding.rvOrderOffline.adapter = adapter binding.rvOrderOffline.adapter = adapter
} }
} }
viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected -> hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) { deviceData ->
if (isConnected) { val devicelist = mutableListOf<DeviceData>()
if (deviceData != null) {
devicelist.add(DeviceData(deviceData.deviceId))
}
}
viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected ->
Log.d("NETWORK OBSERVE", "OBSERVE CALLED")
if (isConnected) {
binding.internetAvailableCL.visibility = View.VISIBLE binding.internetAvailableCL.visibility = View.VISIBLE
binding.internetNotAvailableCL.visibility = View.GONE binding.internetNotAvailableCL.visibility = View.GONE
binding.pendingTest.visibility = View.VISIBLE
loadUserData() loadUserData()
setSearch() setSearch()
checkForLocalDBData() checkForLocalDBData()
checkForTokenAndUpdate() if (Constants.MOLBIO_INTEGRATION) {
checkForTokenAndUpdate()
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { originalUserDataList ->
val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
userDataList.forEach { userData -> Log.d("LOCAL_DB OBSERVE", "OBSERVE CALLED")
if (!userData.molbioFlag && isTokenAvailable) {
val resultList = MolbioV2ResultRequest(mutableListOf())
originalUserDataList.forEach { userData ->
Log.d(
": USER DATA",
originalUserDataList.count().toString() + " : " + userData._id
)
if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION) {
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
val bufferIntensityThreshold =
Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId]?.toString()
?: "defaultThreshold" // Handle possible nulls safely
resultList.results?.add( resultList.results?.add(
MolbioV2Result( MolbioV2Result(
rawData = userData, rawData = userData,
analysisId = userData._id, analysisId = userData._id,
analysisDate = "2024-02-08 16:33:56", analysisDate = currentTimeFormatted,
analysisStatus = userData.classificationResult, analysisStatus = userData.classificationResult
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(), ?: "defaultStatus", // Handle possible nulls
interpretation = userData.classificationResult, thresholds = bufferIntensityThreshold,
interpretation = userData.classificationResult
?: "defaultInterpretation", // Handle possible nulls
testId = userData._id, testId = userData._id,
testTime = userData.testTime, testTime = currentTimeFormatted,
collectionTime = "2024-02-08 16:33:56",//userData.testTime, collectionTime = currentTimeFormatted,
expiryTime = "2024-02-08 16:33:56"//userData.testTime, expiryTime = currentTimeFormatted
) )
) )
} }
if (!userData.molbioFlag && isTokenAvailable) {
userData.molbioFlag = true
hemoCubeViewModel.uploadResult(resultList)
}
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
} }
Log.d("USER DATA LIST SIZE", resultList.results?.count().toString())
resultList.results?.forEach { result ->
val userData = result.rawData
Log.d("UserData", userData.toString())
if (userData != null) {
if (!userData.localFlag) {
hemoCubeViewModel.bulkAddResultTestToDb(userData)
userData.localFlag = true
}
}
}
// Upload results after processing all userData to avoid duplicates and ensure all modifications are done
if (resultList.results?.isNotEmpty() == true) {
hemoCubeViewModel.uploadResult(resultList)
}
} }
} else { } else {
binding.internetAvailableCL.visibility = View.GONE binding.internetAvailableCL.visibility = View.GONE
binding.pendingTest.visibility = View.GONE
binding.internetNotAvailableCL.visibility = View.VISIBLE binding.internetNotAvailableCL.visibility = View.VISIBLE
setUserId() setUserId()
} }
@@ -174,14 +226,13 @@ class HomeFragment : Fragment() {
logoutUser(requireContext()) logoutUser(requireContext())
} }
binding.uploadData.setOnClickListener { binding.uploadData.setOnClickListener {
showUploadDialog(requireContext()) showUploadDialog(requireContext())
} }
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
val btnSaveLocalVisibility = val btnSaveLocalVisibility =
if (userData.any { it.testStatus == true }) View.VISIBLE else View.GONE if (userData.any { it.testStatus == true }) View.GONE else View.GONE
binding.downloadCSV.visibility = btnSaveLocalVisibility binding.downloadCSV.visibility = btnSaveLocalVisibility
@@ -222,13 +273,17 @@ class HomeFragment : Fragment() {
binding.downloadCSV.setOnClickListener { binding.downloadCSV.setOnClickListener {
showDownloadDialog(requireContext()) showDownloadDialog(requireContext())
} }
} }
private fun checkForTokenAndUpdate() { private fun checkForTokenAndUpdate() {
val accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString() var accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
val password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString() var password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
val userID = sharedPreference.getString(Constants.DEVICE_ID_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 (userID.isNotEmpty() && password.isNotEmpty()) {
if (!isTokenAvailable) { if (!isTokenAvailable) {
hemoCubeViewModel.login(createLoginRequestData(userID, password)) hemoCubeViewModel.login(createLoginRequestData(userID, password))
@@ -241,10 +296,49 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData()) hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
hemoCubeViewModel.uploadLogs() hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.startPeriodicCheckUpdate() 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 if (fis.available()>0){
// val buffer = ByteArray(fis.available())
// fis.read(buffer)
// fis.close()
// val encryptedData = String(buffer)
// val parts = encryptedData.split(",".toRegex()).dropLastWhile { it.isEmpty() }
// .toTypedArray()
// val deviceID = parts[0]
// val decryptedUsername = decrypt(parts[1])
// val decryptedPassword = decrypt(parts[2])
// if (accessToken.isEmpty()) {
// hemoCubeViewModel.login(createLoginRequestData(decryptedUsername, decryptedPassword))
//}
// else {
// // Continue with your existing logic if the token is not empty.
// isTokenAvailable = true
// hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
// hemoCubeViewModel.uploadLogs()
// hemoCubeViewModel.startPeriodicCheckUpdate()
// }
//}
else {
Toast.makeText( Toast.makeText(
requireContext(), requireContext(),
"Contact Help and get your device provision done", "Contact Help and get your device provision done",
@@ -280,11 +374,11 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.uploadLogs.observe(viewLifecycleOwner) { response -> hemoCubeViewModel.uploadLogs.observe(viewLifecycleOwner) { response ->
when (response) { when (response) {
is Result.Success -> { is Result.Success -> {
Toast.makeText( // Toast.makeText(
requireContext(), // requireContext(),
"Log uploaded ${response.data.data?.filename}", // "Log uploaded ${response.data.data?.filename}",
Toast.LENGTH_SHORT // Toast.LENGTH_SHORT
).show() // ).show()
} }
is Result.Error -> { is Result.Error -> {
@@ -306,9 +400,55 @@ 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) { hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) { when (it) {
is Result.Success -> { is Result.Success -> {
Log.d("MOLBIO UPLOAD", "RESULT SUCCESS")
it.data.data?.forEach { id -> it.data.data?.forEach { id ->
id.rawData?.let { it1 -> id.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag( hemoCubeViewModel.updateMolbioFlag(
@@ -316,22 +456,29 @@ class HomeFragment : Fragment() {
) )
} }
} }
} }
is Result.Error -> { is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL //Remove this line of code while deploying to IOCL
it.exception.let { message -> it.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG) Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show() .show()
} }
} }
else -> {} else -> {
}
} }
} }
} }
private fun isTokenExpired(token: String): Boolean { private fun isTokenExpired(token: String): Boolean {
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT)) val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
@@ -381,6 +528,63 @@ 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() { private fun setUserId() {
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString() val userId = binding.userId.text.toString()
@@ -406,6 +610,52 @@ 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() { private fun loadUserData() {
try { try {
val dateFormat = SimpleDateFormat("yyyy-MM-dd") val dateFormat = SimpleDateFormat("yyyy-MM-dd")
@@ -575,7 +825,7 @@ class HomeFragment : Fragment() {
private fun checkUnprocessedCSVData() { private fun checkUnprocessedCSVData() {
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val downloadDataVisibility = val downloadDataVisibility =
if (userDataList.any { !it.isCSVCreated && it.testStatus == true }) View.VISIBLE else View.GONE if (userDataList.any { !it.isCSVCreated && it.testStatus == true }) View.GONE else View.GONE
binding.downloadCSV.visibility = downloadDataVisibility binding.downloadCSV.visibility = downloadDataVisibility
} }
} }
@@ -630,39 +880,6 @@ class HomeFragment : Fragment() {
} }
} }
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", //userData.reportUploadTime,
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.localFlag){
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
if (!userData.molbioFlag && isTokenAvailable) {
userData.molbioFlag = true
hemoCubeViewModel.uploadResult(resultList)
}
}
dialog.dismiss()
}
hemoCubeViewModel.allKitTestData.observe(viewLifecycleOwner) { kitDataList -> hemoCubeViewModel.allKitTestData.observe(viewLifecycleOwner) { kitDataList ->
kitDataList.forEach { userData -> kitDataList.forEach { userData ->
if (!userData.localFlag) { if (!userData.localFlag) {
@@ -672,6 +889,7 @@ class HomeFragment : Fragment() {
} }
dialog.dismiss() dialog.dismiss()
} }
} }
// private fun downloadLocalDBData(dialog: DialogInterface) { // private fun downloadLocalDBData(dialog: DialogInterface) {
@@ -791,4 +1009,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 ?: ""
}
}

View File

@@ -37,7 +37,8 @@ class SlideshowFragment : PreferenceFragmentCompat() {
// App Version Preference // App Version Preference
val appVersionPreference = Preference(requireContext()) val appVersionPreference = Preference(requireContext())
appVersionPreference.title = "App Version" appVersionPreference.title = "App Version"
appVersionPreference.summary = getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + " ]" appVersionPreference.summary =
getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + " ]"
preferenceScreen.addPreference(languagePreference) preferenceScreen.addPreference(languagePreference)
preferenceScreen.addPreference(appVersionPreference) preferenceScreen.addPreference(appVersionPreference)

View File

@@ -3,11 +3,11 @@ package com.example.hpostesting.presentation.dashboard.ui
import android.content.Context import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
@@ -20,7 +20,7 @@ class LoginFragment : Fragment() {
private lateinit var sharedPreference: SharedPreferences private lateinit var sharedPreference: SharedPreferences
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle? savedInstanceState: Bundle?,
): View { ): View {
_binding = FragmentLoginBinding.inflate(inflater, container, false) _binding = FragmentLoginBinding.inflate(inflater, container, false)
sharedPreference = sharedPreference =
@@ -33,7 +33,6 @@ class LoginFragment : Fragment() {
init() init()
} }
private fun init() { private fun init() {
if (isUserLoggedIn()) { if (isUserLoggedIn()) {
navigateToHomeFragment() navigateToHomeFragment()

View File

@@ -12,18 +12,21 @@ import android.content.SharedPreferences
import android.hardware.usb.UsbDevice import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager import android.hardware.usb.UsbManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.get import androidx.core.view.get
import com.example.hpostesting.data.DataHolder 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.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.testRight.UsbService import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -33,7 +36,7 @@ import `in`.sminnovations.hpostesting.databinding.ActivityDeviceBinding
@Suppress("MemberVisibilityCanBePrivate") @Suppress("MemberVisibilityCanBePrivate")
@AndroidEntryPoint @AndroidEntryPoint
class DeviceActivity : AppCompatActivity() { class DeviceActivity : AppCompatActivity(), DeviceCommunicationHandler {
private lateinit var binding: ActivityDeviceBinding private lateinit var binding: ActivityDeviceBinding
private val deviceViewModel by viewModels<DeviceViewModel>() private val deviceViewModel by viewModels<DeviceViewModel>()
private var myMenu: Menu? = null private var myMenu: Menu? = null
@@ -169,6 +172,7 @@ class DeviceActivity : AppCompatActivity() {
menuInflater.inflate(R.menu.my_menu, menu) menuInflater.inflate(R.menu.my_menu, menu)
return true return true
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
if (deviceViewModel.isServiceConnected) { if (deviceViewModel.isServiceConnected) {
@@ -177,4 +181,11 @@ class DeviceActivity : AppCompatActivity() {
deviceViewModel.isServiceConnected = false deviceViewModel.isServiceConnected = false
} }
} }
override fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener) {
mService.sendAndListenToHemoCube(
command = HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
listener
)
}
} }

View File

@@ -18,8 +18,6 @@ import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceBinding import `in`.sminnovations.hpostesting.databinding.FragmentDeviceBinding
class DeviceFragment : Fragment() { class DeviceFragment : Fragment() {
private lateinit var binding: FragmentDeviceBinding private lateinit var binding: FragmentDeviceBinding
private val deviceViewModel: HemoCubeViewModel by activityViewModels() private val deviceViewModel: HemoCubeViewModel by activityViewModels()
@@ -61,6 +59,7 @@ class DeviceFragment : Fragment() {
binding.tvSubtitle4.text = "Device ID: ${stringData}" binding.tvSubtitle4.text = "Device ID: ${stringData}"
} }
} }
override fun onUsbError(e: Exception?) { override fun onUsbError(e: Exception?) {
deviceViewModel.progressBar.postValue(false) deviceViewModel.progressBar.postValue(false)
} }
@@ -68,7 +67,6 @@ class DeviceFragment : Fragment() {
} }
private fun listenToHemoCube() { private fun listenToHemoCube() {
val fullReadOutput = StringBuilder() val fullReadOutput = StringBuilder()

View File

@@ -7,6 +7,7 @@ import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class DeviceViewModel @Inject constructor( class DeviceViewModel @Inject constructor(
private val hemoCubeDao: HemoCubeDao, private val hemoCubeDao: HemoCubeDao,
@@ -15,11 +16,6 @@ class DeviceViewModel @Inject constructor(
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>() val messages = MutableLiveData<String>()
// private val _networkStatusLiveData = NetworkStatusLiveData(context)
// val allUserData = hemoCubeDao.getAll()
val deviceData = MutableLiveData<DeviceData?>() val deviceData = MutableLiveData<DeviceData?>()
// val networkStatusLiveData: LiveData<Boolean>
// get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>() val fireBaseUpload = MutableLiveData<String>()
} }

View File

@@ -21,8 +21,11 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.get import androidx.core.view.get
import com.example.hpostesting.data.DataHolder 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.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.testRight.UsbService import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -31,7 +34,7 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityAutoDacBinding import `in`.sminnovations.hpostesting.databinding.ActivityAutoDacBinding
@AndroidEntryPoint @AndroidEntryPoint
class DeviceProvisionActivity : AppCompatActivity() { class DeviceProvisionActivity : AppCompatActivity(), DeviceCommunicationHandler {
private lateinit var binding: ActivityAutoDacBinding private lateinit var binding: ActivityAutoDacBinding
val viewModel: DeviceProvisionViewModel by viewModels() val viewModel: DeviceProvisionViewModel by viewModels()
private var myMenu: Menu? = null private var myMenu: Menu? = null
@@ -90,7 +93,6 @@ class DeviceProvisionActivity : AppCompatActivity() {
supportActionBar?.setDisplayHomeAsUpEnabled(true) supportActionBar?.setDisplayHomeAsUpEnabled(true)
setupListener() setupListener()
connectUsb(false) connectUsb(false)
} }
private fun setupListener() { private fun setupListener() {
@@ -142,18 +144,19 @@ class DeviceProvisionActivity : AppCompatActivity() {
@SuppressLint("MutableImplicitPendingIntent") @SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) { private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) { val mPendingIntent: PendingIntent =
PendingIntent.getBroadcast( if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE PendingIntent.getBroadcast(
) this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
} else { )
PendingIntent.getBroadcast( } else {
this, PendingIntent.getBroadcast(
0, this,
Intent(Constants.HEMOCUBE_USB_PERMISSION), 0,
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE Intent(Constants.HEMOCUBE_USB_PERMISSION),
) PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
} )
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION) val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter) registerReceiver(broadcastReceiver, filter)
@@ -180,4 +183,11 @@ class DeviceProvisionActivity : AppCompatActivity() {
viewModel.isServiceConnected = false viewModel.isServiceConnected = false
} }
} }
override fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener) {
mService.sendAndListenToHemoCube(
command = HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
listener
)
}
} }

View File

@@ -4,30 +4,38 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.widget.Toast import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.Result import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.encryption.AESCrypt
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest 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.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.firebase.crashlytics.ktx.crashlytics import com.google.firebase.crashlytics.ktx.crashlytics
import com.google.firebase.ktx.Firebase import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding
class DeviceProvisionFragment : Fragment() {
class DeviceProvisionFragment : Fragment() {
private var resultData: String = "" private var resultData: String = ""
private lateinit var binding: FragmentDeviceProvisionBinding private lateinit var binding: FragmentDeviceProvisionBinding
private val viewModel: DeviceProvisionViewModel by activityViewModels() private val viewModel: DeviceProvisionViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences 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( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View { ): View {
binding = FragmentDeviceProvisionBinding.inflate(inflater, container, false) binding = FragmentDeviceProvisionBinding.inflate(inflater, container, false)
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
@@ -44,18 +52,25 @@ class DeviceProvisionFragment : Fragment() {
listenToHemoCube() listenToHemoCube()
getDeviceId() getDeviceId()
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
viewModel.deviceProvision( if (Constants.MOLBIO_INTEGRATION) {
DeviceProvisionRequest( viewModel.deviceProvision(
email = Constants.deviceProvisionEmail, DeviceProvisionRequest(
password = Constants.deviceProvisionPassword, email = Constants.deviceProvisionEmail,
serialNumber = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(), password = Constants.deviceProvisionPassword,
uid = sharedPreferences.getString(Constants.DEVICE_ID, "").toString() serialNumber = sharedPreferences.getString(Constants.DEVICE_ID, "")
.toString(),
uid = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()
)
) )
) }
} }
} }
private fun observeViewModel() { private fun observeViewModel() {
viewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
viewModel.deviceProvisionResponse.observe(viewLifecycleOwner) { response -> viewModel.deviceProvisionResponse.observe(viewLifecycleOwner) { response ->
when (response) { when (response) {
@@ -74,20 +89,49 @@ class DeviceProvisionFragment : Fragment() {
Constants.NATS_TOKEN, Constants.NATS_TOKEN,
response.data.data?.device?.deviceUser?.natsToken response.data.data?.device?.deviceUser?.natsToken
) )
response.data.data?.device?.deviceUser?.natsToken?.let {
Log.e(
"natstoken",
it
)
}
putString( putString(
Constants.NATS_TOKEN_EXPIRE_DATE, Constants.NATS_TOKEN_EXPIRE_DATE,
response.data.data?.device?.deviceUser?.natsTokenExpiry response.data.data?.device?.deviceUser?.natsTokenExpiry
) )
apply() apply()
} }
startActivity(Intent(requireContext(), DashboardActivity::class.java)) startActivity(
Intent(
requireContext(),
DashboardActivity::class.java
)
)
Toast.makeText( Toast.makeText(
activity, "Device registered successfully", Toast.LENGTH_LONG activity, "Device registered successfully", Toast.LENGTH_LONG
).show() ).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)
saveDataToLocalFile(response.data.data?.credentials?.username.toString(), response.data.data?.credentials?.password.toString())
} else { } else {
Toast.makeText( Toast.makeText(
activity, activity,
"An error occurred in device provision: ${response.data.message}", "An error in device provision: ${response.data.message}",
Toast.LENGTH_LONG Toast.LENGTH_LONG
).show() ).show()
binding.btnSubmit.visibility = View.VISIBLE binding.btnSubmit.visibility = View.VISIBLE
@@ -112,6 +156,15 @@ class DeviceProvisionFragment : Fragment() {
else -> {} 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() { private fun getDeviceId() {
@@ -128,7 +181,8 @@ class DeviceProvisionFragment : Fragment() {
val fullReadOutput = StringBuilder() val fullReadOutput = StringBuilder()
try { try {
(activity as DeviceProvisionActivity).mService.listenToHemoCube(object : UsbServiceListener { (activity as DeviceProvisionActivity).mService.listenToHemoCube(object :
UsbServiceListener {
override fun onUsbRead(data: ByteArray?) { override fun onUsbRead(data: ByteArray?) {
data?.let { data?.let {
val stringData = String(it) val stringData = String(it)
@@ -169,4 +223,18 @@ class DeviceProvisionFragment : Fragment() {
} }
} }
} }
//saves username and password to a local file after encrypting it.
private fun saveDataToLocalFile( username : String, password : String){
val deviceID = sharedPreferences.getString(Constants.DEVICE_ID, "").toString();
val encryptedUsername = AESCrypt.encrypt(username)
val encryptedPassword = AESCrypt.encrypt(password)
val encryptedData = deviceID + "\n" + encryptedUsername + "\n" + encryptedPassword
val fileOutputStream = requireContext().openFileOutput("credentials.txt", Context.MODE_PRIVATE)
fileOutputStream.write(encryptedData.toByteArray())
fileOutputStream.close()
}
} }

View File

@@ -4,8 +4,10 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.Result 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.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -13,17 +15,54 @@ import javax.inject.Inject
@HiltViewModel @HiltViewModel
class DeviceProvisionViewModel @Inject constructor( class DeviceProvisionViewModel @Inject constructor(
private val databaseRepository: Repository private val repository: Repository,
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>() val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>()
val fireBaseUpload = MutableLiveData<String>()
val fireBaseBulkUpload = MutableLiveData<String>()
val deviceData = MutableLiveData<DeviceData?>()
fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch { fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
deviceProvisionResponse.postValue(Result.Loading()) deviceProvisionResponse.postValue(Result.Loading())
databaseRepository.deviceProvision(deviceProvisionRequest).let { repository.deviceProvision(deviceProvisionRequest).let {
deviceProvisionResponse.postValue(it) 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")
}
}
}
} }

View File

@@ -11,13 +11,13 @@ import android.content.ServiceConnection
import android.hardware.usb.UsbDevice import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager import android.hardware.usb.UsbManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import android.os.IBinder
import android.util.Log import android.util.Log
import android.view.Menu import android.view.Menu
import android.widget.Toast import android.widget.Toast
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.view.get import androidx.core.view.get
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
@@ -63,7 +63,6 @@ class DiagnosticsActivity : AppCompatActivity() {
} }
} }
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder val binder = service as UsbService.UsbServiceBinder
@@ -108,6 +107,7 @@ class DiagnosticsActivity : AppCompatActivity() {
} }
} }
} }
open fun connectUsb(permissionGranted: Boolean) { open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted") Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager val manager = getSystemService(Context.USB_SERVICE) as UsbManager
@@ -127,17 +127,16 @@ class DiagnosticsActivity : AppCompatActivity() {
} }
} }
fun onErrorReported(msg: String) { fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed() if (!isFinishing) onBackPressed()
} }
private fun moveToNext() { private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fgDiagnostics.id, DiagnosticsFragment()) supportFragmentManager.beginTransaction()
.replace(binding.fgDiagnostics.id, DiagnosticsFragment())
.commit() .commit()
} }
@@ -162,17 +161,16 @@ class DiagnosticsActivity : AppCompatActivity() {
manager.requestPermission(device, mPendingIntent) manager.requestPermission(device, mPendingIntent)
} }
fun setupService() { fun setupService() {
val intent = Intent(this, UsbService::class.java) val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE) bindService(intent, connection, Context.BIND_AUTO_CREATE)
} }
override fun onCreateOptionsMenu(menu: Menu?): Boolean { override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.my_menu, menu) menuInflater.inflate(R.menu.my_menu, menu)
return true return true
} }
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
if (viewModel.isServiceConnected) { if (viewModel.isServiceConnected) {

View File

@@ -1,6 +1,8 @@
package com.example.hpostesting.presentation.diagnostics package com.example.hpostesting.presentation.diagnostics
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@@ -11,8 +13,12 @@ import android.widget.Toast
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.Result.Success
import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.devicediagnostics.AdditionalDetails
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRequest
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.UsbServiceListener import com.example.hpostesting.presentation.UsbServiceListener
@@ -32,7 +38,10 @@ class DiagnosticsFragment : Fragment() {
private var resultData: String = "" private var resultData: String = ""
private val messages = MutableLiveData<String>() private val messages = MutableLiveData<String>()
private var startListening = MutableLiveData(false) private var startListening = MutableLiveData(false)
private val batteryStatus: Intent? =
IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
context?.registerReceiver(null, ifilter)
}
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
): View { ): View {
@@ -56,7 +65,25 @@ class DiagnosticsFragment : Fragment() {
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
binding.btnSubmit.visibility = View.GONE binding.btnSubmit.visibility = View.GONE
runDeviceDiagnostics() runDeviceDiagnostics()
val batteryLevel = "" //diagnosticsViewModel.getBatteryLevel().toString()
val batteryCapacity = "" //context?.let { diagnosticsViewModel.getBatteryCapacity(it).toString() }
val batteryMaxCapacity = "" //context?.let { diagnosticsViewModel.getBatteryMaxCapacity(it).toString() }
val batteryTemperature = "" //diagnosticsViewModel.getBatteryTemperature().toString()
val batteryVoltage = "" // context?.let { diagnosticsViewModel.getBatteryVoltage(it).toString() }
val additionalDetails = AdditionalDetails(
batteryLevel = batteryLevel,
batteryCapacity = batteryCapacity!!,
batteryMaxCapacity = batteryMaxCapacity!!,
batteryTemperature = batteryTemperature,
batteryVoltage = batteryVoltage!!
)
diagnosticsViewModel.deviceDiagnostics(
DeviceDiagnosticsRequest(additionalDetails = additionalDetails)
)
} }
} }
@@ -68,7 +95,7 @@ class DiagnosticsFragment : Fragment() {
messages.observe(viewLifecycleOwner) { messages.observe(viewLifecycleOwner) {
binding.tvSubtitle4.text = it binding.tvSubtitle4.text = it
Log.e("diagnostics",binding.tvSubtitle4.text.toString()) Log.e("diagnostics", binding.tvSubtitle4.text.toString())
} }
diagnosticsViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result -> diagnosticsViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
@@ -81,6 +108,42 @@ class DiagnosticsFragment : Fragment() {
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
} }
diagnosticsViewModel.deviceDiagnosticsResponse.observe(viewLifecycleOwner) { response ->
when (response) {
is Success -> {
if (response.data.result == "Success") {
Toast.makeText(
activity, response.data.message ?: "Device diagnostics uploaded successfully", Toast.LENGTH_LONG
).show()
response.data.data?.let { diagnosticsData ->
val batteryLevel = diagnosticsData.additionalDetails?.batteryLevel
}
} else {
Toast.makeText(
activity,
"${response.data.message}",
Toast.LENGTH_LONG
).show()
}
}
is Result.Error -> {
// Handle the error scenario
Toast.makeText(
activity,
"An error occurred: ${response.exception.message}",
Toast.LENGTH_LONG
).show()
}
is Result.Loading -> {
}
}
}
} }
private fun getDeviceId() { private fun getDeviceId() {
@@ -95,6 +158,7 @@ class DiagnosticsFragment : Fragment() {
binding.tvSubtitle4.text = stringData binding.tvSubtitle4.text = stringData
} }
} }
override fun onUsbError(e: Exception?) { override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false) diagnosticsViewModel.progressBar.postValue(false)
} }
@@ -107,22 +171,23 @@ class DiagnosticsFragment : Fragment() {
HemoCubeCommands.DIAGNOSTICS_COMMAND, HemoCubeCommands.DIAGNOSTICS_COMMAND,
object : UsbServiceListener { object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) { override fun onUsbRead(data: ByteArray?) {
} }
override fun onUsbError(e: Exception?) { override fun onUsbError(e: Exception?) {
diagnosticsViewModel.progressBar.postValue(false) diagnosticsViewModel.progressBar.postValue(false)
} }
}) })
} }
private fun listenToHemoCube() { private fun listenToHemoCube() {
val fullReadOutput = StringBuilder() val fullReadOutput = StringBuilder()
startListening.postValue(true) startListening.postValue(true)
try { try {
(activity as DiagnosticsActivity).mService.listenToHemoCube(object : UsbServiceListener { (activity as DiagnosticsActivity).mService.listenToHemoCube(object :
UsbServiceListener {
override fun onUsbRead(data: ByteArray?) { override fun onUsbRead(data: ByteArray?) {
data?.let { data?.let {
val stringData = String(it) val stringData = String(it)
@@ -146,16 +211,28 @@ class DiagnosticsFragment : Fragment() {
} }
if (resultData.contains("END") || fullReadOutput.contains("END")) { if (resultData.contains("END") || fullReadOutput.contains("END")) {
diagnosticsViewModel.addDiagnosticsDataToDb(DiagnosticsData( diagnosticsViewModel.addDiagnosticsDataToDb(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(), DiagnosticsData(
devicePassword = sharedPreferences.getString(Constants.DEVICE_PASSWORD_API, "").toString(), deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "")
deviceNatsToken = sharedPreferences.getString(Constants.NATS_TOKEN, "").toString(), .toString(),
accessToken = sharedPreferences.getString(Constants.ACCESS_TOKEN, "").toString(), devicePassword = sharedPreferences.getString(
deviceData = resultData, Constants.DEVICE_PASSWORD_API,
runTime = SimpleDateFormat( ""
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() ).toString(),
).format(Calendar.getInstance().time) 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()
).format(Calendar.getInstance().time)
)
)
} }
// val inputData = mutableListOf<String>() // val inputData = mutableListOf<String>()
// while (true) { // while (true) {
@@ -178,7 +255,6 @@ class DiagnosticsFragment : Fragment() {
} }
} }
fun parseData(inputData: List<String>): List<Pair<String, String>> { fun parseData(inputData: List<String>): List<Pair<String, String>> {
val pattern = Regex("([A-Z]+)\\s(\\d+)") val pattern = Regex("([A-Z]+)\\s(\\d+)")
val parsedData = mutableListOf<Pair<String, String>>() val parsedData = mutableListOf<Pair<String, String>>()

View File

@@ -3,16 +3,21 @@ package com.example.hpostesting.presentation.diagnostics
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.model.Response import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRequest
import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class DiagnosticsViewModel @Inject constructor( class DiagnosticsViewModel @Inject constructor(
private val repository: Repository private val repository: Repository,
// context: Context,
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
@@ -20,7 +25,11 @@ class DiagnosticsViewModel @Inject constructor(
val deviceData = MutableLiveData<DeviceData?>() val deviceData = MutableLiveData<DeviceData?>()
val fireBaseUpload = MutableLiveData<String>() val fireBaseUpload = MutableLiveData<String>()
val deviceDiagnosticsResponse = MutableLiveData<com.example.hpostesting.data.Result<DeviceDiagnosticsResponse>>()
// private val batteryStatus: Intent? =
// IntentFilter(Intent.ACTION_BATTERY_CHANGED).let { ifilter ->
// context.registerReceiver(null, ifilter)
// }
fun addDiagnosticsDataToDb(data: DiagnosticsData) { fun addDiagnosticsDataToDb(data: DiagnosticsData) {
viewModelScope.launch { viewModelScope.launch {
try { try {
@@ -43,4 +52,81 @@ class DiagnosticsViewModel @Inject constructor(
} }
} }
} }
fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest) = viewModelScope.launch {
deviceDiagnosticsResponse.postValue(Result.Loading())
repository.deviceDiagnostics(deviceDiagnosticsRequest).let {
deviceDiagnosticsResponse.postValue(it)
}
}
// fun getBatteryLevel(): Float? {
// val batteryPct: Float? = batteryStatus?.let { intent ->
// val level: Int =
// intent.getIntExtra(
// BatteryManager.EXTRA_LEVEL,
// -1
// )
// val scale: Int =
// intent.getIntExtra(
// BatteryManager.EXTRA_SCALE,
// -1
// )
// level * 100 / scale.toFloat()
// }
//
// return batteryPct
// }
//
// fun getBatteryTemperature(): Float? {
// val batteryTemp: Float? = batteryStatus?.let { intent ->
// val temperature = intent.getIntExtra(
// BatteryManager.EXTRA_TEMPERATURE,
// 0
// )
// temperature.toFloat() / 10
// }
//
// return batteryTemp
// }
//
// fun getBatteryVoltage(context: Context): Float {
// val batteryIntent =
// context.registerReceiver(
// null,
// IntentFilter(Intent.ACTION_BATTERY_CHANGED)
// )
// val voltage = batteryIntent?.getIntExtra(
// BatteryManager.EXTRA_VOLTAGE,
// 0
// ) ?: 0
//
// // milli-volts to volts
// return voltage.toFloat() / 1000
// }
//
//
// fun getBatteryCapacity(context: Context): Int {
// val batteryManager =
// context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
// val currentCapacity =
// batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
//
// return currentCapacity
// }
//
// fun getBatteryMaxCapacity(context: Context): Float {
// val batteryManager = context.getSystemService(Context.BATTERY_SERVICE) as BatteryManager
// val designCapacity =
// batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY)
// val currentCapacity =
// batteryManager.getIntProperty(BatteryManager.BATTERY_PROPERTY_CHARGE_COUNTER)
//
// // Calculate the estimated maximum battery capacity in mAh
// val maxCapacity = currentCapacity.toFloat() / designCapacity.toFloat() * 100
//
// return maxCapacity
// }
} }

View File

@@ -1,25 +1,10 @@
package com.example.hpostesting.presentation.hemocube package com.example.hpostesting.presentation.hemocube
import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle import android.os.Bundle
import android.os.IBinder import androidx.appcompat.app.AppCompatActivity
import android.view.Menu
import androidx.activity.viewModels
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDigitalCardBinding import `in`.sminnovations.hpostesting.databinding.ActivityDigitalCardBinding
import `in`.sminnovations.hpostesting.databinding.ActivityHemocubeBinding
class DigitalCardActivity : AppCompatActivity() { class DigitalCardActivity : AppCompatActivity() {
@@ -38,10 +23,10 @@ class DigitalCardActivity : AppCompatActivity() {
moveToNext() moveToNext()
} }
private fun moveToNext() { private fun moveToNext() {
if (supportFragmentManager.isDestroyed) return if (supportFragmentManager.isDestroyed) return
supportFragmentManager.beginTransaction().replace(binding.fghemocube.id, DigitalCardFragment()) supportFragmentManager.beginTransaction()
.replace(binding.fghemocube.id, DigitalCardFragment())
.commit() .commit()
} }
} }

View File

@@ -5,16 +5,14 @@ import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import androidx.fragment.app.Fragment
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels import androidx.fragment.app.activityViewModels
import com.example.hpostesting.data.DataHolder import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.FragmentDigitalCardBinding import `in`.sminnovations.hpostesting.databinding.FragmentDigitalCardBinding
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.Calendar import java.util.Calendar
import java.util.Date import java.util.Date
@@ -61,14 +59,16 @@ class DigitalCardFragment : Fragment() {
binding.State.text = "State: ${testDetails?.state}" binding.State.text = "State: ${testDetails?.state}"
binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}" binding.abhaid.text = "ABHA ID: ${testDetails?.abhaId}"
binding.blood.text = "Blood Group: ${testDetails?.bloodGroup}" binding.blood.text = "Blood Group: ${testDetails?.bloodGroup}"
binding.sicklecell.text = "Sickle-Cell: ${DataHolder.hemoCubeTestData?.prdClassification.toString()}" binding.sicklecell.text =
"Sickle-Cell: ${DataHolder.hemoCubeTestData?.prdClassification.toString()}"
} }
// Update the UI with the fetched details // Update the UI with the fetched details
val originalDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) val originalDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault())
val originalDate: Date? = originalDateFormat.parse(SimpleDateFormat( val originalDate: Date? = originalDateFormat.parse(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault() SimpleDateFormat(
).format(Calendar.getInstance().time)) "yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
)
// Format the parsed date to "mm date, year" // Format the parsed date to "mm date, year"
val desiredDateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault()) val desiredDateFormat = SimpleDateFormat("MMM dd, yyyy", Locale.getDefault())

View File

@@ -134,7 +134,6 @@ class HemoCubeFragment : Fragment() {
checkAndStartProcess() checkAndStartProcess()
it.visibility = View.GONE it.visibility = View.GONE
} }
} }
if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") { if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") {
@@ -149,31 +148,38 @@ class HemoCubeFragment : Fragment() {
if (result == "Success") { if (result == "Success") {
uploadedToCloud = true uploadedToCloud = true
showToast(R.string.test_upload) showToast(R.string.test_upload)
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) { if (Constants.MOLBIO_INTEGRATION) {
when (it) { hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
is Result.Success -> { when (it) {
uploadedToMolbio = true is Result.Success -> {
if (Constants.MOLBIO_INTEGRATION) { uploadedToMolbio = true
it.data.data?.get(0)?.rawData?.let { it1 -> it.data.data?.get(0)?.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag( hemoCubeViewModel.updateMolbioFlag(
it1._id it1._id
) )
} }
handleReadingFinish()
} }
handleReadingFinish()
}
is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL
it.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
handleReadingFinish()
}
else -> {} is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL
it.exception.let { message ->
Toast.makeText(
activity,
"An error occurred: $message",
Toast.LENGTH_LONG
)
.show()
}
handleReadingFinish()
}
else -> {}
}
} }
} else {
handleReadingFinish()
} }
} }
if (result == "Local") { if (result == "Local") {
@@ -356,6 +362,20 @@ class HemoCubeFragment : Fragment() {
}) })
} }
private fun loadDACValues() {
hemoCubeViewModel.progressBar.postValue(true)
(activity as HemocubeActivity).mService.sendAndListenToHemoCube(
HemoCubeCommands.LOAD_DAC_VALUES,
object : UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
}
override fun onUsbError(e: Exception?) {
hemoCubeViewModel.progressBar.postValue(false)
}
})
}
fun handleUsbData(stringData: String) { fun handleUsbData(stringData: String) {
if (stringData.contains("#")) { if (stringData.contains("#")) {
isTestOngoing = true isTestOngoing = true
@@ -368,6 +388,7 @@ class HemoCubeFragment : Fragment() {
when { when {
resultData.contains("SNE") && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> { resultData.contains("SNE") && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> {
processV2HardwareId(resultData) processV2HardwareId(resultData)
loadDACValues()
} }
(resultData.contains("SN") && !resultData.contains("SNS") && !resultData.contains("SNE") && resultData.length >= 15) && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> { (resultData.contains("SN") && !resultData.contains("SNS") && !resultData.contains("SNE") && resultData.length >= 15) && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> {
@@ -387,6 +408,12 @@ class HemoCubeFragment : Fragment() {
fetchResult() fetchResult()
} }
(resultData.contains("#RC") && this.testStatusCode < TestStatus.EPROM_ADC_RETRIEVAL_COMPLETED.code) -> {
this.testStatusCode = TestStatus.EPROM_ADC_RETRIEVAL_COMPLETED.code
hemoCubeViewModel.messages.postValue("EPROM ADC Loaded")
showStartBufferButton()
}
resultData.contains("#BS") && this.testStatusCode < TestStatus.BUFFER_STARTED.code -> { resultData.contains("#BS") && this.testStatusCode < TestStatus.BUFFER_STARTED.code -> {
hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started)) hemoCubeViewModel.messages.postValue(getString(R.string.buffer_started))
this.testStatusCode = TestStatus.BUFFER_STARTED.code this.testStatusCode = TestStatus.BUFFER_STARTED.code
@@ -411,7 +438,8 @@ class HemoCubeFragment : Fragment() {
(resultData.contains("#SC") || resultData.contains("#SC1")) && this.testStatusCode < TestStatus.SAMPLE_COMPLETED.code -> { (resultData.contains("#SC") || resultData.contains("#SC1")) && this.testStatusCode < TestStatus.SAMPLE_COMPLETED.code -> {
this.testStatusCode = TestStatus.SAMPLE_COMPLETED.code this.testStatusCode = TestStatus.SAMPLE_COMPLETED.code
hemoCubeViewModel.messages.postValue( hemoCubeViewModel.messages.postValue(
getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data)) getString(R.string.sample_completed) + "\n" + getString(R.string.gathering_data)
)
fetchResult() fetchResult()
currentResultData = "" currentResultData = ""
} }
@@ -519,7 +547,8 @@ class HemoCubeFragment : Fragment() {
led1Gain1 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! led1Gain1 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2Gain1 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! led2Gain1 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3Gain1 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! led3Gain1 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4Gain1 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! led4Gain1 =
resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
} }
sendSecondGainCommand() sendSecondGainCommand()
@@ -537,7 +566,8 @@ class HemoCubeFragment : Fragment() {
led1Gain2 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! led1Gain2 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2Gain2 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! led2Gain2 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3Gain2 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! led3Gain2 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4Gain2 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! led4Gain2 =
resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
} }
sendForthGainCommand() sendForthGainCommand()
@@ -555,7 +585,8 @@ class HemoCubeFragment : Fragment() {
led1Gain4 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! led1Gain4 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!!
led2Gain4 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! led2Gain4 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!!
led3Gain4 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! led3Gain4 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!!
led4Gain4 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! led4Gain4 =
resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!!
} }
finishReading() finishReading()
@@ -565,6 +596,7 @@ class HemoCubeFragment : Fragment() {
fun finishReading() { fun finishReading() {
repeatReadingCount += 1 repeatReadingCount += 1
isTestOngoing = false
if (readingsPerSample == 1) { if (readingsPerSample == 1) {
activity?.runOnUiThread { activity?.runOnUiThread {
@@ -633,23 +665,26 @@ class HemoCubeFragment : Fragment() {
if (!hardwareId.isNullOrBlank()) { if (!hardwareId.isNullOrBlank()) {
updateDeviceId(hardwareId) updateDeviceId(hardwareId)
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue(getString(R.string.start))
} else { } else {
hemoCubeViewModel.messages.postValue("Config error") hemoCubeViewModel.messages.postValue("Config error")
} }
if (!Constants.DEVICE_CONFIGURATION.containsKey(deviceHardwareId)) { if (!Constants.DEVICE_CONFIGURATION.containsKey(deviceHardwareId)) {
assignDefaultDevice(resultData) 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)) { 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"
} }
} }
fun showStartBufferButton() {
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue(getString(R.string.start))
}
fun extractV1HardwareId(input: String): String? { fun extractV1HardwareId(input: String): String? {
val regex = Regex("SN (\\S+)") val regex = Regex("SN (\\S+)")
val matchResult = regex.find(input) val matchResult = regex.find(input)
@@ -662,10 +697,10 @@ class HemoCubeFragment : Fragment() {
if (!hardwareId.isNullOrBlank()) { if (!hardwareId.isNullOrBlank()) {
updateDeviceId(hardwareId) updateDeviceId(hardwareId)
activity?.runOnUiThread { // activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE // binding.btnPlacebuffer.visibility = View.VISIBLE
} // }
hemoCubeViewModel.messages.postValue(getString(R.string.start)) // hemoCubeViewModel.messages.postValue(getString(R.string.start))
} else { } else {
hemoCubeViewModel.messages.postValue("Config error") hemoCubeViewModel.messages.postValue("Config error")
} }
@@ -682,10 +717,10 @@ class HemoCubeFragment : Fragment() {
fun assignDefaultDevice(configData: String) { fun assignDefaultDevice(configData: String) {
deviceHardwareId = "HCV-000-3001" deviceHardwareId = "HCV-000-3001"
testStatusCode = TestStatus.CONFIG_COMPLETED.code testStatusCode = TestStatus.CONFIG_COMPLETED.code
activity?.runOnUiThread { // activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE // binding.btnPlacebuffer.visibility = View.VISIBLE
} // }
hemoCubeViewModel.messages.postValue(getString(R.string.start)) // hemoCubeViewModel.messages.postValue(getString(R.string.start))
} }
fun extractV2HardwareId(input: String): String? { fun extractV2HardwareId(input: String): String? {
@@ -743,9 +778,9 @@ class HemoCubeFragment : Fragment() {
)?.get(0)!! )?.get(0)!!
) { ) {
// validationError = true // validationError = true
testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)" // testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)"
activity?.runOnUiThread { 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 // binding.errorMessage.visibility = View.VISIBLE
} }
} }
@@ -763,11 +798,11 @@ class HemoCubeFragment : Fragment() {
)?.get(1)!! )?.get(1)!!
) { ) {
// validationError = true // validationError = true
testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n" // testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n"
activity?.runOnUiThread { activity?.runOnUiThread {
binding.errorMessage.text = // binding.errorMessage.text =
getString(R.string.error_improper_buffer_high) getString(R.string.error_improper_buffer_high)
binding.errorMessage.visibility = View.VISIBLE // binding.errorMessage.visibility = View.VISIBLE
} }
} }
@@ -805,15 +840,15 @@ class HemoCubeFragment : Fragment() {
calculatedPredictedDenovixRatio = fittedAbs3.div(fittedAbs1) calculatedPredictedDenovixRatio = fittedAbs3.div(fittedAbs1)
val slope = (led4Average - led1Average) / (431-411) val slope = (led4Average - led1Average) / (431 - 411)
val calculatedSlopeRatio = abs(led2Average / slope) val calculatedSlopeRatio = abs(led2Average / slope)
val slopeClass = slopeRatioClassification(calculatedSlopeRatio) val slopeClass = slopeRatioClassification(calculatedSlopeRatio)
if (fittedAbs1 <= fittedAbs2) { if (fittedAbs1 <= fittedAbs2) {
// validationError = true // validationError = true
testState.allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n" // testState.allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n"
activity?.runOnUiThread { 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 // binding.errorMessage.visibility = View.VISIBLE
} }
} }
@@ -837,9 +872,9 @@ class HemoCubeFragment : Fragment() {
if (fittedAbs3 < 0.1) { if (fittedAbs3 < 0.1) {
// validationError = true // validationError = true
testState.allErrorMessages += "Error: Low Hb. Repeat test" + "\n" // testState.allErrorMessages += "Error: Low Hb. Repeat test" + "\n"
activity?.runOnUiThread { activity?.runOnUiThread {
binding.errorMessage.text = "Error: Low Hb. Repeat test" // binding.errorMessage.text = "Error: Low Hb. Repeat test"
// binding.errorMessage.visibility = View.VISIBLE // binding.errorMessage.visibility = View.VISIBLE
} }
} }
@@ -874,8 +909,14 @@ class HemoCubeFragment : Fragment() {
this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio) this.prdClassification = absorbanceBasedClassification(predictedDenovixRatio)
this.deviceRatioClass = deviceRatioClassification(deviceRatio) this.deviceRatioClass = deviceRatioClassification(deviceRatio)
this.slopeRatioClass = slopeClass this.slopeRatioClass = slopeClass
this.classificationResult = findResultWithAdditionalMethods(deviceRatio, deviceRatioClass, slopeRatio) this.classificationResult = deviceRatioClass
hemoCubeViewModel.messages.postValue("${this.classificationResult} \n Device Ratio: ${"%.3f".format(this.deviceRatio)} \n Slope Ratio: ${"%.3f".format(this.slopeRatio)}") hemoCubeViewModel.messages.postValue(
"${this.classificationResult} \n Device Ratio: ${
"%.3f".format(
this.deviceRatio
)
}"
)
if (DataHolder.hemoCubeTestData?.testType == "HB") if (DataHolder.hemoCubeTestData?.testType == "HB")
hemoCubeViewModel.messages.postValue("Hb: $calculatedHb4") hemoCubeViewModel.messages.postValue("Hb: $calculatedHb4")
this.errorMessages = testState.allErrorMessages this.errorMessages = testState.allErrorMessages
@@ -909,7 +950,11 @@ class HemoCubeFragment : Fragment() {
} }
} }
fun findResultWithAdditionalMethods(deviceRatio: Double?, deviceRatioClass: String?, slopeRatio: Double?): String { fun findResultWithAdditionalMethods(
deviceRatio: Double?,
deviceRatioClass: String?,
slopeRatio: Double?,
): String {
try { try {
// hemoCubeViewModel.messages.postValue("post classification checks") // hemoCubeViewModel.messages.postValue("post classification checks")
if (deviceRatio != null) { if (deviceRatio != null) {
@@ -928,17 +973,17 @@ class HemoCubeFragment : Fragment() {
fun deviceRatioClassification(ratio: Double?): String { fun deviceRatioClassification(ratio: Double?): String {
try { try {
if (ratio != null) { if (ratio != null) {
if (ratio in 0.001..0.23) { if (ratio in 0.016..0.22) {
// setSubtitleTextColor(R.color.green_2) // setSubtitleTextColor(R.color.green_2)
return "Normal" return "Normal"
} }
if (ratio in 0.23..0.24) if (ratio in 0.22..0.24)
return "Negative Borderline, Repeat Test" return "Negative Borderline"
if (ratio in 0.24..0.29) if (ratio in 0.24..0.32)
return "Sickle Cell Trait" 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" 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" return "Sickle Cell Disease"
} else { } else {
return "Invalid" return "Invalid"

View File

@@ -79,6 +79,7 @@ class HemoCubeViewModel @Inject constructor(
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>() val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
val deviceUpdate = MutableLiveData<Result<ResponseBody>>() val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
val downloadcertificate = MutableLiveData<Result<ResponseBody>>()
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>() val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
@@ -136,6 +137,7 @@ class HemoCubeViewModel @Inject constructor(
fun uploadResult(molbioV2ResultRequest: MolbioV2ResultRequest) = viewModelScope.launch { fun uploadResult(molbioV2ResultRequest: MolbioV2ResultRequest) = viewModelScope.launch {
resultUpload.postValue(Result.Loading()) resultUpload.postValue(Result.Loading())
Log.d("API CALL", "UPLOADED RESULT")
repository.uploadResults(molbioV2ResultRequest).let { repository.uploadResults(molbioV2ResultRequest).let {
resultUpload.postValue(it) resultUpload.postValue(it)
} }
@@ -155,6 +157,13 @@ class HemoCubeViewModel @Inject constructor(
} }
} }
fun downloadClientCertificate() = viewModelScope.launch {
downloadcertificate.postValue(Result.Loading())
repository.downloadClientCertificate().let {
downloadcertificate.postValue(it)
}
}
fun startPeriodicCheckUpdate() { fun startPeriodicCheckUpdate() {
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>( val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES
@@ -311,24 +320,26 @@ class HemoCubeViewModel @Inject constructor(
Log.i("Testdb", "Data uploaded to Firestore successfully") Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Success") fireBaseUpload.postValue("Success")
testDetails.localFlag = true testDetails.localFlag = true
uploadResult( if (Constants.MOLBIO_INTEGRATION) {
MolbioV2ResultRequest( uploadResult(
mutableListOf( MolbioV2ResultRequest(
MolbioV2Result( mutableListOf(
rawData = testDetails, MolbioV2Result(
analysisId = testDetails._id, rawData = testDetails,
analysisDate = testDetails.testTime, analysisId = testDetails._id,
analysisStatus = testDetails.classificationResult, analysisDate = testDetails.testTime,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[testDetails.deviceId].toString(), analysisStatus = testDetails.classificationResult,
interpretation = testDetails.classificationResult, thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[testDetails.deviceId].toString(),
testId = testDetails._id, interpretation = testDetails.classificationResult,
testTime = testDetails.testTime, testId = testDetails._id,
collectionTime = testDetails.testTime, testTime = testDetails.testTime,
expiryTime = testDetails.testTime, collectionTime = testDetails.testTime,
expiryTime = testDetails.testTime,
)
) )
) )
) )
) }
hemoCubeDao.insertAll(testDetails) hemoCubeDao.insertAll(testDetails)
} }

View File

@@ -61,6 +61,7 @@ open class HemocubeActivity : AppCompatActivity() {
} }
} }
private val connection = object : ServiceConnection { private val connection = object : ServiceConnection {
override fun onServiceConnected(className: ComponentName, service: IBinder) { override fun onServiceConnected(className: ComponentName, service: IBinder) {
val binder = service as UsbService.UsbServiceBinder val binder = service as UsbService.UsbServiceBinder
@@ -74,13 +75,13 @@ open class HemocubeActivity : AppCompatActivity() {
viewModel.isServiceConnected = false viewModel.isServiceConnected = false
} }
} }
override fun attachBaseContext(newBase: Context?) { override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!) val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode) LanguageManager.setLocale(newBase, languageCode)
super.attachBaseContext(newBase) super.attachBaseContext(newBase)
} }
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityHemocubeBinding.inflate(layoutInflater) binding = ActivityHemocubeBinding.inflate(layoutInflater)
@@ -124,7 +125,6 @@ open class HemocubeActivity : AppCompatActivity() {
} }
} }
@SuppressLint("MutableImplicitPendingIntent") @SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) { private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent val mPendingIntent: PendingIntent
@@ -175,7 +175,6 @@ open class HemocubeActivity : AppCompatActivity() {
} }
} }
fun onErrorReported(msg: String) { fun onErrorReported(msg: String) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show() Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
if (!isFinishing) onBackPressed() if (!isFinishing) onBackPressed()

View File

@@ -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
}
}
}

View File

@@ -0,0 +1,232 @@
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<String>()
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() {
sdkHandler = SDKHandler(requireContext())
sdkHandler!!.dcssdkSetDelegate(this)
sdkHandler!!.dcssdkSetOperationalMode(DCSSDKDefs.DCSSDK_MODE.DCSSDK_OPMODE_SNAPI)
var notifications_mask = 0
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<DCSScannerInfo>()
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() {
if (mScannerInfoList.isNotEmpty()) {
if (!mScannerInfoList[0].isActive) {
sdkHandler?.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
}
val inXML = "<inArgs><scannerID> 1 </scannerID></inArgs>"
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?) {}
}

View File

@@ -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<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
val deviceData = MutableLiveData<DeviceData?>()
val fireBaseUpload = MutableLiveData<String>()
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")
}
}
}
}

View File

@@ -14,6 +14,7 @@ import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialPort import com.hoho.android.usbserial.driver.UsbSerialPort
import com.hoho.android.usbserial.util.SerialInputOutputManager import com.hoho.android.usbserial.util.SerialInputOutputManager
import java.io.IOException import java.io.IOException
class UsbService : Service() { class UsbService : Service() {
private val binder = UsbServiceBinder() private val binder = UsbServiceBinder()
private lateinit var mPort: UsbSerialPort private lateinit var mPort: UsbSerialPort
@@ -39,10 +40,11 @@ class UsbService : Service() {
Log.d(TAG, "My Usb Connected ${mPort.driver}") Log.d(TAG, "My Usb Connected ${mPort.driver}")
val usbIoManager = SerialInputOutputManager(mPort, val usbIoManager = SerialInputOutputManager(mPort,
object : SerialInputOutputManager.Listener{ object : SerialInputOutputManager.Listener {
override fun onNewData(data: ByteArray?) { override fun onNewData(data: ByteArray?) {
listener?.onUsbRead(data) listener?.onUsbRead(data)
} }
override fun onRunError(e: Exception?) { override fun onRunError(e: Exception?) {
Log.e(TAG, "onRunError() called inside eventDrivenWrite()") Log.e(TAG, "onRunError() called inside eventDrivenWrite()")
listener?.onUsbError(e) listener?.onUsbError(e)
@@ -51,13 +53,15 @@ class UsbService : Service() {
}) })
usbIoManager.start(); usbIoManager.start();
} }
fun disconnect() { fun disconnect() {
if(isUsbConnected){ if (isUsbConnected) {
mPort.close() mPort.close()
isUsbConnected = false; isUsbConnected = false;
Log.d(TAG, "My Usb disconnected:: ${mPort.driver}") Log.d(TAG, "My Usb disconnected:: ${mPort.driver}")
} }
} }
fun eventDrivenWrite(command: TestRightCommands, listener: UsbServiceListener) { fun eventDrivenWrite(command: TestRightCommands, listener: UsbServiceListener) {
this.listener = listener this.listener = listener
try { try {

Some files were not shown because too many files have changed in this diff Show More