Compare commits

...

19 Commits

Author SHA1 Message Date
sanjay
1a31d26bc1 Merge branch 'dev-check-apk-update' of https://gitlab.com/sminnovations/hpos into dev-check-apk-update 2024-03-06 11:30:30 +05:30
sanjay
3199caae5c changed gradle value 2024-03-06 11:28:51 +05:30
Mariya Varghese
a52538e72d Merge branch 'dev' into 'dev-check-apk-update'
# Conflicts:
#   app/build.gradle
#   app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt
#   app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt
#   app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt
#   build.gradle
#   gradle/wrapper/gradle-wrapper.properties
2024-03-04 11:11:13 +00:00
chandrashekhar reddy
78cc79eef8 changes in HomeFragment added deviceId global and added default values 2024-03-04 15:37:32 +05:30
Mariya
c9d0c440e3 added code for sanitize result upload values if if the result is NAN or infinity for molbio integration 2024-03-04 14:48:43 +05:30
chandrashekhar reddy
99da2fc094 error in HomeFragment and DashboardActivity solved registering broadcast receiver was giving issue solved by adding checks 2024-03-04 14:26:44 +05:30
Mariya
20f408230e api calls managing, and error resolving for molbio 2024-03-02 19:37:24 +05:30
Mariya
c8d5d41c81 api calls maintaining for molbio 2024-03-02 15:41:17 +05:30
Mariya
210c9fed5d added code for usb permission 2024-03-01 16:21:27 +05:30
Mariya
b68ec45642 reduced number of api calls in home screen 2024-03-01 13:37:16 +05:30
Mariya
1e5afa0a5c reduced number api calls for bigtec 2024-03-01 12:38:19 +05:30
Mariya
80ab69c772 added code for uploading logs only once 2024-02-29 14:18:09 +05:30
Mariya
f7dc879c75 added code related offline bulkupload 2024-02-28 15:17:36 +05:30
Mariya
e8b5d12db5 removed unwanted toast messages 2024-02-28 15:12:21 +05:30
Mariya
626dd380ab Apk update successfully added 2024-02-28 14:46:06 +05:30
Mariya
70b0b93f57 Apk Update Code Added 2024-02-27 20:44:32 +05:30
Mariya
5cdc156f33 Apk Update Code Added 2024-02-27 16:49:25 +05:30
Mariya
71d298cd69 Apk Update Code Added 2024-02-27 14:59:03 +05:30
Mariya
bb6f4ee859 Apk Update Code Added 2024-02-27 12:43:14 +05:30
14 changed files with 367 additions and 245 deletions

View File

@@ -25,6 +25,7 @@
<application
android:name="com.example.hpostesting.HPOSTestingApplication"
android:largeHeap="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"

View File

@@ -8,7 +8,7 @@ object Constants {
const val DOCUMENT_ID_FOR_UPDATE ="2o71vBKLqdgEKYtFG8Lb"
const val ABHA_APP_PACKAGE = "in.ndhm.phr"
const val MOLBIO_INTEGRATION = false
const val MOLBIO_INTEGRATION = true
const val deviceProvisionEmail = "HPOS_provisioner@bigtec.co.in"
const val deviceProvisionPassword = "f2ab0e7f9d69"
const val DEVICE_ID_API = "deviceIDAPI"

View File

@@ -10,7 +10,7 @@ import com.example.hpostesting.data.model.patient.UserData
@Database(
entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class],
version = 27,
version = 28,
exportSchema = false
)
@TypeConverters(Converters::class)

View File

