diff --git a/README.md b/README.md index fb71559..fc9da27 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,4 @@ -key0: prime24 +### Release key + + key0: prime24 diff --git a/app/build.gradle b/app/build.gradle index 2765cb5..45d2f0e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -19,8 +19,8 @@ android { applicationId "in.sminnovations.hpostesting.dev" minSdk 21 targetSdk 34 - versionCode 120 - versionName "2.1.120" + versionCode 114 + versionName "2.1.114" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index fdb4286..d0792ae 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -162,7 +162,7 @@ android:screenOrientation="portrait" android:stateNotNeeded="true" tools:replace="android:screenOrientation" /> - + + } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt index 99f4d38..a5e10be 100644 --- a/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt +++ b/app/src/main/java/com/example/hpostesting/data/dao/MyDataBase.kt @@ -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) diff --git a/app/src/main/java/com/example/hpostesting/data/model/patient/DeviceData.kt b/app/src/main/java/com/example/hpostesting/data/model/patient/DeviceData.kt index 3b4fc77..823cf01 100644 --- a/app/src/main/java/com/example/hpostesting/data/model/patient/DeviceData.kt +++ b/app/src/main/java/com/example/hpostesting/data/model/patient/DeviceData.kt @@ -26,4 +26,14 @@ data class DeviceData( var natsToken: String = "", @get:PropertyName("natsTokenExpiry") @set:PropertyName("natsTokenExpiry") var natsTokenExpiry: String = "", + @get:PropertyName("deviceUpdateAvailable") @set:PropertyName("deviceUpdateAvailable") + var deviceUpdateAvailable: Boolean = false, + @get:PropertyName("updatePath") @set:PropertyName("updatePath") + var updatePath: String = "", + @get:PropertyName("deviceVersion") @set:PropertyName("deviceVersion") + var deviceVersion: String = "", + @get:PropertyName("globalUpdateDone") @set:PropertyName("globalUpdateDone") + var globalUpdateDone: Boolean = false, + @get:PropertyName("globalUpdateIgnore") @set:PropertyName("globalUpdateIgnore") + var globalUpdateIgnore: Boolean = false, ) \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/model/test/ViewModelModule.kt b/app/src/main/java/com/example/hpostesting/data/model/test/ViewModelModule.kt deleted file mode 100644 index 7250b18..0000000 --- a/app/src/main/java/com/example/hpostesting/data/model/test/ViewModelModule.kt +++ /dev/null @@ -1,29 +0,0 @@ -package com.example.hpostesting.di - -import android.content.Context -import com.example.hpostesting.data.repository.DatabaseRepository -import com.example.hpostesting.data.dao.UserDao -import com.example.hpostesting.domain.SaveRawData -import com.example.hpostesting.domain.SaveRawDataTest -import com.example.hpostesting.presentation.testRight.TestRightViewModel -import dagger.Module -import dagger.Provides -import dagger.hilt.InstallIn -import dagger.hilt.android.components.ViewModelComponent -import dagger.hilt.android.qualifiers.ApplicationContext - -@Module -@InstallIn(ViewModelComponent::class) -object ViewModelModule { - - @Provides - fun provideTestRightViewModel( - saveRawData: SaveRawData, - saveRawDataTest: SaveRawDataTest, - databaseRepository: DatabaseRepository, - userDao: UserDao, - context: Context - ): TestRightViewModel { - return TestRightViewModel(saveRawData, saveRawDataTest, databaseRepository, userDao, context) - } -} diff --git a/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt b/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt index a84da0a..d7babfd 100644 --- a/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt +++ b/app/src/main/java/com/example/hpostesting/domain/di/AppModule.kt @@ -22,6 +22,8 @@ import com.example.hpostesting.domain.LogFileManager import com.example.hpostesting.domain.LogFileManagerImpl import com.example.hpostesting.domain.SaveRawData import com.example.hpostesting.domain.SaveRawDataTest +import com.example.hpostesting.presentation.UsbServiceListener +import com.example.hpostesting.presentation.UsbServiceListenerImpl import com.example.hpostesting.util.PropertyProviderImpl import dagger.Module import dagger.Provides @@ -179,4 +181,10 @@ object AppModule { fun provideLocalFileDataSource(): LocalFileDataSource { return LocalFileDataSourceImpl() } + + @Provides + @Singleton + fun provideUsbServiceListener(context: Context): UsbServiceListener { + return UsbServiceListenerImpl(context) + } } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt b/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt index 8f2eaf3..63c9e4c 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/NatsManager.kt @@ -125,13 +125,8 @@ class NatsManager(datacollector: DashboardActivity) { if (nc?.status == Connection.Status.CONNECTED) { Log.d("NATSCONNECTION", "NATS is successfully connected.") - - val d = nc?.createDispatcher { msg: Message? -> - println("Nats dispatcher $msg") - } - nc?.subscribe("device.hpos.${deviceId}.ping") - + // Log.d(TAG, "Nats subscribed with ping-"+d) nc?.publish( "server.hpos.${deviceId}.ping", "ALIVE".toByteArray(StandardCharsets.UTF_8) @@ -140,7 +135,10 @@ class NatsManager(datacollector: DashboardActivity) { "server.hpos.${deviceId}.health", "ALIVE".toByteArray(StandardCharsets.UTF_8) ) - + val d = nc?.createDispatcher { msg: Message? -> + println("Nats dispatcher $msg") + Log.d(TAG, "Nats dispatcher--$msg") + } d?.subscribe("device.hpos.${deviceId}.ping") { msg -> val response = String(msg.data, StandardCharsets.UTF_8) datacollector.setResponse(response) @@ -175,7 +173,8 @@ class NatsManager(datacollector: DashboardActivity) { 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") + println("Message received (up to 100 times) on topic checkupdate: $response") + Log.d(TAG, "subscribed msg ${msg} on topic checkupdate") } } else { Log.d("NATSCONNECTION", "NATS is not connected. Current status: ${nc?.status}") diff --git a/app/src/main/java/com/example/hpostesting/presentation/UsbServiceListenerImpl.kt b/app/src/main/java/com/example/hpostesting/presentation/UsbServiceListenerImpl.kt new file mode 100644 index 0000000..6ffd14c --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/UsbServiceListenerImpl.kt @@ -0,0 +1,26 @@ +package com.example.hpostesting.presentation + +import android.content.Context +import android.util.Log +import android.widget.Toast + +class UsbServiceListenerImpl(private val context: Context): UsbServiceListener { + override fun onUsbRead(data: ByteArray?) { + if (data != null) { + val receivedData = String(data) + logData(receivedData) + } + } + + override fun onUsbError(e: Exception?) { + showToast("USB Error: ${e?.message}") + } + + private fun showToast(message: String) { + Toast.makeText(context, message, Toast.LENGTH_SHORT).show() + } + + private fun logData(data: String) { + Log.d("UsbServiceListener", "Received data from USB: $data") + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt index cafeb61..33a8c19 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt @@ -3,6 +3,7 @@ package com.example.hpostesting.presentation.dashboard import android.annotation.SuppressLint import android.content.Context import android.content.Intent +import android.content.IntentFilter import android.content.SharedPreferences import android.net.Uri import android.os.Build @@ -30,6 +31,8 @@ import com.google.android.material.navigation.NavigationView import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.appdistribution.FirebaseAppDistributionException 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 @@ -55,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 @@ -72,6 +76,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { override fun onMessageReceived(topic: String, message: String) { // Handle incoming messages from NATS + Log.d(TAG, "Received message on topic $topic: $message") } @@ -130,6 +135,7 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { } } + val drawerLayout: DrawerLayout = binding.drawerLayout val navView: NavigationView = binding.navView val navController = findNavController(R.id.nav_host_fragment_content_dashboard) @@ -148,6 +154,8 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { } } + + override fun onCreateOptionsMenu(menu: Menu): Boolean { // Inflate the menu; this adds items to the action bar if it is present. menuInflater.inflate(R.menu.dashboard, menu) @@ -183,6 +191,13 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { } override fun onDestroy() { + if(isRegistered) { + try { + unregisterReceiver(downloadReceiver) + } catch (e: Exception) { + Log.d("HomeFragment", e.toString()) + } + } super.onDestroy() } @@ -233,7 +248,6 @@ class DashboardActivity : AppCompatActivity(), IDataCollector { } override fun setResponse(response: String) { - responses = responses+response+"\n" println(responses) // if (response.contains("checkUpdate")) { diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt index 639b5c0..6c5de10 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/HomeFragment.kt @@ -1,11 +1,17 @@ package com.example.hpostesting.presentation.dashboard +import android.annotation.SuppressLint import android.app.AlertDialog +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 @@ -49,6 +55,7 @@ import com.google.firebase.perf.ktx.performance import dagger.hilt.android.AndroidEntryPoint import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding +import kotlinx.coroutines.tasks.await import okhttp3.ResponseBody import org.json.JSONObject import java.io.BufferedOutputStream @@ -65,6 +72,8 @@ 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() private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels() @@ -98,8 +107,10 @@ class HomeFragment : Fragment() { binding.labelQuickCapture.visibility = View.VISIBLE binding.btnQuickCapture.visibility = View.VISIBLE } + getDeviceId() checkUnprocessedCSVData() + checkForUpdate() viewModel.allUserData.observe(viewLifecycleOwner) { userData -> deleteIncompleteRegistrations(userData) } @@ -1088,6 +1099,7 @@ class HomeFragment : Fragment() { } private fun getDeviceId() { + Log.d("HomeFragmentUSb","getDeviceId") val handler = activity as? DeviceCommunicationHandler handler?.sendAndListenToDevice( HemoCubeCommands.DEVICE_CONFIGURATION_COMMAND, @@ -1095,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()) { @@ -1114,6 +1126,7 @@ class HomeFragment : Fragment() { override fun onUsbError(e: Exception?) { // Handle USB communication error + Log.d("HomeFragment","USB read error"+e.toString()) } }) @@ -1125,5 +1138,168 @@ class HomeFragment : Fragment() { val matchResult = regex.find(receivedData) return matchResult?.groups?.get(1)?.value ?: "" } + @SuppressLint("SuspiciousIndentation") + private fun checkForUpdate() { + try { + val db = Firebase.firestore + //val deviceId = deviceId + + val deviceRef = db.collection("deviceUpdate").document(Constants.DOCUMENT_ID_FOR_UPDATE) + + deviceRef.get().addOnSuccessListener { documentSnapshot -> + if (documentSnapshot.exists()) { + + val deviceData = + documentSnapshot.toObject(DeviceData::class.java) + + // deviceData?.let { data -> + + val deviceVersion = deviceData!!.deviceVersion + val deviceUpdateAvailableGlobal= deviceData.deviceUpdateAvailable + val updatePathGlobal= deviceData.updatePath + + // if(deviceUpdateAvailableGlobal){ + db.collection("devices").whereEqualTo("deviceId", deviceId).get().addOnSuccessListener { documentSnapshotNew -> + if (documentSnapshotNew.documents.isNotEmpty()) { + documentSnapshotNew.documents.forEach{ + val documentIn = it.toObject(DeviceData::class.java) + + val globalUpdateIgnore = documentIn!!.globalUpdateIgnore + val deviceUpdateAvailable = documentIn.deviceUpdateAvailable + val globalUpdateDone = documentIn.globalUpdateDone + val updatePath = documentIn.updatePath + if(globalUpdateIgnore){ + if(deviceUpdateAvailable){ + val update = db.collection("devices").document(it.id).update("deviceUpdateAvailable",false) + update.addOnSuccessListener { + Log.d("HomeFragmentUpdate","Device local update done") + + initiateUpdate(updatePath) + }.addOnFailureListener{ + Log.e("fetchDeviceUpdate", "update fail.") + } + }else{ + Log.d("HomeFragmentUpdate","Device update not available") + } + }else{ + if(!globalUpdateDone){ + val update = db.collection("devices").document(it.id).update("globalUpdateDone",true) + update.addOnSuccessListener { + Log.d("HomeFragmentUpdate","Device global update done") + + initiateUpdate(updatePathGlobal) + }.addOnFailureListener{ + Log.e("fetchDeviceUpdate", "update fail.") + } + } + } + } + + } else { + Log.e("fetchDeviceUpdate", "Document does not exist.") + } + }.addOnFailureListener { exception -> + Log.e("fetchDeviceUpdate", "Error fetching device data", exception) + } + + + // Toast.makeText(requireActivity()," true -version."+deviceVersion+"updatePath.."+updatePath,Toast.LENGTH_LONG).show() + + + // Log for debugging + Log.d( + "fetchDeviceCredentials", + "deviceVersion: $deviceVersion, Password: $deviceUpdateAvailableGlobal, updatePath: $updatePathGlobal" + ) + + // } ?: Log.e("fetchDeviceUpdate", "Failed to parse device data.") + } else { + Log.e("fetchDeviceUpdate", "Document does not exist.") + } + } + .addOnFailureListener { exception -> + Log.e("fetchDeviceUpdate", "Error fetching device data", exception) + } + } catch (e: Exception) { + Log.e("fetchDeviceUpdate", "Error in fetchDeviceUpdate", e) + } + } + + + 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(requireActivity(), "Updates", "update.apk") + + val downloadManager = requireActivity().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) + 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() + } + 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(requireActivity().getExternalFilesDir("Updates"), "update.apk") + file.setReadable(true, false) // Ensure the file is readable + + val pInfo = requireActivity().baseContext.packageManager.getPackageInfo(requireActivity().baseContext.packageName, 0) + Log.d("HomeFragmentShowInfo",pInfo.packageName.toString()) + val uri: Uri = FileProvider.getUriForFile( + requireActivity(), + "${pInfo.packageName}.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 + Intent.FLAG_ACTIVITY_NEW_TASK or + Intent.FLAG_ACTIVITY_CLEAR_TOP + installIntent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true) + + // Start the installation + startActivity(installIntent) + + Log.d("InstallApk", "Install Intent URI: $uri") + Log.d("InstallApk", "Package Name: ${requireActivity().packageName}") + } + + override fun onDestroy() { + if(isRegistered) { + try { + requireActivity().unregisterReceiver(downloadReceiver) + } catch (e: Exception) { + Log.d("HomeFragment", e.toString()) + } + } + super.onDestroy() + + } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt index 7bb268c..10d34eb 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt @@ -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())) diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt index f6ef870..fe98a4a 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeFragment.kt @@ -590,8 +590,7 @@ class HemoCubeFragment : Fragment() { led1Gain4 = resultLines[5].split(' ')[1].trim().toDoubleOrNull()!! led2Gain4 = resultLines[6].split(' ')[1].trim().toDoubleOrNull()!! led3Gain4 = resultLines[7].split(' ')[1].trim().toDoubleOrNull()!! - led4Gain4 = - resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! + led4Gain4 = resultLines[8].split(' ')[1].split('\r')[0].trim().toDoubleOrNull()!! } finishReading() diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt index dcfd891..47fc9a3 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemoCubeViewModel.kt @@ -88,6 +88,7 @@ class HemoCubeViewModel @Inject constructor( private val _networkStatusLiveData = NetworkStatusLiveData(context) val allUserData = hemoCubeDao.getAll() + val allPendingUserToUpload = MutableLiveData>() val allKitTestData = hemoCubeBufferDao.getAll() val deviceData = MutableLiveData() @@ -194,6 +195,9 @@ class HemoCubeViewModel @Inject constructor( } } } + fun uploadPendingUser() = viewModelScope.launch { + allPendingUserToUpload.postValue(hemoCubeDao.getPendingUser(false)) + } fun uploadHemoCubeResultToDatabaseForBufferCheck( isOnline: Boolean, diff --git a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt index 64f14ea..99707fd 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/hemocube/HemocubeActivity.kt @@ -148,7 +148,11 @@ open class HemocubeActivity : AppCompatActivity() { } val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION) - registerReceiver(broadcastReceiver, filter, RECEIVER_EXPORTED) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + registerReceiver(broadcastReceiver, filter, RECEIVER_EXPORTED) + }else{ + registerReceiver(broadcastReceiver, filter) + } manager.requestPermission(device, mPendingIntent) } diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/UsbService.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/UsbService.kt index cf240ab..16cf5d5 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/UsbService.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/UsbService.kt @@ -33,32 +33,53 @@ class UsbService : Service() { var bus: UsbServiceListener? = null fun connect(driver: UsbSerialDriver, connection: UsbDeviceConnection) { - mPort = driver.ports[0] // Most devices have just one port (port 0) - mPort.open(connection) - mPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE) - isUsbConnected = true - Log.d(TAG, "My Usb Connected ${mPort.driver}") + try { + mPort = driver.ports[0] + mPort.open(connection) - val usbIoManager = SerialInputOutputManager(mPort, - object : SerialInputOutputManager.Listener { - override fun onNewData(data: ByteArray?) { - listener?.onUsbRead(data) - } + if (mPort.device.vendorId == 6790 && mPort.device.productId == 29987) + mPort.setParameters(115200, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE) + else + mPort.setParameters(9600, 8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE) - override fun onRunError(e: Exception?) { - Log.e(TAG, "onRunError() called inside eventDrivenWrite()") - listener?.onUsbError(e) - } + isUsbConnected = true + Log.d(TAG, "Usb Connected ${mPort.driver}") - }) - usbIoManager.start(); + val usbIoManager = SerialInputOutputManager(mPort, + object : SerialInputOutputManager.Listener { + override fun onNewData(data: ByteArray?) { + listener?.onUsbRead(data) + } + + override fun onRunError(e: Exception?) { + Log.e(TAG, "onRunError() called") + listener?.onUsbError(e) + } + }) + + usbIoManager.start() + } catch (ioException: IOException) { + Log.e(TAG, "IOException during USB connection: ${ioException.message}", ioException) + listener?.onUsbError(ioException) + } catch (e: Exception) { + Log.e(TAG, "Error connecting USB: ${e.message}", e) + listener?.onUsbError(e) + } } fun disconnect() { - if (isUsbConnected) { - mPort.close() - isUsbConnected = false; - Log.d(TAG, "My Usb disconnected:: ${mPort.driver}") + try { + if (isUsbConnected) { + mPort.close() + isUsbConnected = false + Log.d(TAG, "USB Port closed successfully:: ${mPort.driver}") + } else { + Log.d(TAG, "USB Port is not connected") + } + } catch (e: IOException) { + Log.e(TAG, "Error closing USB Port: ${e.message}", e) + } catch (e: Exception) { + Log.e(TAG, "An unexpected error occurred: ${e.message}", e) } } diff --git a/app/src/main/res/menu/activity_main_drawer.xml b/app/src/main/res/menu/activity_main_drawer.xml index c390cb7..67653c3 100644 --- a/app/src/main/res/menu/activity_main_drawer.xml +++ b/app/src/main/res/menu/activity_main_drawer.xml @@ -17,4 +17,4 @@ android:icon="@drawable/baseline_settings_24" android:title="@string/menu_settings" /> - \ No newline at end of file + diff --git a/app/src/test/java/com/example/hpostesting/HemoCubeFragmentTest.kt b/app/src/test/java/com/example/hpostesting/HemoCubeFragmentTest.kt index b08dc74..3835355 100644 --- a/app/src/test/java/com/example/hpostesting/HemoCubeFragmentTest.kt +++ b/app/src/test/java/com/example/hpostesting/HemoCubeFragmentTest.kt @@ -1,11 +1,7 @@ package com.example.hpostesting -import android.content.Context import android.content.SharedPreferences import com.example.hpostesting.presentation.hemocube.HemoCubeFragment -import com.example.hpostesting.presentation.hemocube.HemocubeActivity -import `in`.sminnovations.hpostesting.databinding.FragmentHemoCubeReferenceBinding -import junit.framework.TestCase import junit.framework.TestCase.assertEquals import junit.framework.TestCase.assertNull import org.junit.Before @@ -17,18 +13,9 @@ import org.mockito.MockitoAnnotations class HemoCubeFragmentTest { - @Mock - lateinit var mockContext: Context - @Mock private lateinit var mockSharedPreferences: SharedPreferences - @Mock - private lateinit var mockActivity: HemocubeActivity // Replace with your actual Activity class - - @Mock - private lateinit var mockBinding: FragmentHemoCubeReferenceBinding // Replace with your actual Binding class - private lateinit var hemoCubeFragment: HemoCubeFragment @Before @@ -51,7 +38,7 @@ class HemoCubeFragmentTest { val deviceId = hemoCubeFragment.extractV2HardwareId("SNS HPP1-9000 SNE") // Assert - TestCase.assertEquals("HPP1-9000", deviceId) + assertEquals("HPP1-9000", deviceId) } @Test @@ -71,7 +58,7 @@ class HemoCubeFragmentTest { ) // Assert - TestCase.assertEquals("HPP1-0001", deviceId) + assertEquals("HPP1-0001", deviceId) } @Test @@ -84,8 +71,8 @@ class HemoCubeFragmentTest { val result = hemoCubeFragment.allReadingsComplete(repeatReadingCount, readingsPerSample) // Assert - TestCase.assertEquals(true, result) - TestCase.assertEquals(hemoCubeFragment.allReadingsComplete(0, 1), false) + assertEquals(true, result) + assertEquals(hemoCubeFragment.allReadingsComplete(0, 1), false) } @Test @@ -381,64 +368,75 @@ class HemoCubeFragmentTest { @Test fun findResultWithAdditionalMethods_ValidInput_ReturnsBorderlineNormal() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Normal", 70.0)).thenReturn("Negative Borderline, Repeat Test") - val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Negative Borderline", 2.5) + val result = + hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Negative Borderline", 2.5) assertEquals("Borderline. Normal", result) } @Test fun findResultWithAdditionalMethods_ValidInput_ReturnsBorderlineSickleCellTrait1() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Normal", 70.0)).thenReturn("Negative Borderline, Repeat Test") - val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Negative Borderline", 2.2) + val result = + hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Negative Borderline", 2.2) assertEquals("Borderline. Sickle Cell Trait", result) } @Test fun findResultWithAdditionalMethods_ValidInput_ReturnsBorderlineSickleCellTrait2() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Normal", 70.0)).thenReturn("Negative Borderline, Repeat Test") - val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Positive for Sickle Cell. HPLC for Confirmation", 1.35) + val result = hemoCubeFragment.findResultWithAdditionalMethods( + 0.5, + "Positive for Sickle Cell. HPLC for Confirmation", + 1.35 + ) assertEquals("Borderline. Sickle Cell Trait", result) } @Test fun findResultWithAdditionalMethods_ValidInput_ReturnsBorderlineSickleCellDisease() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Normal", 70.0)).thenReturn("Negative Borderline, Repeat Test") - val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Positive for Sickle Cell. HPLC for Confirmation", 1.33) + val result = hemoCubeFragment.findResultWithAdditionalMethods( + 0.5, + "Positive for Sickle Cell. HPLC for Confirmation", + 1.33 + ) assertEquals("Borderline. Sickle Cell Disease", result) } @Test fun findResultWithAdditionalMethods_NormalDeviceRatio_ReturnsNormalBelowSlopeRatioThreshold() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Normal", 70.0)).thenReturn("Negative Borderline, Repeat Test") val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Normal", 30.0) assertEquals("Normal", result) } @Test fun findResultWithAdditionalMethods_NBL_ReturnsNBL() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid") - val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Negative Borderline, Repeat Test", 70.0) + val result = hemoCubeFragment.findResultWithAdditionalMethods( + 0.5, + "Negative Borderline, Repeat Test", + 70.0 + ) assertEquals("Negative Borderline, Repeat Test", result) } @Test fun findResultWithAdditionalMethods_SCT_ReturnsSCT() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid") - val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Sickle Cell Trait", 70.0) + val result = + hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Sickle Cell Trait", 70.0) assertEquals("Sickle Cell Trait", result) } @Test fun findResultWithAdditionalMethods_PBL_ReturnsPBL() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid") - val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Positive for Sickle Cell. HPLC for Confirmation", 1.35) + val result = hemoCubeFragment.findResultWithAdditionalMethods( + 0.5, + "Positive for Sickle Cell. HPLC for Confirmation", + 1.35 + ) assertEquals("Borderline. Sickle Cell Trait", result) } @Test fun findResultWithAdditionalMethods_SCD_ReturnsSCD() { -// `when`(hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Abnormal", 70.0)).thenReturn("Invalid") - val result = hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Sickle Cell Disease", 70.0) + val result = + hemoCubeFragment.findResultWithAdditionalMethods(0.5, "Sickle Cell Disease", 70.0) assertEquals("Sickle Cell Disease", result) } @@ -450,7 +448,11 @@ class HemoCubeFragmentTest { val led2Average = 0.2 // Act - val result = hemoCubeFragment.reclassifyWithBorderlineMethod2(deviceRatio, deviceRatioClass, led2Average) + val result = hemoCubeFragment.reclassifyWithBorderlineMethod2( + deviceRatio, + deviceRatioClass, + led2Average + ) // Assert assertEquals("Borderline. Normal", result) @@ -464,7 +466,11 @@ class HemoCubeFragmentTest { val led2Average = 0.14 // Act - val result = hemoCubeFragment.reclassifyWithBorderlineMethod2(deviceRatio, deviceRatioClass, led2Average) + val result = hemoCubeFragment.reclassifyWithBorderlineMethod2( + deviceRatio, + deviceRatioClass, + led2Average + ) // Assert assertEquals("Borderline. Sickle Cell Trait", result) @@ -478,7 +484,11 @@ class HemoCubeFragmentTest { val led2Average = 0.18 // Act - val result = hemoCubeFragment.reclassifyWithBorderlineMethod2(deviceRatio, deviceRatioClass, led2Average) + val result = hemoCubeFragment.reclassifyWithBorderlineMethod2( + deviceRatio, + deviceRatioClass, + led2Average + ) // Assert assertEquals("Borderline. Sickle Cell Disease", result) @@ -492,7 +502,11 @@ class HemoCubeFragmentTest { val led2Average = 0.195 // Act - val result = hemoCubeFragment.reclassifyWithBorderlineMethod2(deviceRatio, deviceRatioClass, led2Average) + val result = hemoCubeFragment.reclassifyWithBorderlineMethod2( + deviceRatio, + deviceRatioClass, + led2Average + ) // Assert assertEquals("Borderline. Sickle Cell Trait", result) @@ -506,7 +520,11 @@ class HemoCubeFragmentTest { val led2Average = 0.189 // Act - val result = hemoCubeFragment.reclassifyWithBorderlineMethod2(deviceRatio, deviceRatioClass, led2Average) + val result = hemoCubeFragment.reclassifyWithBorderlineMethod2( + deviceRatio, + deviceRatioClass, + led2Average + ) // Assert assertEquals("Borderline. Sickle Cell Disease", result) diff --git a/build.gradle b/build.gradle index ef52576..21a7b54 100644 --- a/build.gradle +++ b/build.gradle @@ -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' } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2f0e0a2..269daf3 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ #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