Compare commits

..

3 Commits

Author SHA1 Message Date
Mariya
d82ecf624e device registering issue resolved 2024-01-27 12:55:42 +05:30
Mariya
d2d965d524 Uncomment the code for firebase 2024-01-25 11:51:17 +05:30
Mariya
5e0d333fca changes added when testing in dEVICE UPDATION 2024-01-24 12:35:34 +05:30
30 changed files with 307 additions and 1062 deletions

View File

@@ -86,16 +86,3 @@ debugTests:
stage: test stage: test
script: script:
- ./gradlew -Pci --console=plain :app:testDebug - ./gradlew -Pci --console=plain :app:testDebug
artifacts:
paths:
- app/build/test-results/
publishTestResults:
stage: test
script:
- echo "Publishing JUnit test results"
needs: [debugTests]
artifacts:
when: always
reports:
junit: app/build/test-results/testDebugUnitTest/*.xml

View File

@@ -16,11 +16,11 @@ android {
// prod - production, preprod - preproduction, quality - qc, dev - development // prod - production, preprod - preproduction, quality - qc, dev - development
defaultConfig { defaultConfig {
applicationId "in.sminnovations.hpostesting.quality" applicationId "in.sminnovations.hpostesting"
minSdk 21 minSdk 21
targetSdk 34 targetSdk 34
versionCode 98 versionCode 93
versionName "2.1.98" versionName "2.1.93"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -80,7 +80,7 @@ dependencies {
implementation 'com.google.firebase:firebase-storage-ktx' implementation 'com.google.firebase:firebase-storage-ktx'
implementation 'com.firebaseui:firebase-ui-firestore:8.0.2' implementation 'com.firebaseui:firebase-ui-firestore:8.0.2'
implementation 'com.google.android.gms:play-services-auth:20.7.0' implementation 'com.google.android.gms:play-services-auth:20.7.0'
implementation 'com.google.android.gms:play-services-location:21.1.0' implementation 'com.google.android.gms:play-services-location:21.0.1'
implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1'
implementation 'com.google.android.things:androidthings:1.0' implementation 'com.google.android.things:androidthings:1.0'
implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta11' implementation 'com.google.firebase:firebase-appdistribution:16.0.0-beta11'
@@ -95,8 +95,6 @@ dependencies {
// Testing // Testing
testImplementation 'junit:junit:4.13.2' testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
testImplementation "androidx.work:work-testing:2.9.0" testImplementation "androidx.work:work-testing:2.9.0"
androidTestImplementation 'androidx.test:core-ktx:1.5.0' androidTestImplementation 'androidx.test:core-ktx:1.5.0'
@@ -115,6 +113,7 @@ dependencies {
testImplementation "androidx.arch.core:core-testing:2.2.0" testImplementation "androidx.arch.core:core-testing:2.2.0"
testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1' testImplementation 'org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.1'
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.7.0"
implementation 'com.opencsv:opencsv:5.9' implementation 'com.opencsv:opencsv:5.9'
implementation 'com.github.mik3y:usb-serial-for-android:3.5.1' implementation 'com.github.mik3y:usb-serial-for-android:3.5.1'
@@ -161,6 +160,4 @@ dependencies {
// implementation("io.nats:jnats:2.11.2") // implementation("io.nats:jnats:2.11.2")
implementation 'com.google.android.play:core:1.10.3' implementation 'com.google.android.play:core:1.10.3'
// implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation fileTree(dir: 'C:\\Users\\Lenovo\\StudioProjects\\hpos\\app\\libs', include: ['*.aar', '*.jar'])
} }

View File

@@ -1,45 +1,205 @@
{ {
"project_info": { "project_info": {
"project_number": "1004619739289", "project_number": "650071678820",
"project_id": "hpos-qa", "project_id": "hpos-af3cc",
"storage_bucket": "hpos-qa.appspot.com" "storage_bucket": "hpos-af3cc.appspot.com"
}, },
"client": [ "client": [
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:1004619739289:android:f669b47552748433e5c808", "mobilesdk_app_id": "1:650071678820:android:f1435a1c07f710036c6471",
"android_client_info": { "android_client_info": {
"package_name": "in.sminnovations.hposregistration.quality" "package_name": "com.example.hposconsentform"
} }
}, },
"oauth_client": [], "oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs" "current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
} }
], ],
"services": { "services": {
"appinvite_service": { "appinvite_service": {
"other_platform_oauth_client": [] "other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
} }
} }
}, },
{ {
"client_info": { "client_info": {
"mobilesdk_app_id": "1:1004619739289:android:8397cd1f0357bd89e5c808", "mobilesdk_app_id": "1:650071678820:android:7865bef608cdee6f6c6471",
"android_client_info": { "android_client_info": {
"package_name": "in.sminnovations.hpostesting.quality" "package_name": "com.smi.counselling"
} }
}, },
"oauth_client": [], "oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [ "api_key": [
{ {
"current_key": "AIzaSyC4d4GhWHr_NMJAeBvnztQ_yQ3Qe9MAnLs" "current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
} }
], ],
"services": { "services": {
"appinvite_service": { "appinvite_service": {
"other_platform_oauth_client": [] "other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:2925e9ce3417d2386c6471",
"android_client_info": {
"package_name": "in.sminnovations.hemocube"
}
},
"oauth_client": [
{
"client_id": "650071678820-srhm9spm9hjn4frcd3r6o02gdhdbtd15.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hemocube",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:7569c1cad4fc99916c6471",
"android_client_info": {
"package_name": "in.sminnovations.hposregistration"
}
},
"oauth_client": [
{
"client_id": "650071678820-70kp5jvjda4r5diqch2kn4lc40p4f42g.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hposregistration",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:f96be19e5d43102b6c6471",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting"
}
},
"oauth_client": [
{
"client_id": "650071678820-l87dnr0bdj95get0khgnvfv2an1k6ogq.apps.googleusercontent.com",
"client_type": 1,
"android_info": {
"package_name": "in.sminnovations.hpostesting",
"certificate_hash": "7714b9268a81d0cf0fb178b0af8dbb630f8fc70a"
}
},
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
},
{
"client_info": {
"mobilesdk_app_id": "1:650071678820:android:a53292637abb7c0d6c6471",
"android_client_info": {
"package_name": "in.sminnovations.hpostesting.dev"
}
},
"oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyAVdNGCev_AFX0qmuZJF6kxzRzXUTeAW5I"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "650071678820-to41afi9f0gi5r3k6v7pe1e5p96nupcs.apps.googleusercontent.com",
"client_type": 3
}
]
} }
} }
} }

View File

@@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission <uses-permission
android:name="android.permission.BATTERY_STATS" android:name="android.permission.BATTERY_STATS"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
@@ -33,9 +34,6 @@
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/Theme.HPOSTesting" android:theme="@style/Theme.HPOSTesting"
tools:targetApi="31"> tools:targetApi="31">
<activity
android:name="com.example.hpostesting.presentation.KitscanJava"
android:exported="false" />
<activity <activity
android:name="com.example.hpostesting.presentation.deviceinfo.DeviceActivity" android:name="com.example.hpostesting.presentation.deviceinfo.DeviceActivity"
android:exported="false" /> android:exported="false" />
@@ -57,11 +55,13 @@
<activity <activity
android:name="com.example.hpostesting.presentation.calibration.CalibrationActivity" android:name="com.example.hpostesting.presentation.calibration.CalibrationActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" /> android:theme="@style/Theme.HPOS.NoActionBar"/>
<activity <activity
android:name="com.example.hpostesting.presentation.assurance.AssuranceControlsActivity" android:name="com.example.hpostesting.presentation.assurance.AssuranceControlsActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" /> android:theme="@style/Theme.HPOS.NoActionBar"/>
<activity <activity
android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity" android:name="com.example.hpostesting.presentation.hemocube.HemocubeActivity"
android:exported="false" android:exported="false"
@@ -87,17 +87,17 @@
android:label="@string/title_activity_dashboard" android:label="@string/title_activity_dashboard"
android:theme="@style/Theme.HPOS.NoActionBar" android:theme="@style/Theme.HPOS.NoActionBar"
tools:ignore="AppLinkUrlError,MissingClass"> tools:ignore="AppLinkUrlError,MissingClass">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" /> <data android:scheme="content" />
<data android:scheme="file" /> <data android:scheme="file" />
<data android:mimeType="application/vnd.android.package-archive" /> <data android:mimeType="application/vnd.android.package-archive" />
</intent-filter> </intent-filter>
</activity> </activity>
<service <service
android:name="com.example.hpostesting.presentation.testRight.UsbService" android:name="com.example.hpostesting.presentation.testRight.UsbService"
android:enabled="true" android:enabled="true"
@@ -158,6 +158,7 @@
android:name="android.support.FILE_PROVIDER_PATHS" android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" /> android:resource="@xml/file_paths" />
</provider> </provider>
</application> </application>
</manifest> </manifest>

View File

@@ -1,7 +1,5 @@
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
@@ -16,11 +14,6 @@ interface MolbioAuthApi {
@Body deviceProvisionRequest: DeviceProvisionRequest @Body deviceProvisionRequest: DeviceProvisionRequest
): DeviceProvisionResponse ): DeviceProvisionResponse
@POST("deviceService/device/uploadDeviceDiagnostics")
suspend fun deviceDiagnostics(
@Body deviceDiagnosticsRequest: DeviceDiagnosticsRequest
): DeviceDiagnosticsResponse
@POST("deviceService/device/login") @POST("deviceService/device/login")
suspend fun login( suspend fun login(
@Body loginRequest: LoginRequest @Body loginRequest: LoginRequest

View File

@@ -1246,7 +1246,7 @@ object Constants {
listOf(23500, 26250), listOf(23500, 26250),
listOf(23500, 26250), listOf(23500, 26250),
), ),
"HCV-000-3013" to listOf( "HCV-000-1015" to listOf(
listOf(23500, 26250), listOf(23500, 26250),
listOf(23500, 26250), listOf(23500, 26250),
listOf(23500, 26250), listOf(23500, 26250),

View File

@@ -1,36 +0,0 @@
package com.example.hpostesting.data.model
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
data class TestState (
var testDetails: HemoCubeTestData? = null,
var isOnline: Boolean = false,
var currentDeviceData: DeviceData? = null,
var resultData: String = "",
var currentResultData: String = "",
var isUsingExistingBuffer: Boolean = false,
var isTestOngoing: Boolean = false,
var led1BufferForDevice: Double = 0.0,
var led2BufferForDevice: Double = 0.0,
var led3BufferForDevice: Double = 0.0,
var led4BufferForDevice: Double = 0.0,
var led1SampleForDevice: Double = 0.0,
var led2SampleForDevice: Double = 0.0,
var led3SampleForDevice: Double = 0.0,
var led4SampleForDevice: Double = 0.0,
var fittedAbs1: Double = 0.0,
var fittedAbs2: Double = 0.0,
var fittedAbs3: Double = 0.0,
var fittedAbs4: Double = 0.0,
var calculatedPredictedDenovixRatio: Double = 0.0,
var validationError: Boolean = false,
var deviceHardwareId: String = "",
var allErrorMessages: String = "",
var testStatusCode: Double = 0.0,
var repeatReadingCount: Int = 0,
var readingsPerSample: Int = Constants.READINGS_PER_SAMPLE,
var uploadedToCloud: Boolean = false,
var uploadedToMolbio: Boolean = false
)

View File

@@ -1,15 +0,0 @@
package com.example.hpostesting.data.model.devicediagnostics
import com.google.gson.annotations.SerializedName
data class AdditionalDetails(
@SerializedName("batteryLevel") val batteryLevel: String,
@SerializedName("batteryCapacity") val batteryCapacity: String,
@SerializedName("batteryMaxCapacity") val batteryMaxCapacity: String,
@SerializedName("batteryTemperature") val batteryTemperature: String,
@SerializedName("batteryVoltage") val batteryVoltage: String
)
data class DeviceDiagnosticsRequest(
@SerializedName("additionalDetails") val additionalDetails: AdditionalDetails
)

View File

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

View File

@@ -6,8 +6,6 @@ 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
@@ -59,15 +57,10 @@ class DatabaseRepository @Inject constructor(
} }
} }
override suspend fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest): Result<DeviceProvisionResponse> { suspend fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest): Result<DeviceProvisionResponse> {
return safeApiCall { molbioAuthApi.deviceProvision(deviceProvisionRequest) } return safeApiCall { molbioAuthApi.deviceProvision(deviceProvisionRequest) }
} }
override suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse> {
return safeApiCall { molbioAuthApi.deviceDiagnostics(deviceDiagnosticsRequest) }
}
override suspend fun login(loginRequest: LoginRequest): Result<LoginResponse> { override suspend fun login(loginRequest: LoginRequest): Result<LoginResponse> {
return safeApiCall { molbioAuthApi.login(loginRequest) } return safeApiCall { molbioAuthApi.login(loginRequest) }
} }

View File

@@ -2,10 +2,6 @@ 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.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
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
@@ -37,8 +33,6 @@ interface Repository {
abstract fun <UserData> addTestToDatabase(testDetails: UserData): Any abstract fun <UserData> addTestToDatabase(testDetails: UserData): Any
// suspend fun addToDatabase(data: PatientDetails) // suspend fun addToDatabase(data: PatientDetails)
suspend fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest): Result<DeviceProvisionResponse>
suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse>
suspend fun login(loginRequest: LoginRequest): Result<LoginResponse> suspend fun login(loginRequest: LoginRequest): Result<LoginResponse>
suspend fun uploadResults(molbioV2ResultRequest: MolbioV2ResultRequest): Result<MolbioV2ResultResponse> suspend fun uploadResults(molbioV2ResultRequest: MolbioV2ResultRequest): Result<MolbioV2ResultResponse>

View File

@@ -14,7 +14,7 @@ class LogFileManagerImpl @Inject constructor(private val context: Context) : Log
val logFileName = "hpos_$unixTime.log" val logFileName = "hpos_$unixTime.log"
return try { return try {
val process = Runtime.getRuntime().exec("logcat -d -v threadtime -t 100") val process = Runtime.getRuntime().exec("logcat -d -v threadtime -t 1000")
val logBuilder = StringBuilder() val logBuilder = StringBuilder()
val input = process.inputStream val input = process.inputStream
val bufferedReader = input.bufferedReader() val bufferedReader = input.bufferedReader()

View File

@@ -1,19 +1,18 @@
package com.example.hpostesting.presentation package com.example.hpostesting.presentation
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.SharedPreferences import android.content.SharedPreferences
import android.os.AsyncTask
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.View import android.view.View
import android.widget.EditText
import android.widget.Toast import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
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
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.presentation.hemocube.HemocubeActivity import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import com.example.hpostesting.presentation.testRight.TestRightActivity import com.example.hpostesting.presentation.testRight.TestRightActivity
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
@@ -21,28 +20,16 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.journeyapps.barcodescanner.ScanContract import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult import com.journeyapps.barcodescanner.ScanIntentResult
import com.journeyapps.barcodescanner.ScanOptions import com.journeyapps.barcodescanner.ScanOptions
import com.zebra.barcode.sdk.sms.ConfigurationUpdateEvent
import com.zebra.scannercontrol.DCSSDKDefs
import com.zebra.scannercontrol.DCSSDKDefs.DCSSDK_COMMAND_OPCODE
import com.zebra.scannercontrol.DCSSDKDefs.DCSSDK_RESULT
import com.zebra.scannercontrol.DCSScannerInfo
import com.zebra.scannercontrol.FirmwareUpdateEvent
import com.zebra.scannercontrol.IDcsSdkApiDelegate
import com.zebra.scannercontrol.SDKHandler
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityKitScanBinding import `in`.sminnovations.hpostesting.databinding.ActivityKitScanBinding
import java.nio.charset.StandardCharsets
class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate { class KitScanActivity : AppCompatActivity() {
private val TAG = "KitScanActivity" private val TAG = "KitScanActivity"
private lateinit var binding: ActivityKitScanBinding private lateinit var binding: ActivityKitScanBinding
private lateinit var sharedPreference: SharedPreferences private lateinit var sharedPreference: SharedPreferences
var sdkHandler: SDKHandler? = null
var mScannerInfoList = ArrayList<DCSScannerInfo>()
private val barcodeLauncher = registerForActivityResult( private val barcodeLauncher = registerForActivityResult(
ScanContract() ScanContract()
) { result: ScanIntentResult -> ) { result: ScanIntentResult ->
@@ -64,35 +51,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
super.attachBaseContext(newBase) super.attachBaseContext(newBase)
} }
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?) {}
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
@@ -152,8 +110,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
setSupportActionBar(binding.toolbar) setSupportActionBar(binding.toolbar)
binding.btnScanNow.setOnClickListener { binding.btnScanNow.setOnClickListener {
// startScanningNow() startScanningNow()
pullTrigger()
} }
@@ -207,79 +164,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show() Toast.makeText(this, R.string.invalid_kit_number, Toast.LENGTH_LONG).show()
} }
} }
//Setting up the SDK handler
//Setting up the SDK handler
sdkHandler = SDKHandler(this)
//Registers a particular object which conforms to IDcsSdkApiDelegate interface as a receiver of SDK notifications.
//Registers a particular object which conforms to IDcsSdkApiDelegate interface as a receiver of SDK notifications.
sdkHandler!!.dcssdkSetDelegate(this)
//this command is telling the sdk that we're going to be connecting to the scanner via USB
//this command is telling the sdk that we're going to be connecting to the scanner via USB
sdkHandler!!.dcssdkSetOperationalMode(DCSSDKDefs.DCSSDK_MODE.DCSSDK_OPMODE_SNAPI)
//deciding what kind of notifications we want to receive. Explained more in the function
//first we use bitmapping to set these values into the notifications_mask.
//deciding what kind of notifications we want to receive. Explained more in the function
//first we use bitmapping to set these values into the notifications_mask.
var notifications_mask = 0
// We would like to subscribe to all barcode events
// We would like to subscribe to all barcode events
notifications_mask =
notifications_mask or DCSSDKDefs.DCSSDK_EVENT.DCSSDK_EVENT_BARCODE.value
// subscribe to events set in notification mask
// subscribe to events set in notification mask
sdkHandler!!.dcssdkSubsribeForEvents(notifications_mask)
//so adding all the scanners to the mScannerInfoList, then connecting to the first scanner.
//There's only one scanner so this step is unnecessary, I did it thinking about possible scalability.
//here I just get the list of available scanners which also returns the USB scanner attached to the tinker board.
//so adding all the scanners to the mScannerInfoList, then connecting to the first scanner.
//There's only one scanner so this step is unnecessary, I did it thinking about possible scalability.
//here I just get the list of available scanners which also returns the USB scanner attached to the tinker board.
mScannerInfoList.addAll(sdkHandler!!.dcssdkGetAvailableScannersList())
//I'm doing mScannerInfoList.get(0) because there's only one scanner which will be at position 0.
//I'm doing mScannerInfoList.get(0) because there's only one scanner which will be at position 0.
sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
}
fun pullTrigger() {
if (!mScannerInfoList[0].isActive) {
sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
}
val inXML = "<inArgs><scannerID> 1 </scannerID></inArgs>"
val outXML = StringBuilder()
val result: DCSSDK_RESULT =
sdkHandler!!.dcssdkExecuteCommandOpCodeInXMLForScanner(
DCSSDK_COMMAND_OPCODE.DCSSDK_DEVICE_PULL_TRIGGER, inXML, outXML, 1
)
if (result == DCSSDK_RESULT.DCSSDK_RESULT_SUCCESS) Log.d(
"Scanning",
"Success"
) else if (result == DCSSDK_RESULT.DCSSDK_RESULT_FAILURE) Log.d("Scanning", "Failed")
//new MyAsyncTask(1, DCSSDKDefs.DCSSDK_COMMAND_OPCODE.DCSSDK_DEVICE_PULL_TRIGGER,null).execute(inXML);
}
//this function is called if barcode is detected.
override fun dcssdkEventBarcode(barcodeData: ByteArray?, barcodeType: Int, fromScannerID: Int) {
val result = String(barcodeData!!)
Log.d("BARCODE", result)
runOnUiThread {
binding.tvTitle2.text = result
}
} }
private fun checkHemoCubeKitData(): Boolean { private fun checkHemoCubeKitData(): Boolean {

View File

@@ -24,7 +24,7 @@ class NatsManager(datacollector: DashboardActivity) {
Log.d(TAG, "TRY TO CONNECT") Log.d(TAG, "TRY TO CONNECT")
Thread { Thread {
val seedString = "SUANEUKAD7USAMUBJHFRHFMTNAAVL3PAJOIRYOXKO4SDIRAQE5HVUFW75Y" val seedString = "SUAEB5PUWNS6C2HUV3MFI6HUDEAPGPFPBHMI73NHIQATCDD2BWALVEZXZ4"
val seedBytes = seedString.toCharArray() val seedBytes = seedString.toCharArray()
val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere

View File

@@ -12,6 +12,7 @@ import android.view.ViewGroup
import android.widget.AdapterView import android.widget.AdapterView
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import android.widget.Spinner import android.widget.Spinner
import androidx.annotation.RequiresApi
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 `in`.sminnovations.hpostesting.databinding.FragmentAssuranceControlsBindi
import java.time.Instant import java.time.Instant
class AssuranceControlsFragment: Fragment() { class AssuranceControlsFragment: Fragment() {
lateinit var binding: FragmentAssuranceControlsBinding private lateinit var binding: FragmentAssuranceControlsBinding
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
override fun onCreateView( override fun onCreateView(
@@ -42,7 +43,7 @@ class AssuranceControlsFragment: Fragment() {
// binding.btnSubmit.visibility = View.GONE // binding.btnSubmit.visibility = View.GONE
val solutionSpinner: Spinner = binding.spinnerSolutions val solutionSpinner: Spinner = binding.spinnerSolutions
val solutionOptions = arrayOf("Select solution", "Tartrazine", "AR") val solutionOptions = arrayOf("Select solution", "KMnO4", "Tartrazine", "AR", "HB", "Blood")
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
@@ -64,7 +65,7 @@ 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("Select concentration", "250umol", "350umol", "450umol", "550umol", "650umol")
val concentrationAdapter = ArrayAdapter(requireContext(), R.layout.simple_spinner_item, concentrationOptions) 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

View File

@@ -1,10 +1,11 @@
package com.example.hpostesting.presentation.dashboard package com.example.hpostesting.presentation.dashboard
import android.annotation.SuppressLint
import android.app.DownloadManager 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.content.IntentFilter
import android.net.Uri import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
@@ -12,7 +13,6 @@ 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.appcompat.app.AppCompatActivity
import androidx.core.content.ContentProviderCompat.requireContext
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.findNavController import androidx.navigation.findNavController
@@ -21,12 +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.data.model.updates.CheckUpdateRequest
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.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
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
@@ -34,6 +33,7 @@ import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import okhttp3.ResponseBody import okhttp3.ResponseBody
import java.io.File import java.io.File
open interface IDataCollector { open interface IDataCollector {
@@ -48,7 +48,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
var responses: String = "" var responses: String = ""
lateinit var nats: NatsManager lateinit var nats: NatsManager
private var downloadId: Long = 0 private var downloadId: Long = 0
private lateinit var sharedPreference: SharedPreferences private var isReceiverRegistered = false
// TODO: Remove hemocube viewmodel // TODO: Remove hemocube viewmodel
private val hemocubeViewModel: HemoCubeViewModel by viewModels() private val hemocubeViewModel: HemoCubeViewModel by viewModels()
@@ -65,40 +65,39 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar) setSupportActionBar(binding.appBarDashboard.toolbar)
nats = NatsManager(this) nats = NatsManager(this)
sharedPreference =
this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
sharedPreference.getString(Constants.NATS_TOKEN, "")
nats.connect() nats.connect()
nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG") nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
sharedPreference.getString(Constants.NATS_TOKEN,"")?.let { Log.e("NATS_TOKEN", it) }
hemocubeViewModel.deviceUpdate.observe(this) { result -> hemocubeViewModel.deviceUpdate.observe(this) { result ->
when (result) { when (result) {
is Result.Success -> { is Result.Success -> {
// Handle success
val apkUrl = result.data val apkUrl = result.data
// 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 For App Update: $apkUrl")
Toast.makeText( Toast.makeText(
this, this,
"APK UPLOAD ${result.data}", "APK UPLOAD ${result.data}",
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
// The APK URL LiveData will be updated automatically
} }
is Result.Error -> { is Result.Error -> {
result.exception.let { message -> result.exception.let { message ->
Toast.makeText(this, "An error occurred On Updating App: $message", Toast.LENGTH_LONG) Toast.makeText(this, "An error occurred On Updating App: $message", Toast.LENGTH_LONG)
.show() .show()
} }
} }
is Result.Loading -> { is Result.Loading -> {
} }
else -> { else -> {
} }
} }
} }
@@ -128,13 +127,13 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
} }
@SuppressLint("UnspecifiedRegisterReceiverFlag")
private fun initiateUpdate(responseBody: String) { private fun initiateUpdate(responseBody: String) {
val apkUrl = responseBody if (!isValidHttpUrl(responseBody)) {
if (!isValidHttpUrl(apkUrl)) {
return return
} }
val request = DownloadManager.Request(Uri.parse(apkUrl)) val request = DownloadManager.Request(Uri.parse(responseBody))
request.setTitle("App Update") request.setTitle("App Update")
request.setDescription("Downloading update...") request.setDescription("Downloading update...")
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED) request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
@@ -142,10 +141,12 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadId = downloadManager.enqueue(request) downloadId = downloadManager.enqueue(request)
val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
// Register a BroadcastReceiver to receive the download complete event if (!isReceiverRegistered) {
// val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE) val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
// registerReceiver(downloadReceiver, filter) registerReceiver(downloadReceiver, filter)
isReceiverRegistered = true
}
} }
private fun extractApkUrl(responseBody: ResponseBody): String { private fun extractApkUrl(responseBody: ResponseBody): String {
return responseBody.string() return responseBody.string()
@@ -189,7 +190,10 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
// unregisterReceiver(downloadReceiver) if (isReceiverRegistered) {
unregisterReceiver(downloadReceiver)
isReceiverRegistered = false
}
} }
override fun onResume() { override fun onResume() {
@@ -242,26 +246,5 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
responses = responses+response+"\n" responses = responses+response+"\n"
println(responses) println(responses)
when {
response.contains("checkupdate", ignoreCase = true) -> {
hemocubeViewModel.checkUpdate(createCheckUpdateRequestData())
}
response.contains("uploadlogs", ignoreCase = true) -> {
hemocubeViewModel.uploadLogs()
}
response.contains("uploadresult", ignoreCase = true) -> {
}
}
}
private fun createCheckUpdateRequestData(): CheckUpdateRequest {
val pInfo = packageManager.getPackageInfo(packageName, 0)
val version = pInfo.versionName
return CheckUpdateRequest(currentVersion = version)
} }
} }

View File

@@ -200,10 +200,11 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.login(createLoginRequestData(userID, password)) hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else { } else {
isTokenAvailable = true isTokenAvailable = true
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData()) // hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
hemoCubeViewModel.deviceUpdate(createDeviceRequestData())
hemoCubeViewModel.uploadLogs() hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.startPeriodicCheckUpdate() hemoCubeViewModel.startPeriodicCheckUpdate()
} }
} }
} else { } else {
@@ -336,9 +337,10 @@ class HomeFragment : Fragment() {
) )
} }
private fun createDeviceUpdateRequestData(): DeviceUpdateRequest { private fun createDeviceRequestData(): DeviceUpdateRequest {
return DeviceUpdateRequest( return DeviceUpdateRequest(
serial_no = sharedPreference.getString(Constants.DEVICE_ID, "") serial_no = Constants.DEVICE_ID
) )
} }

View File

@@ -149,11 +149,11 @@ class DeviceProvisionFragment : Fragment() {
private fun handleUsbData() { private fun handleUsbData() {
when { when {
resultData.contains("SNE") -> { resultData.contains("SNE") -> {
val pattern = Regex("HPP1-\\d{4}") val pattern = Regex("HCV-\\d{3}-\\d{4}")
val matchResult = pattern.find(resultData) val matchResult = pattern.find(resultData)
val hardwareId = matchResult?.value val hardwareId = matchResult?.value
if (hardwareId.toString().length == 9) { if (hardwareId.toString().length == 12) {
with(sharedPreferences.edit()) { with(sharedPreferences.edit()) {
putString(Constants.DEVICE_ID, hardwareId) putString(Constants.DEVICE_ID, hardwareId)
apply() apply()

View File

@@ -1,22 +1,29 @@
package com.example.hpostesting.presentation.deviceprovision package com.example.hpostesting.presentation.deviceprovision
import android.content.Context
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.Result import com.example.hpostesting.data.Result
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.repository.Repository import com.example.hpostesting.data.repository.DatabaseRepository
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 DeviceProvisionViewModel @Inject constructor( class DeviceProvisionViewModel @Inject constructor(
private val databaseRepository: Repository private val databaseRepository: DatabaseRepository,
context: Context
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
private val _networkStatusLiveData = NetworkStatusLiveData(context)
val networkStatusLiveData: LiveData<Boolean>
get() = _networkStatusLiveData
val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>() val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>()

View File

@@ -1,10 +1,7 @@
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.BatteryManager
import android.os.Bundle import android.os.Bundle
import android.util.Log import android.util.Log
import android.view.LayoutInflater import android.view.LayoutInflater
@@ -14,11 +11,8 @@ 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.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
@@ -38,10 +32,7 @@ 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 {
@@ -65,25 +56,7 @@ 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)
)
} }
} }
@@ -108,44 +81,6 @@ class DiagnosticsFragment : Fragment() {
binding.progressBar.visibility = View.GONE binding.progressBar.visibility = View.GONE
} }
diagnosticsViewModel.deviceDiagnosticsResponse.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success-> {
val result = response.data?.result
if (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,
"Received success response but the result is not successful: ${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() {
@@ -181,7 +116,6 @@ class DiagnosticsFragment : Fragment() {
}) })
} }
private fun listenToHemoCube() { private fun listenToHemoCube() {
val fullReadOutput = StringBuilder() val fullReadOutput = StringBuilder()

View File

@@ -1,42 +1,43 @@
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.SharedPreferences
import android.content.IntentFilter import android.util.Log
import android.os.BatteryManager 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.Result import com.example.hpostesting.data.DataHolder
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.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.DeviceProvisionResponse
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.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.data.repository.DatabaseRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
class DiagnosticsViewModel @Inject constructor( class DiagnosticsViewModel @Inject constructor(
private val repository: Repository, private val hemoCubeDao: HemoCubeDao,
context: Context, private val repository: DatabaseRepository,
context: Context
) : ViewModel() { ) : ViewModel() {
var isServiceConnected = false var isServiceConnected = false
val progressBar = MutableLiveData(false) val progressBar = MutableLiveData(false)
val messages = MutableLiveData<String>() val messages = MutableLiveData<String>()
private val sharedPreference: SharedPreferences =
context.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
val deviceData = MutableLiveData<DeviceData?>() val deviceData = MutableLiveData<DeviceData?>()
val fireBaseUpload = MutableLiveData<String>() val fireBaseUpload = MutableLiveData<String>()
val deviceDiagnosticsResponse = MutableLiveData<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 {
@@ -59,81 +60,4 @@ 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

@@ -17,7 +17,6 @@ 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.constant.TestStatus import com.example.hpostesting.data.constant.TestStatus
import com.example.hpostesting.data.model.TestState
import com.example.hpostesting.data.model.patient.DeviceData import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.toHemoCubeTestData import com.example.hpostesting.data.model.patient.toHemoCubeTestData
import com.example.hpostesting.presentation.UsbServiceListener import com.example.hpostesting.presentation.UsbServiceListener
@@ -66,7 +65,6 @@ class HemoCubeFragment : Fragment() {
private var readingsPerSample = Constants.READINGS_PER_SAMPLE private var readingsPerSample = Constants.READINGS_PER_SAMPLE
private var uploadedToCloud = false private var uploadedToCloud = false
private var uploadedToMolbio = false private var uploadedToMolbio = false
lateinit var testState: TestState
override fun onCreateView( override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?, inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
@@ -74,11 +72,6 @@ class HemoCubeFragment : Fragment() {
binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false) binding = FragmentHemoCubeReferenceBinding.inflate(inflater, container, false)
sharedPreferences = sharedPreferences =
requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
testState = TestState(
testDetails = DataHolder.selectedTest?.toHemoCubeTestData(),
)
return binding.root return binding.root
} }
@@ -324,7 +317,9 @@ class HemoCubeFragment : Fragment() {
} }
private fun listenToHemoCube() { private fun listenToHemoCube() {
DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData() if (DataHolder.hemoCubeTestData == null) {
DataHolder.hemoCubeTestData = DataHolder.selectedTest?.toHemoCubeTestData()
}
hemoCubeViewModel.progressBar.postValue(true) hemoCubeViewModel.progressBar.postValue(true)
val fullReadOutput = StringBuilder() val fullReadOutput = StringBuilder()
@@ -369,7 +364,7 @@ class HemoCubeFragment : Fragment() {
}) })
} }
fun handleUsbData(stringData: String) { private fun handleUsbData(stringData: String) {
if (stringData.contains("#")) { if (stringData.contains("#")) {
isTestOngoing = true isTestOngoing = true
} }
@@ -379,12 +374,8 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.deviceMessages.postValue(currentResultData) hemoCubeViewModel.deviceMessages.postValue(currentResultData)
when { when {
resultData.contains("SNE") && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> { (resultData.contains("SNE") || resultData.contains("SN"))&& this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> {
processV2HardwareId(resultData) processHardwareId(resultData)
}
(resultData.contains("SN") && !resultData.contains("SNS") && !resultData.contains("SNE") && resultData.length >= 15) && this.testStatusCode < TestStatus.CONFIG_COMPLETED.code -> {
processV1HardwareId(resultData)
} }
resultData.contains("#BS") && this.testStatusCode < TestStatus.BUFFER_STARTED.code -> { resultData.contains("#BS") && this.testStatusCode < TestStatus.BUFFER_STARTED.code -> {
@@ -579,8 +570,8 @@ class HemoCubeFragment : Fragment() {
currentResultData = "" currentResultData = ""
} }
fun processV1HardwareId(resultData: String) { fun processHardwareId(resultData: String) {
val hardwareId = extractV1HardwareId(resultData) val hardwareId = extractMiddleString(resultData)
if (!hardwareId.isNullOrBlank()) { if (!hardwareId.isNullOrBlank()) {
updateDeviceId(hardwareId) updateDeviceId(hardwareId)
@@ -593,44 +584,15 @@ class HemoCubeFragment : Fragment() {
} }
if (!Constants.DEVICE_CONFIGURATION.containsKey(deviceHardwareId)) { if (!Constants.DEVICE_CONFIGURATION.containsKey(deviceHardwareId)) {
assignDefaultDevice(resultData) assignDefaultDevice()
testState.allErrorMessages += "Calibration configuration for this device id is not found\n" 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" allErrorMessages += "ADC thresholds for this device id are not found\n"
} }
} }
fun extractV1HardwareId(input: String): String? { fun assignDefaultDevice() {
val regex = Regex("SN (\\S+)")
val matchResult = regex.find(input)
return matchResult?.groupValues?.get(1)
}
fun processV2HardwareId(resultData: String) {
val hardwareId = extractV2HardwareId(resultData)
if (!hardwareId.isNullOrBlank()) {
updateDeviceId(hardwareId)
activity?.runOnUiThread {
binding.btnPlacebuffer.visibility = View.VISIBLE
}
hemoCubeViewModel.messages.postValue(getString(R.string.start))
} else {
hemoCubeViewModel.messages.postValue("Config error")
}
if (!Constants.DEVICE_CONFIGURATION.containsKey(deviceHardwareId)) {
assignDefaultDevice(resultData)
testState.allErrorMessages += "Calibration configuration for this device id is not found\n"
}
if (!Constants.BUFFER_INTENSITY_THRESHOLDS.containsKey(deviceHardwareId)) {
testState.allErrorMessages += "ADC thresholds for this device id are not found\n"
}
}
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 {
@@ -639,8 +601,8 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.messages.postValue(getString(R.string.start)) hemoCubeViewModel.messages.postValue(getString(R.string.start))
} }
fun extractV2HardwareId(input: String): String? { fun extractMiddleString(input: String): String? {
val pattern = Regex("SNS\\s*(.*?)\\s*SNE") val pattern = Regex("SNS\\s(.*?)\\sSNE")
val matchResult: MatchResult? = pattern.find(input) val matchResult: MatchResult? = pattern.find(input)
return matchResult?.groups?.get(1)?.value return matchResult?.groups?.get(1)?.value
@@ -679,8 +641,7 @@ class HemoCubeFragment : Fragment() {
val led2Average = log10(led2BufferForDevice.div(led2SampleForDevice)) val led2Average = log10(led2BufferForDevice.div(led2SampleForDevice))
val led3Average = log10(led3BufferForDevice.div(led3SampleForDevice)) val led3Average = log10(led3BufferForDevice.div(led3SampleForDevice))
val led4Average = log10(led4BufferForDevice.div(led4SampleForDevice)) val led4Average = log10(led4BufferForDevice.div(led4SampleForDevice))
val deviceRatio = led4Average / led1Average
val deviceRatio = led2Average / led1Average
if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0) if (led1BufferForDevice < Constants.BUFFER_INTENSITY_THRESHOLDS[deviceHardwareId]?.get(0)
?.get(0)!! ?.get(0)!!
@@ -695,7 +656,7 @@ class HemoCubeFragment : Fragment() {
)?.get(0)!! )?.get(0)!!
) { ) {
validationError = true validationError = true
testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (low)" 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
@@ -715,7 +676,7 @@ class HemoCubeFragment : Fragment() {
)?.get(1)!! )?.get(1)!!
) { ) {
validationError = true validationError = true
testState.allErrorMessages += "Error: Invalid Test. Improper buffer reading (high)" + "\n" 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)
@@ -763,7 +724,7 @@ class HemoCubeFragment : Fragment() {
if (fittedAbs1 <= fittedAbs2) { if (fittedAbs1 <= fittedAbs2) {
validationError = true validationError = true
testState.allErrorMessages += "Error: Invalid Test. Problem with de-oxygenation" + "\n" 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
@@ -788,7 +749,7 @@ class HemoCubeFragment : Fragment() {
if (fittedAbs3 < 0.1) { if (fittedAbs3 < 0.1) {
validationError = true validationError = true
testState.allErrorMessages += "Error: Low Hb. Repeat test" + "\n" 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
@@ -828,8 +789,8 @@ class HemoCubeFragment : Fragment() {
this.classificationResult = deviceRatioClass //findResult(calculatedRatio) this.classificationResult = deviceRatioClass //findResult(calculatedRatio)
hemoCubeViewModel.messages.postValue("${this.deviceRatioClass} ${if (led4Average < 0.17) " - Low Hb" else ""}\n") hemoCubeViewModel.messages.postValue("${this.deviceRatioClass} ${if (led4Average < 0.17) " - Low Hb" else ""}\n")
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 = allErrorMessages
this.resultData = deviceLog this.resultData = deviceLog
this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString() this.batteryLevel = hemoCubeViewModel.getBatteryLevel().toString()
this.batteryCapacity = this.batteryCapacity =
@@ -892,38 +853,36 @@ class HemoCubeFragment : Fragment() {
fun deviceRatioClassification(ratio: Double?): String { fun deviceRatioClassification(ratio: Double?): String {
try { try {
hemoCubeViewModel.messages.postValue("result classification")
if (ratio != null) { if (ratio != null) {
if (ratio in 0.2..0.29) { if (ratio in 0.2..0.29) {
// setSubtitleTextColor(R.color.green_2) activity?.runOnUiThread {
return "Normal" binding.tvSubtitle4.setTextColor(
ContextCompat.getColor(
requireContext(),
R.color.green_2
)
)
}
return getString(R.string.normal)
} }
if (ratio in 0.29..0.32) if (ratio in 0.29..0.32)
return "Negative Borderline, Repeat Test" return getString(R.string.negative_borderline)
if (ratio in 0.32..0.35) if (ratio in 0.32..0.35)
return "Sickle Cell Trait" return getString(R.string.sickle_cell_trait)
if (ratio in 0.35..0.38) if (ratio in 0.35..0.38)
return "Positive for Sickle Cell. HPLC for Confirmation" return getString(R.string.positive_for_sickle_cell)
if (ratio in 0.38..0.5) if (ratio in 0.38..0.5)
return "Sickle Cell Disease" return getString(R.string.sickle_cell_disease)
} else { } else {
return "Invalid" return getString(R.string.invalid)
} }
} catch (e: Exception) { } catch (e: Exception) {
handleException(e) showToast(R.string.error_classification)
return "Error" Firebase.crashlytics.recordException(e)
return getString(R.string.error)
} }
return "Invalid" return getString(R.string.invalid)
}
fun setSubtitleTextColor(colorResId: Int) {
activity?.runOnUiThread {
binding.tvSubtitle4.setTextColor(ContextCompat.getColor(requireContext(), colorResId))
}
}
fun handleException(e: Exception) {
showToast(R.string.error_classification)
Firebase.crashlytics.recordException(e)
} }
fun slopeRatioClassification(ratio: Double?): String { fun slopeRatioClassification(ratio: Double?): String {

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.hpostesting.presentation.KitscanJava">
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -62,7 +62,6 @@
<Spinner <Spinner
android:id="@+id/spinner_volume" android:id="@+id/spinner_volume"
android:layout_width="0dp" android:layout_width="0dp"
android:visibility="gone"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="52dp" android:layout_marginTop="52dp"
android:background="@drawable/spinner_border" android:background="@drawable/spinner_border"

View File

@@ -83,7 +83,7 @@
android:id="@+id/btn_deviceProvision" android:id="@+id/btn_deviceProvision"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:visibility="gone" android:visibility="visible"
android:layout_marginHorizontal="16dp" android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp" android:layout_marginTop="24dp"
android:clickable="false" android:clickable="false"

View File

@@ -101,7 +101,7 @@
<string name="normal">Normal</string> <string name="normal">Normal</string>
<string name="sickle_cell_disease">Sickle Cell Disease</string> <string name="sickle_cell_disease">Sickle Cell Disease</string>
<string name="sickle_cell_trait">Sickle Cell Trait</string> <string name="sickle_cell_trait">Sickle Cell Trait</string>
<string name="undefined">Undefined</string> <string name="undefined">Undefined\ \ </string>
<string name="sicklecell_nconfirmatory">Sicklecell\nConfirmatory</string> <string name="sicklecell_nconfirmatory">Sicklecell\nConfirmatory</string>
<string name="sicklecell_screening">Sicklecell Screening</string> <string name="sicklecell_screening">Sicklecell Screening</string>
<string name="thalassemia">Thalassemia</string> <string name="thalassemia">Thalassemia</string>

View File

@@ -1,55 +0,0 @@
package com.example.hpostesting
import android.content.SharedPreferences
import com.example.hpostesting.presentation.assurance.AssuranceControlsFragment
import junit.framework.TestCase.assertEquals
import org.junit.Before
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
class AssuranceControlsFragmentTest {
@Mock
lateinit var sharedPreferences: SharedPreferences
private lateinit var assuranceControlsFragment: AssuranceControlsFragment
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
assuranceControlsFragment = AssuranceControlsFragment()
}
// @Test
// fun testInitViews() {
// val fragmentScenario = FragmentScenario.launchInContainer(AssuranceControlsFragment::class.java)
//
// fragmentScenario.onFragment { fragment ->
// // Mock the shared preferences
// `when`(fragment.requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)).thenReturn(sharedPreferences)
//
// // Mock the solution spinner selection
// fragment.binding.spinnerSolutions.setSelection(1)
//
// // Verify that DataHolder.hemoCubeTestData!!.solution is set correctly
// assertEquals("KMnO4", DataHolder.hemoCubeTestData!!.solution)
//
// // You can similarly test other parts of initViews() based on your requirements
// }
// }
@Test
fun testGetPositionOfValue() {
val fragment = AssuranceControlsFragment()
val testData = listOf("Select solution", "KMnO4", "Tartrazine", "AR", "HB", "Blood")
// Test a value that exists in the list
val positionKMnO4 = fragment.getPositionOfValue("KMnO4", testData)
assertEquals(1, positionKMnO4)
// Test a value that does not exist in the list
val positionNonExistent = fragment.getPositionOfValue("NonExistent", testData)
assertEquals(0, positionNonExistent)
}
}

View File

@@ -1,83 +0,0 @@
package com.example.hpostesting
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionViewModel
import com.example.hpostesting.util.TestCoroutineRule
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.test.runBlockingTest
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.MockitoAnnotations
@ExperimentalCoroutinesApi
class DeviceProvisionViewModelTest {
// Rule to make LiveData updates instant
@get:Rule
val instantExecutorRule = InstantTaskExecutorRule()
// Rule for testing coroutines
@get:Rule
val coroutineRule = TestCoroutineRule()
// Mocks
@Mock
private lateinit var databaseRepository: Repository
@Mock
private lateinit var deviceProvisionObserver: Observer<Result<DeviceProvisionResponse>>
// Class under test
private lateinit var viewModel: DeviceProvisionViewModel
@Before
fun setUp() {
MockitoAnnotations.openMocks(this)
viewModel = DeviceProvisionViewModel(databaseRepository)
viewModel.deviceProvisionResponse.observeForever(deviceProvisionObserver)
}
@After
fun tearDown() {
viewModel.deviceProvisionResponse.removeObserver(deviceProvisionObserver)
}
@Test
fun `deviceProvision success`() = coroutineRule.runBlockingTest {
// Arrange
val deviceProvisionRequest = DeviceProvisionRequest(/* provide necessary parameters */)
val expectedResult = Result.Success(DeviceProvisionResponse(/* provide necessary response data */))
Mockito.`when`(databaseRepository.deviceProvision(deviceProvisionRequest)).thenReturn(expectedResult)
// Act
viewModel.deviceProvision(deviceProvisionRequest)
// Assert
// Mockito.verify(deviceProvisionObserver, Mockito.timeout(1000)).onChanged(Result.Loading())
Mockito.verify(deviceProvisionObserver, Mockito.timeout(1000)).onChanged(expectedResult)
}
@Test
fun `deviceProvision error`() = coroutineRule.runBlockingTest {
// Arrange
val deviceProvisionRequest = DeviceProvisionRequest(/* provide necessary parameters */)
val expectedError = Result.Error(Exception("Test error"))
Mockito.`when`(databaseRepository.deviceProvision(deviceProvisionRequest)).thenReturn(expectedError)
// Act
viewModel.deviceProvision(deviceProvisionRequest)
// Assert
// Mockito.verify(deviceProvisionObserver, Mockito.timeout(1000)).onChanged(Result.Loading())
Mockito.verify(deviceProvisionObserver, Mockito.timeout(1000)).onChanged(expectedError)
}
}

View File

@@ -1,86 +0,0 @@
package com.example.hpostesting
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.lifecycle.Observer
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.repository.Repository
import com.example.hpostesting.presentation.diagnostics.DiagnosticsViewModel
import io.mockk.coEvery
import io.mockk.mockk
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.TestCoroutineDispatcher
import kotlinx.coroutines.test.TestCoroutineScope
import kotlinx.coroutines.test.runBlockingTest
import kotlinx.coroutines.test.setMain
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.mockito.Mock
import org.mockito.MockitoAnnotations
@ExperimentalCoroutinesApi
class DiagnosticsViewModelTest {
// Use this rule to swap the background executor used by the Architecture Components
@get:Rule
var instantTaskExecutorRule = InstantTaskExecutorRule()
// Use this dispatcher to control execution of coroutines in tests
private val testDispatcher = TestCoroutineDispatcher()
// Use this scope to control the execution of coroutines in tests
private val testCoroutineScope = TestCoroutineScope(testDispatcher)
// Mock Repository
private val mockRepository = mockk<Repository>()
// Mock Observer for LiveData
@Mock
private lateinit var mockObserver: Observer<String>
// Subject under test
private lateinit var diagnosticsViewModel: DiagnosticsViewModel
@Before
fun setup() {
// Initialize mocks
MockitoAnnotations.openMocks(this)
// Create the ViewModel with the mock repository and set the coroutine dispatcher
diagnosticsViewModel = DiagnosticsViewModel(repository = mockRepository)
// diagnosticsViewModel.viewModelScope = testCoroutineScope
// Observe the LiveData
// diagnosticsViewModel.fireBaseUpload.observeForever(mockObserver)
Dispatchers.setMain(TestCoroutineDispatcher())
}
@Test
fun `test addDiagnosticsDataToDb success`() = runBlocking {
// Given
val diagnosticsData = mockk<DiagnosticsData>()
coEvery { mockRepository.addDiagnostics(diagnosticsData) } returns Response.Success("Success")
// When
diagnosticsViewModel.addDiagnosticsDataToDb(diagnosticsData)
// Then
assert(diagnosticsViewModel.fireBaseUpload.value == "Success")
}
@Test
fun `addDiagnosticsDataToDb error`() = testCoroutineScope.runBlockingTest {
// Given
coEvery { mockRepository.addDiagnostics(any()) } returns Response.Error(Exception("Test error"))
// When
diagnosticsViewModel.addDiagnosticsDataToDb(mockk())
// Then
assert(diagnosticsViewModel.fireBaseUpload.value == "Error")
}
}