@@ -109,20 +109,7 @@ class DatabaseRepository @Inject constructor(
}
override suspend fun addTestToDatabase(data: UserData?): Response<String> {
return try {
val userdata =
db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true)
}
}
db.collection("testData").add(data).await()
Response.Success(data._id)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
TODO("Not yet implemented")
}
override suspend fun addTestToDatabaseforBufferCheck(data: BufferCheckData?): Response<String> {
@@ -247,4 +234,22 @@ class DatabaseRepository @Inject constructor(
override fun <UserData> addTestToDatabase(testDetails: UserData): Any {
TODO("Not yet implemented")
}
override suspend fun addTestToDatabasefornew(data: HemoCubeTestData?): Response<String> {
return try {
val userdata =
db.collection("patientData").whereEqualTo("_id", data!!._id).get().await()
if (userdata.documents.isNotEmpty()) {
userdata.documents.forEach {
db.collection("patientData").document(it.id).update("testStatus", true)
}
}
db.collection("testData").add(data).await()
Response.Success(data._id)
} catch (e: Exception) {
Firebase.crashlytics.recordException(e)
Response.Error(e)
}
}
}

View File

@@ -25,6 +25,7 @@ import okhttp3.ResponseBody
interface Repository {
suspend fun addTestToDatabase(data: HemoCubeTestData?): Response<String>
suspend fun addTestToDatabasefornew(data: HemoCubeTestData?): Response<String>
suspend fun addTestToDatabase(data: UserData?): Response<String>

View File

@@ -1,7 +1,6 @@
package com.example.hpostesting.presentation.dashboard
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
@@ -24,7 +23,7 @@ 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.data.model.patient.DeviceData
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.NatsManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.example.hpostesting.presentation.jig.JigActivity
@@ -35,10 +34,16 @@ import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import dagger.hilt.android.AndroidEntryPoint
import `in`.sminnovations.hpostesting.BuildConfig
import `in`.sminnovations.hpostesting.R
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import okhttp3.ResponseBody
import java.io.BufferedInputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStream
import java.util.zip.ZipInputStream
interface NatsMessageCallback {
fun onMessageReceived(topic: String, message: String)
@@ -53,6 +58,7 @@ open interface IDataCollector: NatsMessageCallback {
class DashboardActivity : AppCompatActivity(), IDataCollector {
val TAG = "DashboardActivity"
private var isRegistered = false
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDashboardBinding
lateinit var sharedPreferences: SharedPreferences
@@ -61,7 +67,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
private var downloadId: Long = 0
// TODO: Remove hemocube viewmodel
private val hemocubeViewModel: HemoCubeViewModel by viewModels()
private lateinit var sharedPreference: SharedPreferences
override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode)
@@ -74,6 +80,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
Log.d(TAG, "Received message on topic $topic: $message")
}
@SuppressLint("SetWorldReadable")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -95,15 +102,22 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
when (result) {
is Result.Success -> {
// Handle success
val apkUrl = result.data
// 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()
val apk = result.data
val file = File(getExternalFilesDir("Updates"), "update.apk")
file.setReadable(true, false) // Ensure the file is readable
apk.byteStream().use { input ->
file.outputStream().use { output ->
input.copyTo(output)
}
}
Log.d("Responsebodyformat", "Responsebodyformat: ")
installApk(file)
Log.e("ApI", "APK URL: $apk")
Toast.makeText(
this,
"${result.data}",
Toast.LENGTH_SHORT
).show()
}
is Result.Error -> {
@@ -153,52 +167,15 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
private fun initiateUpdate(url: String) {
val apkUrl = url
if (!isValidHttpUrl(apkUrl)) {
return
}
val request = DownloadManager.Request(Uri.parse(apkUrl))
request.setTitle("App Update")
request.setDescription("Downloading update...")
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setDestinationInExternalFilesDir(this, "Updates", "update.apk")
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadId = downloadManager.enqueue(request)
// Register a BroadcastReceiver to receive the download complete event
val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
registerReceiver(downloadReceiver, filter)
}
private fun extractApkUrl(responseBody: ResponseBody): String {
return responseBody.string()
}
private fun isValidHttpUrl(url: String): Boolean {
return url.startsWith("http://") || url.startsWith("https://")
}
private val downloadReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (id == downloadId) {
installApk()
}
}
}
private fun installApk() {
val file = File(getExternalFilesDir("Updates"), "update.apk")
file.setReadable(true, false) // Ensure the file is readable
private fun installApk(file: File) {
val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
val uri: Uri = FileProvider.getUriForFile(
this,
"in.sminnovations.hpostesting.dev.fileprovider",
"${BuildConfig.APPLICATION_ID}.fileprovider",
file
)
// Create an intent to install the APK
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
installIntent.data = uri
installIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
@@ -214,8 +191,14 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
}
override fun onDestroy() {
super.onDestroy()
if(isRegistered) {
try {
unregisterReceiver(downloadReceiver)
} catch (e: Exception) {
Log.d("HomeFragment", e.toString())
}
}
super.onDestroy()
}
override fun onResume() {
@@ -267,6 +250,14 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
override fun setResponse(response: String) {
responses = responses+response+"\n"
println(responses)
Log.d("DashBoardActResponse",response)
// if (response.contains("checkUpdate")) {
// hemocubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
// }
}
private fun createDeviceUpdateRequestData(): DeviceUpdateRequest {
return DeviceUpdateRequest(
serial_no = sharedPreference.getString(Constants.DEVICE_ID, "")
)
}
}

View File

@@ -6,12 +6,14 @@ import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Context.BATTERY_SERVICE
import android.content.Context.RECEIVER_EXPORTED
import android.content.DialogInterface
import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import android.net.Uri
import android.os.BatteryManager
import android.os.Build
import android.os.Bundle
import android.util.Base64
import android.util.Log
@@ -19,7 +21,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.core.content.FileProvider
import androidx.annotation.RequiresApi
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
@@ -70,6 +72,7 @@ import java.util.zip.ZipInputStream
@AndroidEntryPoint
class HomeFragment : Fragment() {
private var isRegistered = false
private var downloadId: Long = 0
private lateinit var binding: FragmentHomeBinding
private val viewModel: TestRightViewModel by activityViewModels()
@@ -96,6 +99,7 @@ class HomeFragment : Fragment() {
return binding.root
}
@RequiresApi(Build.VERSION_CODES.P)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
@@ -145,35 +149,67 @@ class HomeFragment : Fragment() {
checkForTokenAndUpdate()
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
userDataList.forEach { userData ->
// Now re-subscribe to allUserData
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { originalUserDataList ->
Log.d("LOCAL_DB OBSERVE", "OBSERVE CALLED")
val resultList = MolbioV2ResultRequest(mutableListOf())
originalUserDataList.forEach { userData ->
Log.d(
": USER DATA",
originalUserDataList.count().toString() + " : " + userData._id
)
var accessToken = sharedPreference.getString(Constants.ACCESS_TOKEN, "").toString()
// Upload results after processing all userData to avoid duplicates and ensure all modifications are done
if(accessToken.isNotEmpty()) {
if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION) {
val currentTimeFormatted = SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ssZZZZZ",
Locale.getDefault()
).format(Calendar.getInstance().time)
val bufferIntensityThreshold =
Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId]?.toString()
?: "defaultThreshold" // Handle possible nulls safely
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = "2024-02-08 16:33:56",//userData.testTime,
analysisStatus = userData.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(),
interpretation = userData.classificationResult,
analysisDate = currentTimeFormatted,
analysisStatus = userData.classificationResult
?: "defaultStatus", // Handle possible nulls
thresholds = bufferIntensityThreshold,
interpretation = userData.classificationResult
?: "defaultInterpretation", // Handle possible nulls
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,
testTime = currentTimeFormatted,
collectionTime = currentTimeFormatted,
expiryTime = currentTimeFormatted
)
)
}
if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION) {
userData.molbioFlag = true
hemoCubeViewModel.uploadResult(resultList)
}
}
Log.d("USER DATA LIST SIZE", resultList.results?.count().toString())
resultList.results?.forEach { result ->
val userData = result.rawData
Log.d("UserData", userData.toString())
if (userData != null) {
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
}
}
resultList.results?.forEach { result ->
result.rawData?.let { sanitizeDoubleValues(it) }
}
// Then, check if there are any results to upload.
if (resultList.results?.isNotEmpty() == true) {
hemoCubeViewModel.uploadResult(resultList)
Log.d("resultcount1", "Uploading sanitized results")
}
}
@@ -201,7 +237,7 @@ class HomeFragment : Fragment() {
}
binding.uploadData.setOnClickListener {
showUploadDialog(requireContext())
// showUploadDialog(requireContext())
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData ->
@@ -250,41 +286,32 @@ class HomeFragment : Fragment() {
}
@RequiresApi(Build.VERSION_CODES.P)
private fun checkForTokenAndUpdate() {
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()
if (userID.isNotEmpty() && password.isNotEmpty()) {
if(userID.isNotEmpty() && password.isNotEmpty()) {
Log.d("istoken",isTokenAvailable.toString())
if (!isTokenAvailable) {
Log.d("istoken1",isTokenAvailable.toString())
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 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.
}else if(isTokenAvailable){
Log.d("istoken7",isTokenAvailable.toString())
isTokenAvailable = true
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.startPeriodicCheckUpdate()
hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData())
}else{
if(isTokenExpired(accessToken)) {
Log.d("istoken8",isTokenAvailable.toString())
hemoCubeViewModel.login(createLoginRequestData(userID, password))
}
}
} else if (userID.isEmpty() && password.isEmpty() && deviceId.isNotEmpty()) {
fetchDeviceCredentials()
} else {
Toast.makeText(
requireContext(),
@@ -297,6 +324,9 @@ class HomeFragment : Fragment() {
when (response) {
is Result.Success -> {
updateTokens(response)
response.data.data?.accessToken
isTokenAvailable = true
Log.d("istoken2",isTokenAvailable.toString())
}
is Result.Error -> {
@@ -318,6 +348,36 @@ class HomeFragment : Fragment() {
}
}
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) {
is Result.Success -> {
Log.d("success,","uploded")
it.data.data?.forEach { id ->
id.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag(
it1._id
)
}
}
Toast.makeText(activity, "Molbio Result is successfully uploaded", Toast.LENGTH_LONG)
.show()
}
is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL
it.exception.let { message ->
Toast.makeText(activity, "$message", Toast.LENGTH_LONG)
.show()
Log.d("resultuploadfail", message.toString())
}
}
else -> {}
}
}
hemoCubeViewModel.uploadLogs.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
@@ -326,13 +386,14 @@ class HomeFragment : Fragment() {
// "Log uploaded ${response.data.data?.filename}",
// Toast.LENGTH_SHORT
// ).show()
}
is Result.Error -> {
response.exception.let { message ->
Toast.makeText(
activity,
"An error occurred in uploading logs: $message",
"$message",
Toast.LENGTH_LONG
)
.show()
@@ -347,28 +408,84 @@ class HomeFragment : Fragment() {
}
}
hemoCubeViewModel.checkUpdate.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
val updatedversion = response.data.data?.version.toString()
val currentversion =
context?.let { ctx ->
val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
val versionName = packageInfo.versionName
val versionCode: Long = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
// From Android P (API level 28), versionCode is deprecated and you should use longVersionCode instead.
packageInfo.longVersionCode
} else {
// For older Android versions, use versionCode (cast it to Long for consistency).
packageInfo.versionCode.toLong()
}
// Use versionName and versionCode as needed
Log.d("AppInfo", "Version Name: $versionName, Version Code: $versionCode")
}
Log.d("versionnow",currentversion.toString())
Log.d("versionnow",updatedversion.toString())
if(updatedversion > currentversion.toString()){
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
Toast.makeText(
activity,
"new version ${response.data.data?.version} Available",
Toast.LENGTH_LONG
)
.show()
}else{
Toast.makeText(
activity,
"App is Up to date",
Toast.LENGTH_LONG
)
.show()
}
}
is Result.Error -> {
// response.exception.let { message ->
//// Toast.makeText(
//// activity,
//// "$message",
//// Toast.LENGTH_LONG
//// )
//// .show()
// }
}
is Result.Loading -> {
}
else -> {
}
}
}
hemoCubeViewModel.downloadcertificate.observe(viewLifecycleOwner) { response ->
when (response) {
is Result.Success -> {
val url = response.data
val fileName = "nats_certificate.zip"
val downloadDirectory = "NATS"
val file = downloadFile(url, requireContext(), fileName, downloadDirectory)
Toast.makeText(
requireContext(),
"NATS certificate Downloaded",
Toast.LENGTH_SHORT
).show()
val fileName = "nats_certificate.zip"
val unzipDirectoryPath = requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory"
// Check if the directory with extracted files exists.
val directory = File(unzipDirectoryPath)
if (directory.exists() && directory.isDirectory) {
// Assuming if the directory exists, the certificate has been downloaded and extracted.
// You can add more specific checks here, e.g., checking for specific files within the directory.
Toast.makeText(requireContext(), "NATS certificate already downloaded and extracted.", Toast.LENGTH_SHORT).show()
return@observe
}
val file = downloadFile(url, requireContext(), fileName, downloadDirectory)
val unzipDirectoryPath =
requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory"
unzip(file.absolutePath, unzipDirectoryPath)
Toast.makeText(
requireContext(),
"NATS certificate Extracted",
Toast.LENGTH_SHORT
).show()
}
is Result.Error -> {
@@ -390,36 +507,12 @@ class HomeFragment : Fragment() {
}
}
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
when (it) {
is Result.Success -> {
it.data.data?.forEach { id ->
id.rawData?.let { it1 ->
hemoCubeViewModel.updateMolbioFlag(
it1._id
)
}
}
}
is Result.Error -> {
binding.btnSubmit.visibility = View.VISIBLE
//Remove this line of code while deploying to IOCL
it.exception.let { message ->
Toast.makeText(activity, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
else -> {}
}
}
}
private fun isTokenExpired(token: String): Boolean {
if(token.isNotEmpty()) {
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
val jsonPayload = JSONObject(decodedPayload)
@@ -428,6 +521,9 @@ class HomeFragment : Fragment() {
val currentTimeSeconds = System.currentTimeMillis() / 1000
return exp <= currentTimeSeconds
}else{
return false
}
}
private fun updateTokens(response: Result.Success<LoginResponse>) {
@@ -440,6 +536,7 @@ class HomeFragment : Fragment() {
apply()
}
isTokenAvailable = true
Log.d("istoken3",isTokenAvailable.toString())
}
private fun createLoginRequestData(userID: String, password: String): LoginRequest {
@@ -550,6 +647,7 @@ class HomeFragment : Fragment() {
}
}
@RequiresApi(Build.VERSION_CODES.P)
private fun fetchDeviceCredentials() {
try {
val db = Firebase.firestore
@@ -576,12 +674,16 @@ class HomeFragment : Fragment() {
)
// Save credentials in SharedPreferences
with(sharedPreference.edit()) {
putString("username", username)
putString("password", password)
putString(Constants.DEVICE_ID_API, username)
putString(Constants.DEVICE_PASSWORD_API, password)
putString(Constants.NATS_TOKEN, natsToken)
apply()
}
if (!isTokenAvailable ) {
Log.d("istoken0", isTokenAvailable.toString())
hemoCubeViewModel.login(createLoginRequestData(username, password))
}
} ?: Log.e("fetchDeviceCredentials", "Failed to parse device data.")
} else {
Log.e("fetchDeviceCredentials", "Document does not exist.")
@@ -770,13 +872,28 @@ class HomeFragment : Fragment() {
}
}
private fun sanitizeDoubleValues(hemoCubeTestData: HemoCubeTestData): HemoCubeTestData {
hemoCubeTestData::class.java.declaredFields.forEach { field ->
if (field.type == Double::class.javaObjectType || field.type == Double::class.javaPrimitiveType) {
field.isAccessible = true
val value = field.get(hemoCubeTestData) as Double?
if (value != null && (value.isInfinite() || value.isNaN())) {
field.set(hemoCubeTestData, 0.0) // Replace with a suitable default value
}
}
}
return hemoCubeTestData
}
private fun showUploadDialog(context: Context) {
val builder = AlertDialog.Builder(context)
builder.setTitle(R.string.upload_db_registration_title)
builder.setMessage(R.string.upload_db_registration_message)
builder.setPositiveButton(R.string.upload) { dialog, _ ->
uploadLocalDBData(dialog)
// uploadLocalDBData(dialog)
}
builder.setNegativeButton(R.string.cancel) { dialog, _ ->
@@ -822,34 +939,34 @@ class HomeFragment : Fragment() {
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
userDataList.forEach { userData ->
if (!userData.molbioFlag && isTokenAvailable) {
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = "2024-02-08 16:33:56", //userData.reportUploadTime,
analysisStatus = userData.classificationResult,
thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(),
interpretation = userData.classificationResult,
testId = userData._id,
testTime = userData.testTime,
collectionTime = "2024-02-08 16:33:56",//userData.testTime,
expiryTime = "2024-02-08 16:33:56",//userData.testTime,
)
)
// userDataList.forEach { userData ->
// if (!userData.molbioFlag && isTokenAvailable) {
// resultList.results?.add(
// MolbioV2Result(
// rawData = userData,
// analysisId = userData._id,
// analysisDate = "2024-02-08 16:33:56", //userData.reportUploadTime,
// analysisStatus = userData.classificationResult,
// thresholds = Constants.BUFFER_INTENSITY_THRESHOLDS[userData.deviceId].toString(),
// interpretation = userData.classificationResult,
// testId = userData._id,
// testTime = userData.testTime,
// collectionTime = "2024-02-08 16:33:56",//userData.testTime,
// expiryTime = "2024-02-08 16:33:56",//userData.testTime,
// )
// )
//
// }
}
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION) {
userData.molbioFlag = true
hemoCubeViewModel.uploadResult(resultList)
}
}
// if (!userData.localFlag) {
// userData.localFlag = true
// hemoCubeViewModel.bulkAddResultTestToDb(userData)
// }
// if (!userData.molbioFlag && isTokenAvailable && Constants.MOLBIO_INTEGRATION) {
// userData.molbioFlag = true
// hemoCubeViewModel.uploadResult(resultList)
// }
// }
dialog.dismiss()
}
@@ -862,37 +979,6 @@ class HomeFragment : Fragment() {
}
dialog.dismiss()
}
hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userDataList ->
val resultList = MolbioV2ResultRequest(mutableListOf(MolbioV2Result()))
userDataList.forEach { userData ->
if (!userData.molbioFlag && isTokenAvailable) {
resultList.results?.add(
MolbioV2Result(
rawData = userData,
analysisId = userData._id,
analysisDate = "2024-02-08 16:33:56",//userData.testTime,
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,
)
)
userData.molbioFlag = true
hemoCubeViewModel.uploadResult(resultList)
}
if (!userData.localFlag) {
userData.localFlag = true
hemoCubeViewModel.bulkAddResultTestToDb(userData)
}
}
dialog.dismiss()
}
}
// private fun downloadLocalDBData(dialog: DialogInterface) {
@@ -1013,6 +1099,7 @@ class HomeFragment : Fragment() {
}
private fun getDeviceId() {
Log.d("HomeFragmentUSb","getDeviceId")
val handler = activity as? DeviceCommunicationHandler
handler?.sendAndListenToDevice(
HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND,
@@ -1020,9 +1107,9 @@ class HomeFragment : Fragment() {
override fun onUsbRead(data: ByteArray?) {
data?.let {
val receivedData = String(it, Charset.forName("UTF-8"))
Log.d("HomeFragment","USB data"+receivedData)
// 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.
deviceId = extractDeviceId(receivedData) // Implement this method based on your data format.
if (deviceId.isNotEmpty()) {
// Store the deviceId in SharedPreferences
with(sharedPreference.edit()) {
@@ -1039,6 +1126,7 @@ class HomeFragment : Fragment() {
override fun onUsbError(e: Exception?) {
// Handle USB communication error
Log.d("HomeFragment","USB read error"+e.toString())
}
})
@@ -1054,8 +1142,8 @@ class HomeFragment : Fragment() {
private fun checkForUpdate() {
try {
val db = Firebase.firestore
//val deviceId = deviceId
val deviceId="HHH-AAA-ZZZ"
val deviceRef = db.collection("deviceUpdate").document(Constants.DOCUMENT_ID_FOR_UPDATE)
deviceRef.get().addOnSuccessListener { documentSnapshot ->
@@ -1155,7 +1243,10 @@ class HomeFragment : Fragment() {
// Register a BroadcastReceiver to receive the download complete event
val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
requireActivity().registerReceiver(downloadReceiver, filter)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
isRegistered = true
requireActivity().registerReceiver(downloadReceiver, filter, RECEIVER_EXPORTED)
}
}
private fun extractApkUrl(responseBody: ResponseBody): String {
return responseBody.string()
@@ -1200,8 +1291,15 @@ class HomeFragment : Fragment() {
}
override fun onDestroy() {
super.onDestroy()
if(isRegistered) {
try {
requireActivity().unregisterReceiver(downloadReceiver)
} catch (e: Exception) {
Log.d("HomeFragment", e.toString())
}
}
super.onDestroy()
}
}

View File

@@ -116,7 +116,10 @@ class DeviceProvisionFragment : Fragment() {
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()
natsTokenExpiry = response.data.data?.device?.deviceUser?.natsTokenExpiry.toString(),
globalUpdateIgnore = false,
globalUpdateDone = false,
deviceUpdateAvailable = false
)
)
// viewModel.addDeviceId(DeviceData(deviceId = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()))

View File

@@ -149,6 +149,7 @@ class HemoCubeFragment : Fragment() {
hemoCubeViewModel.fireBaseUpload.observe(viewLifecycleOwner) { result ->
if (result == "Success") {
uploadedToCloud = true
var accessToken = sharedPreferences.getString(Constants.ACCESS_TOKEN, "").toString()
showToast(R.string.test_upload)
if (Constants.MOLBIO_INTEGRATION) {
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
@@ -161,6 +162,8 @@ class HemoCubeFragment : Fragment() {
)
}
handleReadingFinish()
hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.downloadClientCertificate()
}
is Result.Error -> {

View File

@@ -143,6 +143,14 @@ class HemoCubeViewModel @Inject constructor(
}
}
fun uploadResultfornew(molbioV2ResultRequest: MolbioV2ResultRequest) = viewModelScope.launch {
resultUpload.postValue(Result.Loading())
repository.uploadResults(molbioV2ResultRequest).let {
resultUpload.postValue(it)
}
}
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
checkUpdate.postValue(Result.Loading())
repository.checkUpdate(checkUpdateRequest).let {
@@ -367,7 +375,7 @@ class HemoCubeViewModel @Inject constructor(
userData.reportUploadTime = SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss", Locale.getDefault()
).format(Calendar.getInstance().time)
when (repository.addTestToDatabase(userData)) {
when (repository.addTestToDatabasefornew(userData)) {
is Response.Success -> {
fireBaseBulkUpload.postValue("Success")
updateLocalFlag(userData._id)

View File

@@ -11,12 +11,14 @@ 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
@@ -43,6 +45,7 @@ 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) {
@@ -82,6 +85,7 @@ open class HemocubeActivity : AppCompatActivity() {
super.attachBaseContext(newBase)
}
@RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityHemocubeBinding.inflate(layoutInflater)
@@ -106,6 +110,7 @@ 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
@@ -125,6 +130,7 @@ open class HemocubeActivity : AppCompatActivity() {
}
}
@RequiresApi(Build.VERSION_CODES.O)
@SuppressLint("MutableImplicitPendingIntent")
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
val mPendingIntent: PendingIntent
@@ -142,15 +148,21 @@ open class HemocubeActivity : AppCompatActivity() {
}
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
registerReceiver(broadcastReceiver, filter, RECEIVER_EXPORTED)
}else{
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

@@ -1,3 +1,3 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="Updates" path="." />
<external-files-path name="downloaded_file" path="." />
</paths>

View File

@@ -3,7 +3,7 @@ buildscript {
kotlin_version = '1.8.21'
}
dependencies {
classpath 'com.android.tools.build:gradle:8.2.2'
classpath 'com.android.tools.build:gradle:8.3.0'
classpath 'com.google.gms:google-services:4.4.0'
classpath 'com.google.firebase:firebase-appdistribution-gradle:4.0.1'
}

View File

@@ -1,6 +1,6 @@
#Mon Jun 12 17:07:47 IST 2023
#Tue Feb 27 16:09:58 IST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists