Compare commits

..

23 Commits

Author SHA1 Message Date
Mariya
c379d68679 errors fixed in Repository file 2024-02-15 20:49:29 +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
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
8c9903c759 changes added for bulkupload the devices 2024-02-12 16:57:56 +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
Mariya
d5b6910408 Device provision response storing 2024-02-10 17:37:07 +05:30
Mariya
89dc7f7234 Added code related to device provision fetching fromfirestore 2024-02-09 16:39:02 +05:30
Mariya
dd1144d884 Molbio Flags are updated 2024-02-08 20:48:26 +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
35 changed files with 1391 additions and 256 deletions

View File

@@ -14,13 +14,13 @@ android {
compileSdk 34
namespace 'in.sminnovations.hpostesting'
// dev - development, quality - qc, uat - User Acceptance Test, preprod - preproduction, prod - production
// dev -> development, quality -> qc, uat -> User Acceptance Testing, preprod -> preproduction, prod -> production, iocl -> iocl-iisc production
defaultConfig {
applicationId "in.sminnovations.hpostesting.quality"
applicationId "in.sminnovations.hpostesting.dev"
minSdk 21
targetSdk 34
versionCode 106
versionName "2.1.106"
versionCode 114
versionName "2.1.114"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

View File

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

View File

@@ -48,6 +48,10 @@
android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity"
android:exported="false"
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
android:name="com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity"
android:exported="false"
@@ -119,13 +123,8 @@
android:noHistory="true"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
<category android:name="android.intent.category.LAUNCHER_APP" />
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity

View File

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

View File

@@ -61,6 +61,9 @@ object Constants {
const val BLANK_EVERY_TEST = false
// jig
const val NAVIGATE_TO_TEST_JIG_DIRECTLY = false
val STATICID = listOf(
"FACTORY",
"ADMIN",
@@ -173,6 +176,7 @@ object Constants {
const val KIT_NUMBER = "KitNumber"
const val KIT_COUNT = "KitCount"
const val KIT_CAPACITY = Int.MAX_VALUE // Enforceable
const val BUFFER_VALUE_1 = "BufferValue1"
const val BUFFER_VALUE_2 = "BufferValue2"
const val BUFFER_VALUE_3 = "BufferValue3"
@@ -1659,7 +1663,6 @@ object Constants {
)
)
val COEFFICIENTS: Map<String, List<List<Double>>> = mapOf(
"HC-V1-005" to listOf(
listOf(1.5,0.0),

View File

@@ -8,7 +8,7 @@ import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], version = 24, exportSchema = false)
@Database(entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], version = 26, exportSchema = false)
@TypeConverters(Converters::class)
abstract class MyDatabase : RoomDatabase() {
abstract fun userDao(): UserDao

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

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

@@ -4,7 +4,7 @@ import com.example.hpostesting.data.model.patient.HemoCubeTestData
data class MolbioV2Result(
val age: Int? = 31,
val analysisDate: String? = "",
val analysisDate: String? = "2024-02-08 16:33:56",
val analysisId: String? = "",
val analysisStatus: String? = "",
val analysisType: String? = "HPOS",
@@ -12,11 +12,11 @@ data class MolbioV2Result(
val bloodGroup: String? = "",
val coefficients: List<Int>? = listOf(22, 22),
val collectionLocation: List<Any>? = listOf(),
val collectionTime: String? = "",
val collectionTime: String? = "2024-02-08 16:33:56",
val collector: String? = "",
val curveFitting: String? = "Linear",
val deviceName: String? = "HPOS",
val expiryTime: String? = "",
val expiryTime: String? = "2024-02-08 16:33:56",
val gender: String? = "",
val interpretation: String? = "",
val `operator`: String? = "",
@@ -30,7 +30,7 @@ data class MolbioV2Result(
val testId: String? = "",
val testResult: String? = "",
val testStatus: String? = "",
val testTime: String? = "",
val testTime: String? = "2024-02-08 16:33:56",
val testType: String? = "",
val thresholds: String? = "",
val underMedication: Boolean? = false,

View File

@@ -15,5 +15,15 @@ data class DeviceData(
@get:PropertyName("coefficients") @set:PropertyName("coefficients")
var coefficients: List<Double> = emptyList(),
@get:PropertyName("calibratedAt") @set:PropertyName("calibratedAt")
var calibratedAt: String = ""
var calibratedAt: String = "" ,
@get:PropertyName("deviceProvisionResponse") @set:PropertyName("deviceProvisionResponse")
var deviceProvisionResponse: String = "" ,
@get:PropertyName("username") @set:PropertyName("username")
var username: String = "",
@get:PropertyName("password") @set:PropertyName("password")
var password: String = "",
@get:PropertyName("natsToken") @set:PropertyName("natsToken")
var natsToken: String = "",
@get:PropertyName("natsTokenExpiry") @set:PropertyName("natsTokenExpiry")
var natsTokenExpiry: String = ""
)

View File

@@ -9,6 +9,7 @@ import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.jig.JigData
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
@@ -137,6 +138,16 @@ 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(
patientID: String, filePath: String
): Response<Boolean> {
@@ -206,7 +217,28 @@ class DatabaseRepository @Inject constructor(
return allDeviceDataList.find { it.deviceId == deviceId }
}
override suspend fun getDeviceResponse(data: DeviceData?): Response<String> {
return try {
db.collection("devices").add(data!!).await()
Response.Success(data.deviceProvisionResponse)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
override suspend fun uploadDeviceId(data: DeviceData): Response<String>? {
return try {
db.collection("devices").add(data!!).await()
Response.Success(data.deviceId)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
override fun <UserData> addTestToDatabase(testDetails: UserData): Any {
TODO("Not yet implemented")
}
}

View File

@@ -5,6 +5,7 @@ import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.diagnostics.DiagnosticsData
import com.example.hpostesting.data.model.jig.JigData
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
@@ -29,9 +30,13 @@ interface Repository {
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 getDeviceDataById(deviceId: String): DeviceData?
suspend fun getDeviceResponse(data: DeviceData?): Response<String>
suspend fun uploadDeviceId(data: DeviceData): Response<String>?
abstract fun <UserData> addTestToDatabase(testDetails: UserData): Any
// suspend fun addToDatabase(data: PatientDetails)

View File

@@ -229,7 +229,6 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
} else {
Toast.makeText(this,"Error", Toast.LENGTH_LONG).show()
}
}
private fun pullTrigger() {
@@ -271,7 +270,7 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate {
return sharedPreference.getString(Constants.KIT_NUMBER, "")
?.isNotBlank() == true && sharedPreference.getInt(
Constants.KIT_COUNT, 0
) > 0 && sharedPreference.getInt(Constants.KIT_COUNT, 0) < 35
) > 0 && sharedPreference.getInt(Constants.KIT_COUNT, 0) < Constants.KIT_CAPACITY
}
private fun isSerialValid(s: String): Boolean {

View File

@@ -149,6 +149,15 @@ class MainActivity : AppCompatActivity() {
Constants.DEVICE_TYPE_HEMOCUBE
}
device.productId == 4614 && device.vendorId == 7111 -> {
binding.cvItem1.visibility = View.VISIBLE
binding.cvItem3.visibility = View.VISIBLE
binding.cvItem2.visibility = View.GONE
binding.cvItem4.visibility = View.GONE
DataHolder.deviceType.postValue(Constants.DEVICE_TYPE_HEMOCUBE)
Constants.DEVICE_TYPE_HEMOCUBE
}
device.productId == Constants.DEVICE_PRODUCT_ID && device.vendorId == Constants.DEVICE_VENDOR_ID -> {
Log.d(
TAG,

View File

@@ -1,9 +1,10 @@
package com.example.hpostesting.presentation
import android.content.Context
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import io.nats.client.AuthHandler
import io.nats.client.Connection
@@ -12,20 +13,15 @@ import io.nats.client.NKey
import io.nats.client.Nats
import io.nats.client.Options
import io.nats.client.support.SSLUtils
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.nio.file.Paths
import java.security.GeneralSecurityException
import java.security.KeyStore
import java.security.SecureRandom
import java.security.cert.CertificateFactory
import javax.net.ssl.KeyManager
import javax.net.ssl.KeyManagerFactory
import javax.net.ssl.SSLContext
import javax.net.ssl.TrustManager
import javax.net.ssl.TrustManagerFactory
@@ -35,6 +31,7 @@ class NatsManager(datacollector: DashboardActivity) {
var nc: Connection? = null
val datacollector = datacollector
var connect = false
var sharedPreferences = datacollector.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
private fun createSSLContext(): SSLContext {
val keyStorePassword = "prime24".toCharArray() // Change as necessary
@@ -45,7 +42,8 @@ class NatsManager(datacollector: DashboardActivity) {
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 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)
@@ -71,107 +69,116 @@ class NatsManager(datacollector: DashboardActivity) {
return sslContext
}
@RequiresApi(Build.VERSION_CODES.O)
fun connect() {
Log.d(TAG, "TRY TO CONNECT")
Thread {
val seedString = "SUAJH5VMO6GDRQA6QTXCLIJMS74IWIUTU3NJVYIOTZF2LBWUPD77DA2ZEA"
Log.e("seedString",seedString)
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()
try {
val seedString = sharedPreferences.getString(Constants.NATS_TOKEN, "")
val deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "")
Log.e("seedString", seedString.toString())
Log.d("nats deviceId", deviceId.toString())
val seedBytes = seedString?.toCharArray()
val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere
val options = Options.Builder()
.server("nats://nanodgx.in:4222")
.sslContext(SSLUtils.createOpenTLSContext())
.authHandler(object : AuthHandler {
override fun getID(): CharArray? {
return try {
theNKey?.publicKey
} catch (ex: GeneralSecurityException) {
null
} catch (ex: IOException) {
null
} catch (ex: NullPointerException) {
null
}
}
override fun sign(nonce: ByteArray): ByteArray? {
return try {
theNKey?.sign(nonce)
} catch (ex: GeneralSecurityException) {
null
} catch (ex: IOException) {
null
} catch (ex: NullPointerException) {
null
}
}
override fun getJWT(): CharArray? {
return null
}
})
.build()
nc = Nats.connect(options)
Log.d(TAG, "Connected to Nats server ${options.servers.first()}")
connect = true
datacollector.setConnect(true)
if (nc?.status == Connection.Status.CONNECTED) {
Log.e("NATSCONNECTION", "NATS is successfully connected.")
Log.d("NATSCONNECTION", "NATS is successfully connected.")
val d = nc?.createDispatcher { msg: Message? ->
println("Nats dispatcher $msg")
}
nc?.subscribe("device.hpos.${deviceId}.ping")
nc?.publish(
"server.hpos.${deviceId}.ping",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
nc?.publish(
"server.hpos.${deviceId}.health",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
d?.subscribe("device.hpos.${deviceId}.ping") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
Log.d(TAG, "subscribed msg ${msg} on topic ping")
}
d?.subscribe("device.hpos.${deviceId}.update") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.${deviceId}.uploadlogs") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response + "UPLOAD")
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.${deviceId}.disable") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.${deviceId}.updatecustomer") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.${deviceId}.checkupdate") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
} else {
Log.e("NATSCONNECTION", "NATS is not connected. Current status: ${nc?.status}")
}
nc?.publish(
"server.hpos.HCV-000-3001.ping",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
nc?.publish(
"server.hpos.HCV-000-3001.health",
"ALIVE".toByteArray(StandardCharsets.UTF_8)
)
Log.d(TAG, "Published msg server.hpos.HCV-000-3001.ping on topic Testing")
val d = nc?.createDispatcher { msg: Message? ->
println("PRITIMOI SARKAR $msg")
}
d?.subscribe("device.hpos.HCV-000-3001.update") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.uploadlogs") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response + "uPLOAD")
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.disable") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.updatecustomer") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
}
d?.subscribe("device.hpos.HCV-000-3001.checkupdate") { msg ->
val response = String(msg.data, StandardCharsets.UTF_8)
datacollector.setResponse(response)
println("Message received (up to 100 times): $response")
Log.d("NATSCONNECTION", "NATS is not connected. Current status: ${nc?.status}")
}
} catch (exp: Exception) {
@@ -188,6 +195,16 @@ class NatsManager(datacollector: DashboardActivity) {
Log.d(TAG, "Published msg ${msg} on topic ${topic}")
}
fun sub(topic: String) {
val d = nc?.createDispatcher { msg: Message? ->
val response = String(msg?.data ?: ByteArray(0), StandardCharsets.UTF_8)
datacollector.onMessageReceived(topic, response)
Log.d(TAG, "Subscribed msg $msg on topic $topic")
}
d?.subscribe(topic)
}
fun close() {
nc?.close()
Log.d(TAG, "Nats connection close")

View File

@@ -3,19 +3,14 @@ package com.example.hpostesting.presentation.assurance
import android.content.Context
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import com.example.hpostesting.presentation.NatsManager
import com.example.hpostesting.presentation.dashboard.IDataCollector
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.databinding.ActivityAssuranceControlsBinding
@AndroidEntryPoint
class AssuranceControlsActivity: AppCompatActivity(), IDataCollector {
class AssuranceControlsActivity: AppCompatActivity() {
lateinit var binding: ActivityAssuranceControlsBinding
lateinit var sharedPreference: SharedPreferences
lateinit var nats: NatsManager
var responses: String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -29,21 +24,5 @@ class AssuranceControlsActivity: AppCompatActivity(), IDataCollector {
.replace(binding.fgAssuranceControls.id, AssuranceControlsFragment())
.commit()
}
// nats = NatsManager(this)
// nats.connect()
// nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
}
override fun setConnect(connect: Boolean) {
if(connect){
Log.i("NATS Connection", connect.toString())
}
}
override fun setResponse(response: String) {
responses = responses+response+"\n"
println(responses)
}
}

View File

@@ -13,6 +13,7 @@ import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Spinner
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.constant.Constants
@@ -102,9 +103,6 @@ class AssuranceControlsFragment: Fragment() {
id: Long
) {
val selectedValue: String = volumeOptions[position]
if (!selectedValue.equals("Select volume")) {
DataHolder.hemoCubeTestData!!.volume = selectedValue
}
}
override fun onNothingSelected(parent: AdapterView<*>?) {
@@ -125,13 +123,19 @@ class AssuranceControlsFragment: Fragment() {
volumeSpinner.setSelection(volumePosition)
binding.btnSubmit.setOnClickListener {
val selectedSolution = DataHolder.hemoCubeTestData!!.solution
val selectedVolume = DataHolder.hemoCubeTestData!!.volume
if (selectedSolution == "Select solution" || selectedVolume == "Select volume") {
Toast.makeText(requireContext(), "Please select both solution and volume", Toast.LENGTH_SHORT).show()
return@setOnClickListener
val selectedSolution = binding.spinnerSolutions.selectedItem.toString()
val selectedConcentration = binding.spinnerConcentration.selectedItem.toString()
// Check if any of the selections are default values
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
val currentUnixTime = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
Instant.now().epochSecond

View File

@@ -4,7 +4,9 @@ import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.util.Log
import android.view.Menu
@@ -19,9 +21,11 @@ import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.NatsManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.jig.JigActivity
import com.google.android.material.navigation.NavigationView
import com.google.firebase.appdistribution.FirebaseAppDistribution
import com.google.firebase.appdistribution.FirebaseAppDistributionException
@@ -32,15 +36,22 @@ import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import okhttp3.ResponseBody
import java.io.File
open interface IDataCollector {
interface NatsMessageCallback {
fun onMessageReceived(topic: String, message: String)
}
open interface IDataCollector: NatsMessageCallback {
fun setConnect(connect: Boolean)
fun setResponse(response: String)
}
@AndroidEntryPoint
class DashboardActivity : AppCompatActivity(), IDataCollector {
val TAG = "DashboardActivity"
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDashboardBinding
lateinit var sharedPreferences: SharedPreferences
var responses: String = ""
lateinit var nats: NatsManager
private var downloadId: Long = 0
@@ -53,15 +64,27 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
super.attachBaseContext(newBase)
}
override fun onMessageReceived(topic: String, message: String) {
// Handle incoming messages from NATS
Log.d(TAG, "Received message on topic $topic: $message")
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityDashboardBinding.inflate(layoutInflater)
sharedPreferences = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar)
nats = NatsManager(this)
nats.connect()
nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
nats.connect()
}
val deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "")
nats.sub("server.hpos.${deviceId}.ping")
nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG")
hemocubeViewModel.deviceUpdate.observe(this) { result ->
when (result) {
@@ -71,11 +94,11 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
// val apkUrl = "https://dl.dropboxusercontent.com/s/fi/1c3nn7t0co431hicl3hrt/app-debug.apk?rlkey=e4uf13ty1dpcked614vy1aaqp&dl=0"
initiateUpdate(apkUrl.toString())
Log.d("ApI", "APK URL: $apkUrl")
Toast.makeText(
this,
"APK UPLOAD ${result.data}",
Toast.LENGTH_SHORT
).show()
// Toast.makeText(
// this,
// "APK UPLOAD ${result.data}",
// Toast.LENGTH_SHORT
// ).show()
}
is Result.Error -> {
@@ -105,6 +128,11 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
if (Constants.NAVIGATE_TO_TEST_JIG_DIRECTLY) {
startActivity(Intent(this, JigActivity::class.java))
finish()
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {

View File

@@ -57,7 +57,7 @@ class GalleryFragment : Fragment() {
) {
binding.btnDeviceProvision.visibility = View.VISIBLE
} else {
binding.btnDeviceProvision.visibility = View.GONE
binding.btnDeviceProvision.visibility = View.VISIBLE
}
binding.btnDeviceProvision.setOnClickListener {

View File

@@ -19,16 +19,20 @@ import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.api.DeviceCommunicationHandler
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.molbioresult.MolbioV2Result
import com.example.hpostesting.data.model.molbioresult.MolbioV2ResultRequest
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.KitScanActivity
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
@@ -49,7 +53,7 @@ import java.io.BufferedOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.net.URL
import java.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
@@ -70,6 +74,10 @@ class HomeFragment : Fragment() {
private val homeViewModel: HemoCubeViewModel by activityViewModels()
private var isTokenAvailable = false
private var natsToken: String = ""
private var deviceId: String = ""
private lateinit var sharedPreference: SharedPreferences
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
@@ -96,7 +104,7 @@ class HomeFragment : Fragment() {
binding.labelQuickCapture.visibility = View.VISIBLE
binding.btnQuickCapture.visibility = View.VISIBLE
}
getDeviceId()
checkUnprocessedCSVData()
viewModel.allUserData.observe(viewLifecycleOwner) { userData ->
deleteIncompleteRegistrations(userData)
@@ -117,15 +125,55 @@ class HomeFragment : Fragment() {
binding.rvOrderOffline.adapter = adapter
}
}
hemoCubeViewModel.deviceData.observe(viewLifecycleOwner) { deviceData ->
val devicelist = mutableListOf<DeviceData>()
if (deviceData != null) {
devicelist.add(DeviceData(deviceData.deviceId))
}
}
viewModel.networkStatusLiveData?.observe(viewLifecycleOwner) { isConnected ->
if (isConnected) {
binding.internetAvailableCL.visibility = View.VISIBLE
binding.internetNotAvailableCL.visibility = View.GONE
loadUserData()
setSearch()
checkForLocalDBData()
checkForTokenAndUpdate()
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
userDataList.forEach { userData ->
if (!userData.molbioFlag && isTokenAvailable) {
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = "2024-02-08 16:33:56",
analysisStatus = userData.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(),
interpretation = userData.classificationResult,
testId = userData._id,
testTime = "2024-02-08 16:33:56",//userData.testTime,
collectionTime = "2024-02-08 16:33:56",//userData.testTime,
expiryTime = "2024-02-08 16:33:56"//userData.testTime,
)
)
}
if (!userData.molbioFlag && isTokenAvailable) {
userData.molbioFlag = true
hemoCubeViewModel.uploadResult(resultList)
}
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
}
}
} else {
binding.internetAvailableCL.visibility = View.GONE
binding.internetNotAvailableCL.visibility = View.VISIBLE
@@ -156,9 +204,9 @@ class HomeFragment : Fragment() {
val btnSaveLocalVisibility =
if (userData.any { it.testStatus == true }) View.VISIBLE else View.GONE
binding.btnSaveLocal.visibility = btnSaveLocalVisibility
binding.downloadCSV.visibility = btnSaveLocalVisibility
binding.btnSaveLocal.setOnClickListener {
binding.downloadCSV.setOnClickListener {
if (btnSaveLocalVisibility == View.VISIBLE) {
// Execute the action when the button is visible (testStatus is true for at least one user)
showDownloadDialog(requireContext())
@@ -172,6 +220,8 @@ class HomeFragment : Fragment() {
}
}
}
binding.btnNewKit.setOnClickListener {
with(sharedPreference.edit()) {
putString(Constants.KIT_NUMBER, "")
@@ -193,27 +243,48 @@ class HomeFragment : Fragment() {
binding.downloadCSV.setOnClickListener {
showDownloadDialog(requireContext())
}
}
private fun checkForTokenAndUpdate() {
val accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
val password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
val userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
var accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
var password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
var userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
deviceId = sharedPreference.getString(Constants.DEVICE_ID, "").toString()
Log.e("idpass", userID)
Log.e("idpass", password)
Log.e("idpass", deviceId)
if (userID.isNotEmpty() && password.isNotEmpty()) {
if (accessToken.isEmpty()) {
if (!isTokenAvailable) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
if (isTokenExpired(accessToken)) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
isTokenAvailable = true
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.startPeriodicCheckUpdate()
hemoCubeViewModel.downloadClientCertificate()
}
}
} else {
}else if (deviceId.isNotEmpty()) {
fetchDeviceCredentials()
// This code will execute after credentials have been successfully fetched and stored.
userID = sharedPreference.getString("username", "").toString()
password = sharedPreference.getString("password", "").toString()
accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
if (accessToken.isEmpty()) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
// Continue with your existing logic if the token is not empty.
isTokenAvailable = true
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.startPeriodicCheckUpdate()
}
} else {
Toast.makeText(
requireContext(),
"Contact Help and get your device provision done",
@@ -221,10 +292,6 @@ class HomeFragment : Fragment() {
).show()
}
hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
@@ -253,11 +320,11 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.uploadLogs.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
Toast.makeText(
requireContext(),
"Log uploaded ${response.data.data?.filename}",
Toast.LENGTH_SHORT
).show()
// Toast.makeText(
// requireContext(),
// "Log uploaded ${response.data.data?.filename}",
// Toast.LENGTH_SHORT
// ).show()
}
is Result.Error -> {
@@ -471,6 +538,48 @@ class HomeFragment : Fragment() {
}
}
private fun fetchDeviceCredentials() {
try {
val db = Firebase.firestore
// Ensure deviceId is not null or empty
val deviceId = sharedPreference.getString(Constants.DEVICE_ID, "").takeIf { it!!.isNotBlank() }
?: throw IllegalStateException("Device ID is missing or blank.")
val deviceRef = db.collection("devices").whereEqualTo("deviceId", deviceId)
deviceRef.get()
.addOnSuccessListener { documentSnapshot ->
if (!documentSnapshot.isEmpty) {
val deviceData = documentSnapshot.documents[0].toObject(DeviceData::class.java)
deviceData?.let { data ->
val username = data.username
val password = data.password
val natsToken = data.natsToken
// Log for debugging
Log.d("fetchDeviceCredentials", "Username: $username, Password: $password")
// Save credentials in SharedPreferences
with(sharedPreference.edit()) {
putString("username", username)
putString("password", password)
putString(Constants.NATS_TOKEN, natsToken)
apply()
}
hemoCubeViewModel.login(createLoginRequestData(username, password))
} ?: Log.e("fetchDeviceCredentials", "Failed to parse device data.")
} else {
Log.e("fetchDeviceCredentials", "Document does not exist.")
}
}
.addOnFailureListener { exception ->
Log.e("fetchDeviceCredentials", "Error fetching device data", exception)
}
} catch (e: Exception) {
Log.e("fetchDeviceCredentials", "Error in fetchDeviceCredentials", e)
}
}
private fun loadUserData() {
try {
val dateFormat = SimpleDateFormat("yyyy-MM-dd")
@@ -698,29 +807,32 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
userDataList.forEach { userData ->
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
if (!userData.molbioFlag && isTokenAvailable) {
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = userData.testTime,
analysisDate = "2024-02-08 16:33:56", //userData.reportUploadTime,
analysisStatus = userData.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(),
interpretation = userData.classificationResult,
testId = userData._id,
testTime = userData.testTime,
collectionTime = userData.testTime,
expiryTime = userData.testTime,
testTime = "2024-02-08 16:33:56",//userData.testTime,
collectionTime = "2024-02-08 16:33:56",//userData.testTime,
expiryTime = "2024-02-08 16:33:56",//userData.testTime,
)
)
}
}
if(!userData.localFlag){
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
if (!userData.molbioFlag && isTokenAvailable) {
userData.molbioFlag = true
hemoCubeViewModel.uploadResult(resultList)
}
}
if (isTokenAvailable) {
hemoCubeViewModel.uploadResult(resultList)
}
dialog.dismiss()
}
@@ -853,4 +965,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

@@ -22,8 +22,11 @@ import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.api.DeviceCommunicationHandler
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -33,7 +36,7 @@ import `in`.sminnovations.hpostesting.databinding.ActivityDeviceBinding
@Suppress("MemberVisibilityCanBePrivate")
@AndroidEntryPoint
class DeviceActivity : AppCompatActivity() {
class DeviceActivity : AppCompatActivity(), DeviceCommunicationHandler {
private lateinit var binding: ActivityDeviceBinding
private val deviceViewModel by viewModels<DeviceViewModel>()
private var myMenu: Menu? = null
@@ -177,4 +180,8 @@ class DeviceActivity : AppCompatActivity() {
deviceViewModel.isServiceConnected = false
}
}
override fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener) {
mService.sendAndListenToHemoCube(command = HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND, listener)
}
}

View File

@@ -20,6 +20,7 @@ class DeviceViewModel @Inject constructor(
val deviceData = MutableLiveData<DeviceData?>()
// val networkStatusLiveData: LiveData<Boolean>
// get() = _networkStatusLiveData
val fireBaseUpload = MutableLiveData<String>()
val fireBaseUpload = MutableLiveData<String>()
val fireBaseBulkUpload = MutableLiveData<String>()
}

View File

@@ -21,8 +21,11 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
import com.example.hpostesting.data.DataHolder
import com.example.hpostesting.data.api.DeviceCommunicationHandler
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.testRight.UsbService
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -31,7 +34,7 @@ import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityAutoDacBinding
@AndroidEntryPoint
class DeviceProvisionActivity : AppCompatActivity() {
class DeviceProvisionActivity : AppCompatActivity(), DeviceCommunicationHandler {
private lateinit var binding: ActivityAutoDacBinding
val viewModel: DeviceProvisionViewModel by viewModels()
private var myMenu: Menu? = null
@@ -180,4 +183,8 @@ class DeviceProvisionActivity : AppCompatActivity() {
viewModel.isServiceConnected = false
}
}
override fun sendAndListenToDevice(command: HemoCubeCommands, listener: UsbServiceListener) {
mService.sendAndListenToHemoCube(command = HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND, listener)
}
}

View File

@@ -11,10 +11,12 @@ import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.constant.HemoCubeCommands
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.presentation.UsbServiceListener
import com.example.hpostesting.presentation.dashboard.DashboardActivity
import com.google.firebase.crashlytics.ktx.crashlytics
@@ -22,11 +24,14 @@ import com.google.firebase.ktx.Firebase
import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding
class DeviceProvisionFragment : Fragment() {
private var resultData: String = ""
private lateinit var binding: FragmentDeviceProvisionBinding
private val viewModel: DeviceProvisionViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private lateinit var deviceProvisionResponse: String
private var currentDeviceData: DeviceData? = null
private var isOnline = false
val deviceData = MutableLiveData<DeviceData?>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
@@ -34,13 +39,11 @@ class DeviceProvisionFragment : Fragment() {
sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initViews()
observeViewModel()
}
private fun initViews() {
listenToHemoCube()
getDeviceId()
@@ -56,7 +59,11 @@ class DeviceProvisionFragment : Fragment() {
}
}
private fun observeViewModel() {
viewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
viewModel.deviceProvisionResponse.observe(viewLifecycleOwner) { response ->
when (response) {
@@ -86,14 +93,33 @@ class DeviceProvisionFragment : Fragment() {
)
apply()
}
startActivity(Intent(requireContext(), DashboardActivity::class.java))
startActivity(
Intent(
requireContext(),
DashboardActivity::class.java
)
)
Toast.makeText(
activity, "Device registered successfully", Toast.LENGTH_LONG
).show()
viewModel.addDeviceProvisionDataToDb(
DeviceData(
deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
username = response.data.data?.credentials?.username.toString(),
password = response.data.data?.credentials?.password.toString(),
deviceProvisionResponse = response.data.data.toString(),
natsToken = response.data.data?.device?.deviceUser?.natsToken.toString(),
natsTokenExpiry = response.data.data?.device?.deviceUser?.natsTokenExpiry.toString()
)
)
// viewModel.addDeviceId(DeviceData(deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()))
Log.e("idpass",response.toString())
Log.e("idpass",response.data.data?.credentials?.username.toString())
Log.e("idpass",deviceProvisionResponse)
} else {
Toast.makeText(
activity,
"An error occurred in device provision: ${response.data.message}",
"An error in device provision: ${response.data.message}",
Toast.LENGTH_LONG
).show()
binding.btnSubmit.visibility = View.VISIBLE
@@ -118,6 +144,13 @@ class DeviceProvisionFragment : Fragment() {
else -> {}
}
}
viewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
Toast.makeText(
activity, "Device provision successfully uploaded to firebase", Toast.LENGTH_LONG
).show()
}
}
}
private fun getDeviceId() {
@@ -134,7 +167,8 @@ class DeviceProvisionFragment : Fragment() {
val fullReadOutput = StringBuilder()
try {
(activity as DeviceProvisionActivity).mService.listenToHemoCube(object : UsbServiceListener {
(activity as DeviceProvisionActivity).mService.listenToHemoCube(object :
UsbServiceListener {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val stringData = String(it)

View File

@@ -4,8 +4,10 @@ import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.model.Response
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.patient.DeviceData
import com.example.hpostesting.data.repository.Repository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
@@ -13,17 +15,54 @@ import javax.inject.Inject
@HiltViewModel
class DeviceProvisionViewModel @Inject constructor(
private val databaseRepository: Repository
private val repository: Repository,
) : ViewModel() {
var isServiceConnected = false
val deviceProvisionResponse = MutableLiveData<Result<DeviceProvisionResponse>>()
val fireBaseUpload = MutableLiveData<String>()
val fireBaseBulkUpload = MutableLiveData<String>()
val deviceData = MutableLiveData<DeviceData?>()
fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
deviceProvisionResponse.postValue(Result.Loading())
databaseRepository.deviceProvision(deviceProvisionRequest).let {
repository.deviceProvision(deviceProvisionRequest).let {
deviceProvisionResponse.postValue(it)
}
}
fun addDeviceId(data: DeviceData) {
viewModelScope.launch {
try {
repository.uploadDeviceId(data)
fireBaseUpload.postValue("Successfully device Id uploaded to firebase")
} catch (e: Exception) {
// Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
fun addDeviceProvisionDataToDb(data: DeviceData) {
viewModelScope.launch {
try {
when (val response = repository.getDeviceResponse(data)) {
is Response.Success -> {
// Log.i("Testdb", "Data uploaded to Firestore successfully")
fireBaseUpload.postValue("Successfully device response uploaded to firebase")
}
is Response.Error -> {
// Log.e("Testdb", "Error uploading data to Firestore: $response")
fireBaseUpload.postValue("Error")
}
else -> {}
}
} catch (e: Exception) {
// Log.e("Testdb", "Exception during data upload: ${e.message}")
fireBaseUpload.postValue("Error")
}
}
}
}

View File

@@ -142,9 +142,6 @@ class HemoCubeViewModel @Inject constructor(
}
}
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
checkUpdate.postValue(Result.Loading())
repository.checkUpdate(checkUpdateRequest).let {
@@ -159,7 +156,6 @@ class HemoCubeViewModel @Inject constructor(
}
}
fun downloadClientCertificate() = viewModelScope.launch {
downloadcertificate.postValue(Result.Loading())
repository.downloadClientCertificate().let {
@@ -167,9 +163,6 @@ class HemoCubeViewModel @Inject constructor(
}
}
fun startPeriodicCheckUpdate() {
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES

View File

@@ -11,14 +11,12 @@ import android.content.ServiceConnection
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbManager
import android.os.Build
import android.os.Bundle
import android.os.IBinder
import android.util.Log
import android.view.Menu
import android.widget.Toast
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.get
@@ -45,7 +43,6 @@ open class HemocubeActivity : AppCompatActivity() {
private val TAG = "HemoCube"
private val broadcastReceiver = object : BroadcastReceiver() {
@RequiresApi(Build.VERSION_CODES.O)
override fun onReceive(context: Context, intent: Intent) {
synchronized(this) {
@@ -84,7 +81,6 @@ open class HemocubeActivity : AppCompatActivity() {
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHemocubeBinding.inflate(layoutInflater)
@@ -109,7 +105,6 @@ open class HemocubeActivity : AppCompatActivity() {
}
}
@RequiresApi(Build.VERSION_CODES.O)
open fun connectUsb(permissionGranted: Boolean) {
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
@@ -130,40 +125,32 @@ open class HemocubeActivity : AppCompatActivity() {
}
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("UnspecifiedImmutableFlag")
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent
val pendingIntentFlags = when {
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
PendingIntent.FLAG_IMMUTABLE
}
else -> {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
mPendingIntent = PendingIntent.getBroadcast(
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
mPendingIntent = PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HEMOCUBE_USB_PERMISSION),
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
}
)
}
mPendingIntent = PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HEMOCUBE_USB_PERMISSION),
pendingIntentFlags
)
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
registerReceiver(broadcastReceiver, filter, RECEIVER_EXPORTED)
// Request permission
registerReceiver(broadcastReceiver, filter)
manager.requestPermission(device, mPendingIntent)
}
fun setupService() {
val intent = Intent(this, UsbService::class.java)
bindService(intent, connection, Context.BIND_AUTO_CREATE)
}
@RequiresApi(Build.VERSION_CODES.O)
open fun reconnectDevice() {
mService.disconnect()
unbindService(connection)

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,241 @@
package com.example.hpostesting.presentation.jig
import android.annotation.SuppressLint
import android.content.Context
import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.os.Bundle
import android.text.Editable
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.EditText
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.MutableLiveData
import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.model.jig.JigData
import com.example.hpostesting.data.model.patient.DeviceData
import com.journeyapps.barcodescanner.ScanContract
import com.journeyapps.barcodescanner.ScanIntentResult
import com.zebra.barcode.sdk.sms.ConfigurationUpdateEvent
import com.zebra.scannercontrol.DCSSDKDefs
import com.zebra.scannercontrol.DCSScannerInfo
import com.zebra.scannercontrol.FirmwareUpdateEvent
import com.zebra.scannercontrol.IDcsSdkApiDelegate
import com.zebra.scannercontrol.SDKHandler
import `in`.sminnovations.hpostesting.databinding.FragmentJigBinding
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Locale
class JigFragment : Fragment(), IDcsSdkApiDelegate {
private lateinit var binding: FragmentJigBinding
private val jigViewModel: JigViewModel by activityViewModels()
private lateinit var sharedPreferences: SharedPreferences
private var currentDeviceData: DeviceData? = null
private var resultData: String = ""
private val messages = MutableLiveData<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() {
//Setting up the SDK handler
sdkHandler = SDKHandler(requireContext())
//Registers a particular object which conforms to IDcsSdkApiDelegate interface as a receiver of SDK notifications.
sdkHandler!!.dcssdkSetDelegate(this)
//this command is telling the sdk that we're going to be connecting to the scanner via USB
sdkHandler!!.dcssdkSetOperationalMode(DCSSDKDefs.DCSSDK_MODE.DCSSDK_OPMODE_SNAPI)
//deciding what kind of notifications we want to receive. Explained more in the function
//first we use bitmapping to set these values into the notifications_mask.
var notifications_mask = 0
// We would like to subscribe to all barcode events
notifications_mask =
notifications_mask or DCSSDKDefs.DCSSDK_EVENT.DCSSDK_EVENT_BARCODE.value
sdkHandler!!.dcssdkSubsribeForEvents(notifications_mask)
mScannerInfoList.addAll(sdkHandler!!.dcssdkGetAvailableScannersList())
Log.e("scannersize", sdkHandler!!.dcssdkGetAvailableScannersList().size.toString())
if (mScannerInfoList.isNotEmpty()) {
sdkHandler!!.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
} else {
Toast.makeText(requireContext(), "Scanner Error", Toast.LENGTH_LONG).show()
}
}
@SuppressLint("SetTextI18n")
private fun initViews() {
binding.btnScanNow.setOnClickListener {
pullTrigger()
}
binding.btnRefresh.setOnClickListener {
activity?.recreate()
initScanner()
activity?.runOnUiThread {
binding.tvScanText.text = ""
}
}
activity?.runOnUiThread {
binding.tvAppVersion.text =
getAppVersion(requireContext()) + " [ " + getAppEnvironment(requireContext()) + " ]"
}
}
private fun observeViewModel() {
jigViewModel.deviceData.observe(viewLifecycleOwner) {
currentDeviceData = it
}
messages.observe(viewLifecycleOwner) {
binding.tvScanText.text = it
}
jigViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
showToast("Data uploaded successfully")
}
if (result == "Local") {
showToast("Data uploading failed, note it down manually")
}
binding.progressBar.visibility = View.GONE
}
}
private fun getAppVersion(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.versionName
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}
}
private fun getAppEnvironment(context: Context): String {
return try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
pInfo.packageName.substringAfterLast('.')
} catch (e: PackageManager.NameNotFoundException) {
"N/A"
}
}
private fun showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
}
var sdkHandler: SDKHandler? = null
var editBarcode: EditText? = null
var mScannerInfoList = ArrayList<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() {
// Check if the list is not empty before accessing its elements
if (mScannerInfoList.isNotEmpty()) {
// Only proceed if the scanner is not active
if (!mScannerInfoList[0].isActive) {
sdkHandler?.dcssdkEstablishCommunicationSession(mScannerInfoList[0].scannerID)
}
val inXML = "<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

@@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/cl_parent"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- <androidx.appcompat.widget.Toolbar-->
<!-- android:id="@+id/my_toolbar"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="?attr/actionBarSize"-->
<!-- android:background="?attr/colorPrimary"-->
<!-- app:titleTextColor="#FFFFFF"-->
<!-- android:elevation="4dp"-->
<!-- app:menu="@menu/my_menu"-->
<!-- android:theme="@style/ToolbarTheme"-->
<!-- app:popupTheme="@style/ThemeOverlay.AppCompat.Light"-->
<!-- app:layout_constraintStart_toStartOf="parent"-->
<!-- app:layout_constraintTop_toTopOf="parent"/>-->
<FrameLayout
android:id="@+id/fg_jig"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:context=".presentation.jig.JigActivity">
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View File

@@ -77,13 +77,13 @@
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_auto_dac" />
app:layout_constraintTop_toBottomOf="@id/btn_deviceProvision" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_deviceProvision"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:visibility="visible"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
@@ -92,7 +92,7 @@
app:cornerRadius="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_deviceInfo" />
app:layout_constraintTop_toBottomOf="@id/btn_auto_dac" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_deviceInfo"

View File

@@ -115,15 +115,15 @@
tools:listitem="@layout/offline_user_list_view" />
<ImageView
android:id="@+id/btnSaveLocal"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginEnd="10dp"
android:src="@drawable/downloads"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@+id/rv_order_offline"
app:layout_constraintStart_toStartOf="parent" />
<!-- <ImageView-->
<!-- android:id="@+id/btnSaveLocal"-->
<!-- android:layout_width="30dp"-->
<!-- android:layout_height="30dp"-->
<!-- android:layout_marginEnd="10dp"-->
<!-- android:src="@drawable/downloads"-->
<!-- android:visibility="gone"-->
<!-- app:layout_constraintBottom_toBottomOf="@+id/rv_order_offline"-->
<!-- app:layout_constraintStart_toStartOf="parent" />-->
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -0,0 +1,126 @@
<?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.jig.JigFragment">
<TextView
android:id="@+id/tv_subtitle2"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="Test Jig"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_app_version"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="0.0.0"
app:layout_constraintStart_toEndOf="@id/tv_subtitle2"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_title"
style="@style/title1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:text="Scan to get the code"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<TextView
android:id="@+id/tv_subtitle3"
style="@style/title2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle2" />
<com.google.android.material.button.MaterialButton
android:id="@+id/btn_scan_now"
android:layout_width="258dp"
android:layout_height="56dp"
android:layout_margin="24dp"
android:drawableLeft="@drawable/baseline_qr_code_scanner_24"
android:text="@string/scan_now"
android:textColor="@color/black"
app:backgroundTint="@color/blue_app_light"
app:cornerRadius="100dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
<TextView
android:id="@+id/tv_scan_text"
style="@style/title1_1"
android:layout_width="0dp"
android:layout_height="150dp"
android:layout_marginHorizontal="24dp"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="no scan"
android:textColor="@color/black"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_scan_now" />
<Button
android:id="@+id/btn_refresh"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:layout_marginTop="24dp"
android:clickable="false"
android:gravity="center"
android:text="Refresh"
android:visibility="visible"
android:textColor="@color/white"
app:layout_constraintEnd_toEndOf="@id/btn_scan_now"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_scan_now" />
<ImageView
android:id="@+id/iv_check"
android:visibility="gone"
android:layout_width="100dp"
android:layout_height="100dp"
android:layout_marginTop="40dp"
android:importantForAccessibility="no"
android:src="@drawable/check"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/btn_submit" />
<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:elevation="12dp"
android:indeterminate="true"
android:indeterminateDrawable="@drawable/progressbar_drawable"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

View File

@@ -12,6 +12,12 @@
android:paddingBottom="@dimen/activity_vertical_margin"
android:theme="@style/ThemeOverlay.AppCompat.Dark">
<androidx.cardview.widget.CardView
android:id="@+id/cardView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="16dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
@@ -19,6 +25,7 @@
android:contentDescription="@string/nav_header_desc"
android:paddingTop="@dimen/nav_header_vertical_spacing"
app:srcCompat="@mipmap/hpos_icon" />
</androidx.cardview.widget.CardView>
<TextView
android:layout_width="match_parent"