View File

@@ -1,13 +1,10 @@
package com.example.hpostesting package com.example.hpostesting
import android.content.Context
import android.content.SharedPreferences import android.content.SharedPreferences
import com.example.hpostesting.presentation.hemocube.HemoCubeFragment import com.example.hpostesting.presentation.hemocube.HemoCubeFragment
import com.example.hpostesting.presentation.hemocube.HemocubeActivity import com.example.hpostesting.presentation.hemocube.HemocubeActivity
import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding
import junit.framework.TestCase import junit.framework.TestCase
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertNull
import org.junit.Before import org.junit.Before
import org.junit.Test import org.junit.Test
import org.mockito.ArgumentMatchers import org.mockito.ArgumentMatchers
@@ -17,9 +14,6 @@ import org.mockito.MockitoAnnotations
class HemoCubeFragmentTest { class HemoCubeFragmentTest {
@Mock
lateinit var mockContext: Context
@Mock @Mock
private lateinit var mockSharedPreferences: SharedPreferences private lateinit var mockSharedPreferences: SharedPreferences
@@ -38,7 +32,7 @@ class HemoCubeFragmentTest {
} }
@Test @Test
fun `extractV2HardwareId to get device id`() { fun `extractMiddleString to get device id`() {
// Arrange // Arrange
Mockito.`when`( Mockito.`when`(
mockSharedPreferences.getString( mockSharedPreferences.getString(
@@ -48,7 +42,7 @@ class HemoCubeFragmentTest {
).thenReturn("dummy_value") ).thenReturn("dummy_value")
// Act // Act
val deviceId = hemoCubeFragment.extractV2HardwareId("SNS HPP1-9000 SNE") val deviceId = hemoCubeFragment.extractMiddleString("SNS HPP1-9000 SNE")
// Assert // Assert
TestCase.assertEquals("HPP1-9000", deviceId) TestCase.assertEquals("HPP1-9000", deviceId)
@@ -87,274 +81,4 @@ class HemoCubeFragmentTest {
TestCase.assertEquals(true, result) TestCase.assertEquals(true, result)
TestCase.assertEquals(hemoCubeFragment.allReadingsComplete(0, 1), false) TestCase.assertEquals(hemoCubeFragment.allReadingsComplete(0, 1), false)
} }
@Test
fun `extractV1HardwareId should return hardware ID when input contains SN`() {
// Arrange
val input = "Some text SN ABC123 some more text"
// Act
val result = hemoCubeFragment.extractV1HardwareId(input)
// Assert
assertEquals("ABC123", result)
}
@Test
fun `extractV1HardwareId should return null when input does not contain SN`() {
// Arrange
val input = "Some text without SN"
// Act
val result = hemoCubeFragment.extractV1HardwareId(input)
// Assert
assertNull(result)
}
@Test
fun `extractV1HardwareId should return null when input is empty`() {
// Arrange
val input = ""
// Act
val result = hemoCubeFragment.extractV1HardwareId(input)
// Assert
assertNull(result)
}
@Test
fun `extractV1HardwareId should return null when input is null`() {
// Arrange
val input: String? = null
// Act
val result = input?.let { hemoCubeFragment.extractV1HardwareId(it) }
// Assert
assertNull(result)
}
@Test
fun `extractV1HardwareId should return hardware ID when input contains SN in a specific format`() {
// Arrange
val input = """
SN HCV-000-3001
#BS
#BC
#SS
#SC
RESULT
LB1 20636.32
LB2 15855.67
LB3 21801.36
LB4 18362.33
LS1 17287
LS2 14855.67
LS3 15282.31
LS4 9737.98
REND
""".trimIndent()
// Act
val result = hemoCubeFragment.extractV1HardwareId(input)
// Assert
assertEquals("HCV-000-3001", result)
}
@Test
fun `extractV2HardwareId should return the correct hardware ID when it exists in the input`() {
// Arrange
val input = "SNS ABC123 SNE"
// Act
val result = hemoCubeFragment.extractV2HardwareId(input)
// Assert
assertEquals("ABC123", result)
}
@Test
fun `extractV2HardwareId should return null when no hardware ID is found in the input`() {
// Arrange
val input = "No hardware ID in this input"
// Act
val result = hemoCubeFragment.extractV2HardwareId(input)
// Assert
assertNull(result)
}
@Test
fun `extractV2HardwareId should handle whitespace around the hardware ID`() {
// Arrange
val input = "SNS XYZ789 SNE"
// Act
val result = hemoCubeFragment.extractV2HardwareId(input)
// Assert
assertEquals("XYZ789", result)
}
@Test
fun `extractV2HardwareId should handle provided input string with HCV-000-3013`() {
// Arrange
val input = "SNS HCV-000-3013 SNE\n" +
"#SS1\n" +
"#SC1\n" +
"RESULT \n" +
"LB1 23411.00\n" +
"LB2 21417.00\n" +
"LB3 23869.00\n" +
"LB4 24967.00\n" +
"LS1 3401.00\n" +
"LS2 1107.00\n" +
"LS3 14410.00\n" +
"LS4 15047.00\n" +
"REND\n"
// Act
val result = hemoCubeFragment.extractV2HardwareId(input)
// Assert
assertEquals("HCV-000-3013", result)
}
@Test
fun `extractV2HardwareId should handle provided input string with HPP1-4001`() {
// Arrange
val input = "SNS HPP1-4001 SNE#SS1\n" +
"#SC1\n" +
"RESULT\n" +
"LB1 23777\n" +
"LB2 24130\n" +
"LB3 23442\n" +
"LB4 23945\n" +
"LS1 2521\n" +
"LS2 973\n" +
"LS3 10252\n" +
"LS4 11017\n" +
"REND\n"
// Act
val result = hemoCubeFragment.extractV2HardwareId(input)
// Assert
assertEquals("HPP1-4001", result)
}
@Test
fun `extractV2HardwareId should handle provided input string with HPP1-000-4001`() {
// Arrange
val input = "SNS HPP1-000-4001 SNE#SS1\n" +
"#SC1\n" +
"RESULT\n" +
"LB1 23777\n" +
"LB2 24130\n" +
"LB3 23442\n" +
"LB4 23945\n" +
"LS1 2521\n" +
"LS2 973\n" +
"LS3 10252\n" +
"LS4 11017\n" +
"REND\n"
// Act
val result = hemoCubeFragment.extractV2HardwareId(input)
// Assert
assertEquals("HPP1-000-4001", result)
}
@Test
fun `extractV2HardwareId should handle provided input string with HPP-000-4001`() {
// Arrange
val input = "SNS HPP-000-4001 SNE#SS1\n" +
"#SC1\n" +
"RESULT\n" +
"LB1 23777\n" +
"LB2 24130\n" +
"LB3 23442\n" +
"LB4 23945\n" +
"LS1 2521\n" +
"LS2 973\n" +
"LS3 10252\n" +
"LS4 11017\n" +
"REND\n"
// Act
val result = hemoCubeFragment.extractV2HardwareId(input)
// Assert
assertEquals("HPP-000-4001", result)
}
@Test
fun `extractV2HardwareId should handle provided input string with HPP-000-5001`() {
// Arrange
val input = "SNS HPP-000-5001 SNE#SS1\n" +
"#SC1\n" +
"RESULT\n" +
"LB1 23777\n" +
"LB2 24130\n" +
"LB3 23442\n" +
"LB4 23945\n" +
"LS1 2521\n" +
"LS2 973\n" +
"LS3 10252\n" +
"LS4 11017\n" +
"REND\n"
// Act
val result = hemoCubeFragment.extractV2HardwareId(input)
// Assert
assertEquals("HPP-000-5001", result)
}
@Test
fun testDeviceRatioClassificationNormal() {
val ratio = 0.25
val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Normal", result)
}
@Test
fun testDeviceRatioClassificationNegativeBorderline() {
val ratio = 0.31
val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Negative Borderline, Repeat Test", result)
}
@Test
fun testDeviceRatioClassificationSickleCellTrait() {
val ratio = 0.34
val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Sickle Cell Trait", result)
}
@Test
fun testDeviceRatioClassificationPositiveForSickleCell() {
val ratio = 0.37
val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Positive for Sickle Cell. HPLC for Confirmation", result)
}
@Test
fun testDeviceRatioClassificationSickleCellDisease() {
val ratio = 0.45
val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Sickle Cell Disease", result)
}
@Test
fun testDeviceRatioClassificationInvalid() {
val ratio: Double? = null
val result = hemoCubeFragment.deviceRatioClassification(ratio)
assertEquals("Invalid", result)
}
} }