From bdb58f9b4968556074684601e44211a87b31606e Mon Sep 17 00:00:00 2001 From: chandrashekhar reddy Date: Wed, 5 Jun 2024 16:22:12 +0530 Subject: [PATCH] new 124 version with cuvette size option --- app/build.gradle | 1 + app/release/output-metadata.json | 6 +- app/src/main/AndroidManifest.xml | 34 +- .../hpostesting/data/constant/Constants.kt | 348 ++++++++--------- .../hpostesting/data/constant/DataHolder.kt | 1 + .../data/constant/HemoCubeCommands.kt | 1 + .../hpostesting/data/dao/MyDataBase.kt | 2 +- .../presentation/KitScanActivity.kt | 23 +- .../hpostesting/presentation/MainActivity.kt | 2 +- .../adapter/OfflineUserListAdapter.kt | 2 +- .../presentation/autodac/AutoDacFragment.kt | 133 ++++++- .../presentation/dashboard/GalleryFragment.kt | 8 +- .../presentation/dashboard/HomeFragment.kt | 139 +++---- .../dashboard/ui/LoginFragment.kt | 82 ++-- .../dashboard/ui/PasswordResetActivity.kt | 42 +++ .../presentation/deviceinfo/DeviceActivity.kt | 4 +- .../presentation/deviceinfo/DeviceFragment.kt | 3 +- .../diagnostics/DiagnosticsFragment.kt | 3 - .../presentation/hemocube/HemoCubeFragment.kt | 1 + .../testRight/TestRightViewModel.kt | 2 +- .../hpostesting/util/AppInitializer.kt | 14 + .../hpostesting/util/MyAuthenticator.kt | 44 +++ .../util/MyAuthenticatorService.kt | 12 + .../example/hpostesting/util/SecureStorage.kt | 33 ++ app/src/main/res/drawable-v24/internet.png | Bin 0 -> 12662 bytes app/src/main/res/drawable-v24/off.png | Bin 0 -> 11842 bytes app/src/main/res/layout/activity_device.xml | 24 +- app/src/main/res/layout/activity_kit_scan.xml | 2 +- app/src/main/res/layout/activity_main.xml | 2 + .../res/layout/activity_password_reset.xml | 35 ++ app/src/main/res/layout/fragment_auto_dac.xml | 8 +- app/src/main/res/layout/fragment_device.xml | 2 +- .../main/res/layout/fragment_diagnostics.xml | 2 +- app/src/main/res/layout/fragment_gallery.xml | 17 +- .../layout/fragment_hemo_cube_reference.xml | 2 +- app/src/main/res/layout/fragment_home.xml | 351 +++++++++--------- .../main/res/layout/fragment_slideshow.xml | 2 +- .../main/res/layout/fragment_usb_terminal.xml | 2 +- app/src/main/res/values-hi/strings.xml | 7 + app/src/main/res/values-kn/strings.xml | 7 + app/src/main/res/values/strings.xml | 7 + app/src/main/res/xml/authenticator.xml | 5 + 42 files changed, 924 insertions(+), 491 deletions(-) create mode 100644 app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/PasswordResetActivity.kt create mode 100644 app/src/main/java/com/example/hpostesting/util/AppInitializer.kt create mode 100644 app/src/main/java/com/example/hpostesting/util/MyAuthenticator.kt create mode 100644 app/src/main/java/com/example/hpostesting/util/MyAuthenticatorService.kt create mode 100644 app/src/main/java/com/example/hpostesting/util/SecureStorage.kt create mode 100644 app/src/main/res/drawable-v24/internet.png create mode 100644 app/src/main/res/drawable-v24/off.png create mode 100644 app/src/main/res/layout/activity_password_reset.xml create mode 100644 app/src/main/res/xml/authenticator.xml diff --git a/app/build.gradle b/app/build.gradle index c30314c..d755fd5 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -170,5 +170,6 @@ dependencies { implementation 'io.nats:jnats:2.11.4' implementation 'org.apache.commons:commons-math3:3.6.1' implementation 'pl.droidsonroids.gif:android-gif-drawable:1.2.17' + implementation 'androidx.security:security-crypto:1.1.0-alpha03' } \ No newline at end of file diff --git a/app/release/output-metadata.json b/app/release/output-metadata.json index 14fde68..bd0f6e5 100644 --- a/app/release/output-metadata.json +++ b/app/release/output-metadata.json @@ -4,15 +4,15 @@ "type": "APK", "kind": "Directory" }, - "applicationId": "in.sminnovations.hpostesting.quality", + "applicationId": "in.sminnovations.hpostesting.iocl", "variantName": "release", "elements": [ { "type": "SINGLE", "filters": [], "attributes": [], - "versionCode": 101, - "versionName": "2.1.101", + "versionCode": 124, + "versionName": "2.1.124", "outputFile": "app-release.apk" } ], diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 858168f..1d17348 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,9 @@ + @@ -34,12 +37,29 @@ android:supportsRtl="true" android:theme="@style/Theme.HPOSTesting" tools:targetApi="31"> + + + + + + + + - - - - - - - + + + + + + + diff --git a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt index b69fd0d..e2761c2 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/Constants.kt @@ -37,7 +37,7 @@ object Constants { const val TEST_RIGHT_TOTAL_PIXEL = 3694 - const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 40 + const val MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE = 35 const val RANGE_IN_RESULT_CALCULATIONS = 10 @@ -78,178 +78,6 @@ object Constants { // jig const val NAVIGATE_TO_TEST_JIG_DIRECTLY = false - val STATICID = listOf( - "FACTORY", - "ADMIN", - "PQUSER", - "QCUSER", - "VIZ-1000-0004", - "VIZ-1000-0005", - "VIZ-1000-0006", - "HC-V1-001", - "HC-V1-002", - "HC-V1-003", - "HC-V1-004", - "HC-V1-005", - "HC-V1-006", - "HC-V1-007", - "HC-V1-008", - "HC-V1-009", - "HC-V1-010", - "HC-V1-011", - "HC-V1-012", - "HC-V1-013", - "HC-V1-014", - "HC-V1-015", - "HC-V1-016", - "HC-V1-017", - "HC-V1-018", - "HC-V1-019", - "HC-V1-020", - "HCV-000-1015", - "HCV-000-3002", - "HCV-000-3003", - "HCV-000-3004", - "HCV-000-3005", - "HCV-000-3006", - "HCV-000-3007", - "HCV-000-3008", - "HCV-000-3009", - "HCV-000-3010", - "HCV-000-3011", - "HCV-000-3012", - "HCV-000-3013", - "HCV-000-3014", - "HCV-000-3015", - "HCV-000-3016", - "HCV-000-3017", - "HCV-000-3018", - "HCV-000-3019", - "HCV-000-3020", - "HCV-000-3021", - "HCV-000-3022", - "HCV-000-3023", - "HCV-000-3024", - "HCV-000-3025", - "HCV-000-3026", - "HCV-000-3027", - "HCV-000-3028", - "HCV-000-3029", - "HCV-000-3030", - "HPP1-0124-0001", - "HPP1-0124-0002", - "HPP1-0124-0003", - "HPP1-0124-0004", - "HPP1-0124-0005", - "HPP1-0124-0006", - "HPP1-0124-0007", - "HPP1-0124-0008", - "HPP1-0124-0009", - "HPP1-0124-0010", - "HPP1-0124-0011", - "HPP1-0124-0012", - "HPP1-0124-0013", - "HPP1-0124-0014", - "HPP1-0124-0015", - "HPP1-0124-0016", - "HPP1-0124-0017", - "HPP1-0124-0018", - "HPP1-0124-0019", - "HPP1-0124-0020", - "HPP1-0124-0021", - "HPP1-0124-0022", - "HPP1-0124-0023", - "HPP1-0124-0024", - "HPP1-0124-0025", - "HPP1-0124-0026", - "HPP1-0124-0027", - "HPP1-0124-0028", - "HPP1-0124-0029", - "HPP1-0124-0030", - "HPP1-0124-0031", - "HPP1-0124-0032", - "HPP1-0124-0033", - "HPP1-0124-0034", - "HPP1-0124-0035", - "HPP1-0124-0036", - "HPP1-0124-0037", - "HPP1-0124-0038", - "HPP1-0124-0039", - "HPP1-0124-0040", - "HPP1-0124-0041", - "HPP1-0124-0042", - "HPP1-0124-0043", - "HPP1-0124-0044", - "HPP1-0124-0045", - "HPP1-0124-0046", - "HPP1-0124-0047", - "HPP1-0124-0048", - "HPP1-0124-0049", - "HPP1-0124-0050", - "HCV-001-0001", - "HCV-001-0002", - "HCV-001-0003", - "HCV-001-0004", - "HCV-001-0005", - "HCV-001-0006", - "HCV-001-0007", - "HCV-001-0008", - "HCV-001-0009", - "HCV-001-0010", - "HCV-001-0011", - "HCV-001-0012", - "HCV-001-0013", - "HCV-001-0014", - "HCV-001-0015", - "HCV-001-0016", - "HCV-001-0017", - "HCV-001-0018", - "HCV-001-0019", - "HCV-001-0020", - "HCV-001-0021", - "HCV-001-0022", - "HCV-001-0023", - "HCV-001-0024", - "HCV-001-0025", - "HCV-001-0026", - "HCV-001-0027", - "HCV-001-0028", - "HCV-001-0029", - "HCV-001-0030", - "HCV-001-0031", - "HCV-001-0032", - "HCV-001-0033", - "HCV-001-0034", - "HCV-001-0003", - "HCV-001-0035", - "HCV-001-0036", - "HCV-001-0037", - "HCV-001-0038", - "HCV-001-0039", - "HCV-001-0040", - "HCV-001-0041", - "HCV-001-0042", - "HCV-001-0043", - "HCV-001-0044", - "HCV-001-0045", - "HCV-001-0046", - "HCV-001-0047", - "HCV-001-0048", - "HCV-001-0049", - "HCV-001-0050", - "HCV-000-6001", - "HCV-000-6002", - "HCV-000-6003", - "HCV-000-6004", - "HCV-000-6005", - "HCV-000-6006", - "HCV-000-6007", - "HCV-000-6008", - "HCV-000-6009", - "HCV-000-6010", - ) - - const val password = "SMI@12345" const val KIT_NUMBER = "KitNumber" const val KIT_COUNT = "KitCount" @@ -1763,4 +1591,178 @@ object Constants { const val positiveForSickleCellMax2mm = 0.39 const val sickleCellDiseaseMin2mm = 0.39 const val sickleCellDiseaseMax2mm = 1.0 + + + + // val STATICID = listOf( +// "FACTORY", +// "ADMIN", +// "PQUSER", +// "QCUSER", +// "VIZ-1000-0004", +// "VIZ-1000-0005", +// "VIZ-1000-0006", +// "HC-V1-001", +// "HC-V1-002", +// "HC-V1-003", +// "HC-V1-004", +// "HC-V1-005", +// "HC-V1-006", +// "HC-V1-007", +// "HC-V1-008", +// "HC-V1-009", +// "HC-V1-010", +// "HC-V1-011", +// "HC-V1-012", +// "HC-V1-013", +// "HC-V1-014", +// "HC-V1-015", +// "HC-V1-016", +// "HC-V1-017", +// "HC-V1-018", +// "HC-V1-019", +// "HC-V1-020", +// "HCV-000-1015", +// "HCV-000-3002", +// "HCV-000-3003", +// "HCV-000-3004", +// "HCV-000-3005", +// "HCV-000-3006", +// "HCV-000-3007", +// "HCV-000-3008", +// "HCV-000-3009", +// "HCV-000-3010", +// "HCV-000-3011", +// "HCV-000-3012", +// "HCV-000-3013", +// "HCV-000-3014", +// "HCV-000-3015", +// "HCV-000-3016", +// "HCV-000-3017", +// "HCV-000-3018", +// "HCV-000-3019", +// "HCV-000-3020", +// "HCV-000-3021", +// "HCV-000-3022", +// "HCV-000-3023", +// "HCV-000-3024", +// "HCV-000-3025", +// "HCV-000-3026", +// "HCV-000-3027", +// "HCV-000-3028", +// "HCV-000-3029", +// "HCV-000-3030", +// "HPP1-0124-0001", +// "HPP1-0124-0002", +// "HPP1-0124-0003", +// "HPP1-0124-0004", +// "HPP1-0124-0005", +// "HPP1-0124-0006", +// "HPP1-0124-0007", +// "HPP1-0124-0008", +// "HPP1-0124-0009", +// "HPP1-0124-0010", +// "HPP1-0124-0011", +// "HPP1-0124-0012", +// "HPP1-0124-0013", +// "HPP1-0124-0014", +// "HPP1-0124-0015", +// "HPP1-0124-0016", +// "HPP1-0124-0017", +// "HPP1-0124-0018", +// "HPP1-0124-0019", +// "HPP1-0124-0020", +// "HPP1-0124-0021", +// "HPP1-0124-0022", +// "HPP1-0124-0023", +// "HPP1-0124-0024", +// "HPP1-0124-0025", +// "HPP1-0124-0026", +// "HPP1-0124-0027", +// "HPP1-0124-0028", +// "HPP1-0124-0029", +// "HPP1-0124-0030", +// "HPP1-0124-0031", +// "HPP1-0124-0032", +// "HPP1-0124-0033", +// "HPP1-0124-0034", +// "HPP1-0124-0035", +// "HPP1-0124-0036", +// "HPP1-0124-0037", +// "HPP1-0124-0038", +// "HPP1-0124-0039", +// "HPP1-0124-0040", +// "HPP1-0124-0041", +// "HPP1-0124-0042", +// "HPP1-0124-0043", +// "HPP1-0124-0044", +// "HPP1-0124-0045", +// "HPP1-0124-0046", +// "HPP1-0124-0047", +// "HPP1-0124-0048", +// "HPP1-0124-0049", +// "HPP1-0124-0050", +// "HCV-001-0001", +// "HCV-001-0002", +// "HCV-001-0003", +// "HCV-001-0004", +// "HCV-001-0005", +// "HCV-001-0006", +// "HCV-001-0007", +// "HCV-001-0008", +// "HCV-001-0009", +// "HCV-001-0010", +// "HCV-001-0011", +// "HCV-001-0012", +// "HCV-001-0013", +// "HCV-001-0014", +// "HCV-001-0015", +// "HCV-001-0016", +// "HCV-001-0017", +// "HCV-001-0018", +// "HCV-001-0019", +// "HCV-001-0020", +// "HCV-001-0021", +// "HCV-001-0022", +// "HCV-001-0023", +// "HCV-001-0024", +// "HCV-001-0025", +// "HCV-001-0026", +// "HCV-001-0027", +// "HCV-001-0028", +// "HCV-001-0029", +// "HCV-001-0030", +// "HCV-001-0031", +// "HCV-001-0032", +// "HCV-001-0033", +// "HCV-001-0034", +// "HCV-001-0003", +// "HCV-001-0035", +// "HCV-001-0036", +// "HCV-001-0037", +// "HCV-001-0038", +// "HCV-001-0039", +// "HCV-001-0040", +// "HCV-001-0041", +// "HCV-001-0042", +// "HCV-001-0043", +// "HCV-001-0044", +// "HCV-001-0045", +// "HCV-001-0046", +// "HCV-001-0047", +// "HCV-001-0048", +// "HCV-001-0049", +// "HCV-001-0050", +// "HCV-000-6001", +// "HCV-000-6002", +// "HCV-000-6003", +// "HCV-000-6004", +// "HCV-000-6005", +// "HCV-000-6006", +// "HCV-000-6007", +// "HCV-000-6008", +// "HCV-000-6009", +// "HCV-000-6010", +// ) +// } \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/data/constant/DataHolder.kt b/app/src/main/java/com/example/hpostesting/data/constant/DataHolder.kt index f86f27a..29b88b3 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/DataHolder.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/DataHolder.kt @@ -27,6 +27,7 @@ object DataHolder { var isAppFolderCreated = false var appFolderPath = "" var isReferenceTaken = false + var isToken = false var sampleReadCounter = 0 var deviceConstant: TestRightDeviceConstants? = null diff --git a/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt b/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt index ff07fad..4664153 100644 --- a/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt +++ b/app/src/main/java/com/example/hpostesting/data/constant/HemoCubeCommands.kt @@ -30,4 +30,5 @@ enum class HemoCubeCommands(val command: String) { FORTH_GAIN_COMMAND("W\r"), CHECK_CUVETTE_COMMAND("L\r"), CHECK_TEMP_COMMAND("A\r"), + J_COMMAND("J\r"), } \ 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 801a948..bc1b3bb 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 @@ -23,7 +23,7 @@ import com.example.hpostesting.data.model.patient.UserData @Database( entities = [UserData::class, HemoCubeTestData::class, DeviceData::class, BufferCheckData::class], - version = 33, + version = 34, exportSchema = false ) @TypeConverters(Converters::class) diff --git a/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt index ed06ade..15e8515 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/KitScanActivity.kt @@ -67,8 +67,24 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate { } } - private fun processScannedData(contents: String) { - binding.nameEditText.setText(contents) + private fun processScannedData(contents: String) {//edited auto selection of cuvette size + if(contents.contains("SMI/SC/")){ + with(sharedPreference.edit()) { + putString(Constants.CUVETTE_SIZE, "10mm") + apply() + } + Toast.makeText(this, "Selected cuvette size: 10mm", Toast.LENGTH_SHORT).show() + binding.nameEditText.setText(contents) + }else if(contents.contains("SC-2-D10/")){ + with(sharedPreference.edit()) { + putString(Constants.CUVETTE_SIZE, "2mm") + apply() + } + Toast.makeText(this, "Selected cuvette size: 2mm", Toast.LENGTH_SHORT).show() + binding.nameEditText.setText(contents) + }else{ + Toast.makeText(this, R.string.invalid_kit, Toast.LENGTH_LONG).show() + } } override fun attachBaseContext(newBase: Context?) { @@ -112,8 +128,9 @@ class KitScanActivity : AppCompatActivity(), IDcsSdkApiDelegate { binding = ActivityKitScanBinding.inflate(layoutInflater) sharedPreference = this.getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) setContentView(binding.root) + binding.toolbar.title = "Kit Serial Number" - if (DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE && DataHolder.isReferenceTaken) { + if (DataHolder.sampleReadCounter <= Constants.MAXIMUM_TEST_ALLOWED_BEFORE_REFERENCE && DataHolder.isToken) { DataHolder.selectedTest!!.kitSerial = DataHolder.kitSerial moveToNext() } diff --git a/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt index 215c942..6d1ce11 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/MainActivity.kt @@ -75,7 +75,7 @@ class MainActivity : AppCompatActivity() { super.onCreate(savedInstanceState) binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) - + binding.myToolbar.title = "Test Type" setSupportActionBar(binding.myToolbar) setupListeners() diff --git a/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt index 8c4fd16..27916fc 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/adapter/OfflineUserListAdapter.kt @@ -72,7 +72,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int,p override fun onBindViewHolder(holder: OfflineUserListViewHolder, position: Int) { val userList = differ.currentList[position] holder.binding.apply { - userID.text = "User ID: ${userList._id}" + userID.text = "Sample ID: ${userList._id}" bloodGroup.text = "Blood group: ${userList.bloodGroup}" time.text = "Time: ${isBetween15And30Minutes(userList.incubationTime)} \n Started at: ${ SimpleDateFormat("HH:mm:ss").format( diff --git a/app/src/main/java/com/example/hpostesting/presentation/autodac/AutoDacFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/autodac/AutoDacFragment.kt index b42e956..57dbe66 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/autodac/AutoDacFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/autodac/AutoDacFragment.kt @@ -16,6 +16,7 @@ package com.example.hpostesting.presentation.autodac import android.content.Context import android.content.SharedPreferences import android.os.Bundle +import android.text.method.ScrollingMovementMethod import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -36,13 +37,14 @@ import java.util.Calendar import java.util.Locale class AutoDacFragment : Fragment() { - + private var readClick = false + private var testStatusCode = 0.0 private lateinit var binding: FragmentAutoDacBinding private val autoDacViewModel: AutoDacViewModel by activityViewModels() private lateinit var sharedPreferences: SharedPreferences private var currentDeviceData: DeviceData? = null private var resultData: String = "" - private val messages = MutableLiveData() + // private val messages = MutableLiveData() private var startListening = MutableLiveData(false) override fun onCreateView( @@ -64,14 +66,23 @@ class AutoDacFragment : Fragment() { binding.btnSubmit.visibility = View.GONE listenToHemoCube() getDeviceId() + binding.tvSubtitle4.movementMethod = ScrollingMovementMethod() binding.btnSubmit.setOnClickListener { + testStatusCode = 0.5 binding.btnSubmit.visibility = View.GONE - runAutoDacCommand() + runJCommand() } binding.btnReadDac.setOnClickListener { + readClick = true binding.btnReadDac.visibility = View.GONE - readCurrentDACValuesCommand() + runECommand() } + if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") { + binding.btnReadDac.visibility = View.VISIBLE + }else{ + binding.btnReadDac.visibility = View.GONE + } + } private fun observeViewModel() { @@ -80,7 +91,7 @@ class AutoDacFragment : Fragment() { currentDeviceData = it } - messages.observe(viewLifecycleOwner) { + autoDacViewModel.messages.observe(viewLifecycleOwner) { binding.tvSubtitle4.text = it } @@ -114,8 +125,33 @@ class AutoDacFragment : Fragment() { } }) } + private fun runJCommand() { + autoDacViewModel.progressBar.postValue(true) + (activity as AutoDacActivity).mService.sendAndListenToHemoCube( + HemoCubeCommands.J_COMMAND, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) { + } - private fun runAutoDacCommand() { + override fun onUsbError(e: Exception?) { + autoDacViewModel.progressBar.postValue(false) + } + }) + } + private fun runDCommand() { + autoDacViewModel.progressBar.postValue(true) + (activity as AutoDacActivity).mService.sendAndListenToHemoCube( + HemoCubeCommands.DIAGNOSTICS_COMMAND, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) { + } + + override fun onUsbError(e: Exception?) { + autoDacViewModel.progressBar.postValue(false) + } + }) + } + private fun runCCommand() { autoDacViewModel.progressBar.postValue(true) (activity as AutoDacActivity).mService.sendAndListenToHemoCube( HemoCubeCommands.AUTO_DAC_COMMAND, @@ -128,6 +164,33 @@ class AutoDacFragment : Fragment() { } }) } + private fun runGCommand() { + autoDacViewModel.progressBar.postValue(true) + (activity as AutoDacActivity).mService.sendAndListenToHemoCube( + HemoCubeCommands.SET_AUTO_DAC_TO_EPROM_COMMAND, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) { + } + + override fun onUsbError(e: Exception?) { + autoDacViewModel.progressBar.postValue(false) + } + }) + } + private fun runECommand() { + autoDacViewModel.progressBar.postValue(true) + (activity as AutoDacActivity).mService.sendAndListenToHemoCube( + HemoCubeCommands.LOAD_DAC_VALUES, + object : UsbServiceListener { + override fun onUsbRead(data: ByteArray?) { + } + + override fun onUsbError(e: Exception?) { + autoDacViewModel.progressBar.postValue(false) + } + }) + } + private fun setAutoDacValuesCommand() { autoDacViewModel.progressBar.postValue(true) @@ -168,10 +231,13 @@ class AutoDacFragment : Fragment() { override fun onUsbRead(data: ByteArray?) { data?.let { val stringData = String(it) - autoDacViewModel.messages.postValue(stringData) fullReadOutput.append(stringData) resultData += stringData - binding.tvSubtitle4.text = resultData + if (sharedPreferences.getString(Constants.USER_ID, "").toString() == "ADMIN") { + autoDacViewModel.messages.postValue(resultData) + } + + // binding.tvSubtitle4.text = resultData if (stringData.contains("SN")) { val slData = stringData.split(" ") if (slData.size > 1) { @@ -186,9 +252,47 @@ class AutoDacFragment : Fragment() { } } } + if (resultData.contains("#JC") && testStatusCode < 1.0) { + testStatusCode = 1.1 + runDCommand() + } + if (resultData.contains("#DC") && testStatusCode < 1.2) { + testStatusCode = 1.3 + runCCommand() + } + if (resultData.contains("#GC") && testStatusCode < 1.6) { + testStatusCode = 1.7 + runECommand() + } + if (resultData.contains("#EC") && testStatusCode < 1.8) { + testStatusCode = 1.9 + if(resultData.contains("#CS")){ + val pattern = "#CS(.*?)#CC".toRegex() + val matchResult = pattern.find(resultData) + resultData = matchResult?.groups?.get(1)?.value?.trim().toString() + } + resultData += "Calibration Completed\n" + autoDacViewModel.messages.postValue(resultData) + activity?.runOnUiThread { + Toast.makeText(requireActivity(), "Calibration completed", Toast.LENGTH_LONG).show() + binding.ivCheck.visibility = View.VISIBLE + } + } + if (resultData.contains("#EC") && readClick && testStatusCode < 2.1) { + testStatusCode = 2.2 + readCurrentDACValuesCommand() + } + if (resultData.contains("#CC") && testStatusCode < 1.4) { + testStatusCode = 1.5 + if(validateDacValues()){ + setAutoDacValuesCommand() + }else{ + activity?.runOnUiThread { + Toast.makeText(requireActivity(), "use fresh buffer with clean cuvette and restart", Toast.LENGTH_LONG).show() + binding.btnReadDac.visibility = View.GONE + } + } - if (resultData.contains("#CC")) { - setAutoDacValuesCommand() autoDacViewModel.addAutoDacDataToDb( DiagnosticsData( @@ -212,9 +316,7 @@ class AutoDacFragment : Fragment() { ).format(Calendar.getInstance().time) ) ) - activity?.runOnUiThread { - binding.ivCheck.visibility = View.VISIBLE - } + } if (resultData.contains("#WC")) { @@ -231,6 +333,11 @@ class AutoDacFragment : Fragment() { } } + private fun validateDacValues(): Boolean { + + return true + } + fun parseData(inputData: List): List> { val pattern = Regex("([A-Z]+)\\s(\\d+)") val parsedData = mutableListOf>() diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt index ab67eb9..72fd714 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/GalleryFragment.kt @@ -28,6 +28,7 @@ import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.presentation.autodac.AutoDacActivity import com.example.hpostesting.presentation.buffercheck.HemocubeBufferCheckActivity import com.example.hpostesting.presentation.calibration.CalibrationActivity +import com.example.hpostesting.presentation.dashboard.ui.PasswordResetActivity import com.example.hpostesting.presentation.deviceinfo.DeviceActivity import com.example.hpostesting.presentation.deviceprovision.DeviceProvisionActivity import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity @@ -86,9 +87,11 @@ class GalleryFragment : Fragment() { binding.btnUsbTerminal.visibility = View.VISIBLE binding.btnSubmit.visibility = View.VISIBLE binding.btnDeviceInfo.visibility = View.VISIBLE + binding.btnResetPassword.visibility = View.VISIBLE }else{ + binding.btnResetPassword.visibility = View.GONE binding.btnDeviceProvision.visibility = View.GONE - binding.btnAutoDac.visibility = View.GONE + binding.btnAutoDac.visibility = View.VISIBLE binding.btnDeviceProvision.visibility = View.GONE binding.btnDiagnostics.visibility = View.VISIBLE binding.btnFiles.visibility = View.GONE @@ -99,6 +102,9 @@ class GalleryFragment : Fragment() { binding.btnDeviceInfo.visibility = View.VISIBLE } + binding.btnResetPassword.setOnClickListener{ + startActivity(Intent(requireContext(), PasswordResetActivity::class.java)) + } binding.btnDeviceProvision.setOnClickListener { startActivity(Intent(requireContext(), DeviceProvisionActivity::class.java)) } 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 e0fe2ea..264295c 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 @@ -37,6 +37,7 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.annotation.RequiresApi +import androidx.appcompat.content.res.AppCompatResources import androidx.core.content.FileProvider import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels @@ -168,17 +169,17 @@ class HomeFragment : Fragment() { .show() } } - binding.btnLogout.setOnClickListener { - logoutUser(requireContext()) - } +// binding.btnLogout.setOnClickListener { +// logoutUser(requireContext()) +// } binding.btnLogout1.setOnClickListener { logoutUser(requireContext()) } - binding.uploadData.setOnClickListener { -// showUploadDialog(requireContext()) - } +// binding.uploadData.setOnClickListener { +//// showUploadDialog(requireContext()) +// } hemoCubeViewModel.allUserData.observe(viewLifecycleOwner) { userData -> if (sharedPreference.getString(Constants.USER_ID, "").toString() == "ADMIN") { val btnSaveLocalVisibility = @@ -203,15 +204,15 @@ class HomeFragment : Fragment() { } - binding.btnNewKit.setOnClickListener { - with(sharedPreference.edit()) { - putString(Constants.KIT_NUMBER, "") - putInt(Constants.KIT_COUNT, 0) - apply() - } - startActivity(Intent(requireContext(), KitScanActivity::class.java)) - // requireActivity().finish() - } +// binding.btnNewKit.setOnClickListener { +// with(sharedPreference.edit()) { +// putString(Constants.KIT_NUMBER, "") +// putInt(Constants.KIT_COUNT, 0) +// apply() +// } +// startActivity(Intent(requireContext(), KitScanActivity::class.java)) +// // requireActivity().finish() +// } binding.btnNewKitoffline.setOnClickListener { @@ -239,18 +240,20 @@ class HomeFragment : Fragment() { checkNetworkStatus() } - @RequiresApi(Build.VERSION_CODES.P) private fun checkNetworkStatus() { hemoCubeViewModel.networkStatusLiveData.observe(viewLifecycleOwner) { isConnected -> // Toast.makeText(requireContext(),"connected"+isConnected+wasConnected, Toast.LENGTH_SHORT).show() if (isConnected != wasConnected) { if (isConnected) { - binding.internetAvailableCL.visibility = View.VISIBLE - binding.internetNotAvailableCL.visibility = View.GONE - binding.pendingTest.visibility = View.VISIBLE - loadUserData() - setSearch() + binding.tvTitleNoInternet.text = "Please enter the user id and select blood group to start the test." + //binding.internetAvailableCL.visibility = View.VISIBLE + binding.internetIcon.setImageDrawable(AppCompatResources.getDrawable(requireContext(),R.drawable.internet)) + binding.internetNotAvailableCL.visibility = View.VISIBLE + binding.pendingTest.visibility = View.GONE + setUserId() + // loadUserData() + // setSearch() checkForLocalDBData() if (Constants.MOLBIO_INTEGRATION) { checkForTokenAndUpdate() @@ -326,7 +329,9 @@ class HomeFragment : Fragment() { hemoCubeViewModel.sendDataToFirebase() } else { - binding.internetAvailableCL.visibility = View.GONE + binding.tvTitleNoInternet.text = getString(R.string.internet_not_available_please_enter_the_user_id_manually) + // binding.internetAvailableCL.visibility = View.GONE + binding.internetIcon.setImageDrawable(AppCompatResources.getDrawable(requireContext(),R.drawable.off)) binding.pendingTest.visibility = View.GONE binding.internetNotAvailableCL.visibility = View.VISIBLE setUserId() @@ -334,7 +339,9 @@ class HomeFragment : Fragment() { wasConnected = isConnected }else{ if(!wasConnected){ - binding.internetAvailableCL.visibility = View.GONE + binding.internetIcon.setImageDrawable(AppCompatResources.getDrawable(requireContext(),R.drawable.off)) + binding.tvTitleNoInternet.text = getString(R.string.internet_not_available_please_enter_the_user_id_manually) + // binding.internetAvailableCL.visibility = View.GONE binding.pendingTest.visibility = View.GONE binding.internetNotAvailableCL.visibility = View.VISIBLE setUserId() @@ -834,7 +841,7 @@ class HomeFragment : Fragment() { requireActivity() ) }!! - binding.rvOrder.adapter = rvAdapter + // binding.rvOrder.adapter = rvAdapter rvAdapter.startListening() } catch (e: Exception) { @@ -903,50 +910,54 @@ class HomeFragment : Fragment() { requireActivity() ) }!! - binding.rvOrder.adapter = rvAdapter + // binding.rvOrder.adapter = rvAdapter rvAdapter.startListening() userSearchTrace.stop() } - private fun setSearch() { - binding.searchProduct.setOnQueryTextListener(object : - androidx.appcompat.widget.SearchView.OnQueryTextListener { - override fun onQueryTextSubmit(query: String?): Boolean { - return if (!query.isNullOrEmpty()) { - val field = when { - binding.userIdRadioButton.isChecked -> "_id" - binding.abhaIdRadioButton.isChecked -> "abhaId" - binding.aadharIdRadioButton.isChecked -> "aadharId" - else -> null - } - - field?.let { getData(query, it) } - false - - } else { - loadUserData() - false - } - } - - override fun onQueryTextChange(query: String?): Boolean { - return if (!query.isNullOrEmpty()) { - val field = when { - binding.userIdRadioButton.isChecked -> "_id" - binding.abhaIdRadioButton.isChecked -> "abhaId" - binding.aadharIdRadioButton.isChecked -> "aadharId" - else -> null - } - field?.let { getData(query, it) } - false - } else { - loadUserData() - false - } - } - }) - } +// private fun setSearch() { +// binding.searchProduct.setOnQueryTextListener(object : +// androidx.appcompat.widget.SearchView.OnQueryTextListener { +// override fun onQueryTextSubmit(query: String?): Boolean { +// return if (!query.isNullOrEmpty()) { +// val field = when { +// binding.userIdRadioButton.isChecked -> "_id" +// binding.abhaIdRadioButton.isChecked -> "abhaId" +// binding.aadharIdRadioButton.isChecked -> "aadharId" +// else -> null +// } +// +// field?.let { +// //getData(query, it) } +// } +// false +// +// } else { +// // loadUserData() +// false +// } +// } +// +// override fun onQueryTextChange(query: String?): Boolean { +// return if (!query.isNullOrEmpty()) { +// val field = when { +// binding.userIdRadioButton.isChecked -> "_id" +// binding.abhaIdRadioButton.isChecked -> "abhaId" +// binding.aadharIdRadioButton.isChecked -> "aadharId" +// else -> null +// } +// field?.let { +// //getData(query, it) +// } +// false +// } else { +// // loadUserData() +// false +// } +// } +// }) +// } private fun checkForLocalDBData() { // viewModel.allUserData.observe(viewLifecycleOwner) { userDataList -> @@ -963,7 +974,7 @@ class HomeFragment : Fragment() { hemoCubeViewModel.allKitTestData.observe(viewLifecycleOwner) { bufferData -> val uploadDataVisibility = if (bufferData.any { !it.localFlag }) View.VISIBLE else View.GONE - binding.uploadData.visibility = uploadDataVisibility + // binding.uploadData.visibility = uploadDataVisibility } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt index 8170264..daa8e9a 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/LoginFragment.kt @@ -13,15 +13,16 @@ package com.example.hpostesting.presentation.dashboard.ui +import com.example.hpostesting.util.SecureStorage +import android.accounts.Account +import android.accounts.AccountManager import android.annotation.SuppressLint import android.content.Context -import android.content.Context.WIFI_SERVICE import android.content.SharedPreferences import android.location.Location import android.location.LocationListener import android.location.LocationManager import android.net.ConnectivityManager -import android.net.wifi.WifiManager import android.os.Build import android.os.Bundle import android.util.Log @@ -30,23 +31,19 @@ import android.view.View import android.view.ViewGroup import android.widget.Toast import androidx.annotation.RequiresApi -import androidx.core.content.ContextCompat.getSystemService import androidx.fragment.app.Fragment import androidx.navigation.fragment.findNavController import com.example.hpostesting.data.constant.Constants +import com.example.hpostesting.util.AppInitializer import `in`.sminnovations.hpostesting.R import `in`.sminnovations.hpostesting.databinding.FragmentLoginBinding -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import java.net.HttpURLConnection -import java.net.URL -import java.util.Scanner class LoginFragment : Fragment() { var latitude = 0.0 var longitude = 0.0 + private lateinit var accountManager: AccountManager + private lateinit var secureStorage: SecureStorage var TAG = "LoginFragmentCheck" private var _binding: FragmentLoginBinding? = null private val binding get() = _binding!! @@ -58,6 +55,11 @@ class LoginFragment : Fragment() { _binding = FragmentLoginBinding.inflate(inflater, container, false) sharedPreference = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE) + accountManager = AccountManager.get(requireActivity()) + secureStorage = SecureStorage(requireActivity()) + + // Initialize user roles and credentials if not already done + AppInitializer.initialize(requireActivity()) return binding.root } @@ -75,9 +77,8 @@ class LoginFragment : Fragment() { binding.btnLogin.setOnClickListener { // Toast.makeText(requireContext(), "$latitude/$longitude",Toast.LENGTH_SHORT).show() - - val loginId = binding.loginId.text.toString() - val password = binding.password.text.toString() + val loginId = binding.loginId.text.toString().trim() + val password = binding.password.text.toString().trim() if (loginId.isNotBlank() && password.isNotBlank()) { performLogin(loginId, password) @@ -104,21 +105,52 @@ class LoginFragment : Fragment() { } private fun performLogin(loginId: String, password: String) { - val matchingId = Constants.STATICID.firstOrNull { it == loginId } - if (matchingId != null) { - if (password == Constants.password) { - saveUserId(loginId) - navigateToHomeFragment() - return - } else { - Log.d("LoginFragment","wrong password") - Toast.makeText(requireContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show() - } + if (validateCredentials(loginId, password)) { + addAccount(loginId, password) + val role = getRoleForUser(loginId) + saveUserId(role) + navigateToHomeFragment() + return + } else { + Toast.makeText(requireActivity(), "Invalid credentials", Toast.LENGTH_SHORT).show() } - Log.d("LoginFragment","wrong password") - Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show() +// val matchingId = Constants.STATICID.firstOrNull { it == loginId } +// if (matchingId != null) { +// if (password == Constants.password) { +// saveUserId(loginId) +// navigateToHomeFragment() +// return +// } else { +// Log.d("LoginFragment","wrong password") +// Toast.makeText(requireContext(), R.string.wrong_password, Toast.LENGTH_SHORT).show() +// } +// } + // Log.d("LoginFragment","wrong password") + // Toast.makeText(requireContext(), R.string.wrong_user_id, Toast.LENGTH_SHORT).show() + } + private fun getRoleForUser(username: String): String { + // Replace this with your actual logic to determine the role for the user + return when (username) { + "FACTORY" -> "FACTORY" + "ADMIN" -> "ADMIN" + "PQUSER" -> "PQUSER" + "QCUSER" -> "QCUSER" + else -> "HPOSUSER" + } + } + private fun validateCredentials(username: String, password: String): Boolean { + var storedPassword = secureStorage.getPassword() + if(username == "ADMIN"){ + storedPassword = secureStorage.getAdminPassword() + } + return storedPassword != null && + password == storedPassword && + (username == "HPOSUSER" || username == "ADMIN" || username == "FACTORY" || username == "PQUSER" || username == "QCUSER") + } + private fun addAccount(username: String, password: String) { + val account = Account(username, "com.example.account") + accountManager.addAccountExplicitly(account, password, null) } - private fun saveUserId(userId: String) { with(sharedPreference.edit()) { putString(Constants.USER_ID, userId) diff --git a/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/PasswordResetActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/PasswordResetActivity.kt new file mode 100644 index 0000000..d7f65b0 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/presentation/dashboard/ui/PasswordResetActivity.kt @@ -0,0 +1,42 @@ +package com.example.hpostesting.presentation.dashboard.ui + +import com.example.hpostesting.util.SecureStorage +import android.os.Bundle +import android.widget.Button +import android.widget.EditText +import android.widget.Toast +import androidx.appcompat.app.AppCompatActivity +import `in`.sminnovations.hpostesting.R + +class PasswordResetActivity : AppCompatActivity() { + + private lateinit var editTextNewPassword: EditText + private lateinit var buttonResetPassword: Button + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_password_reset) + + editTextNewPassword = findViewById(R.id.editTextNewPassword) + buttonResetPassword = findViewById(R.id.buttonResetPassword) + + buttonResetPassword.setOnClickListener { + val newPassword = editTextNewPassword.text.toString().trim() + if (newPassword.isNotEmpty()) { + resetPassword(newPassword) + } else { + Toast.makeText(this, "Please enter a new password", Toast.LENGTH_SHORT).show() + } + } + } + + private fun resetPassword(newPassword: String) { + // Implement password reset logic here + // For example, you can store the new password securely + // and update it in the authentication system + val secureStorage = SecureStorage(this) + secureStorage.storePassword(newPassword) + Toast.makeText(this, "Password reset successfully", Toast.LENGTH_SHORT).show() + finish() + } +} diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceActivity.kt index 7bf5457..b8bc962 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceActivity.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceActivity.kt @@ -29,6 +29,7 @@ import android.os.Bundle import android.os.IBinder import android.util.Log import android.view.Menu +import android.view.MenuItem import android.widget.Toast import androidx.activity.viewModels import androidx.appcompat.app.AppCompatActivity @@ -105,8 +106,7 @@ class DeviceActivity : AppCompatActivity(), DeviceCommunicationHandler { super.onCreate(savedInstanceState) binding = ActivityDeviceBinding.inflate(layoutInflater) setContentView(binding.root) -// setSupportActionBar(binding.myToolbar) - supportActionBar?.setDisplayHomeAsUpEnabled(true) + binding.myToolbar.title = "Device Information" setupListener() connectUsb(false) } diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceFragment.kt index 6dc688e..e67a9a8 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/deviceinfo/DeviceFragment.kt @@ -141,7 +141,8 @@ class DeviceFragment : Fragment() { val lines = resultData.split("\n") var temp = lines[2] val temp1 = resultData.substringAfter("#AS").substringBefore("#AC") - binding.tvSubtitleNew.text = "Device ID : "+hardwareId+"\nTemperature : $temp\n"+temp1 + binding.tvSubtitleNew.text = + "Device ID : $hardwareId\nTemperature : $temp\n$temp1" } } diff --git a/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt index 57c6860..c563b60 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/diagnostics/DiagnosticsFragment.kt @@ -30,13 +30,10 @@ import androidx.fragment.app.activityViewModels import androidx.lifecycle.MutableLiveData import com.example.hpostesting.data.constant.Constants import com.example.hpostesting.data.constant.HemoCubeCommands -import com.example.hpostesting.data.constant.TestStatus import com.example.hpostesting.data.model.devicediagnostics.AdditionalDetails import com.example.hpostesting.data.model.devicediagnostics.DeviceDiagnosticsRequest import com.example.hpostesting.data.model.diagnostics.DiagnosticsData import com.example.hpostesting.data.model.patient.DeviceData -import com.example.hpostesting.presentation.autodac.AutoDacActivity -import com.example.hpostesting.presentation.hemocube.HemocubeActivity import com.example.hpostesting.presentation.utils.UsbServiceListener import com.example.hpostesting.util.Result import com.example.hpostesting.util.Result.Success 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 28d0865..c83abd4 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 @@ -115,6 +115,7 @@ class HemoCubeFragment : Fragment() { @SuppressLint("SetTextI18n") private fun initViews() { binding.btnSubmit.setOnClickListener { + DataHolder.sampleReadCounter++ binding.btnSubmit.isEnabled = false binding.btnSubmit.isClickable = false activity?.runOnUiThread { diff --git a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt index 0c97970..700f7f9 100644 --- a/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt +++ b/app/src/main/java/com/example/hpostesting/presentation/testRight/TestRightViewModel.kt @@ -485,7 +485,7 @@ class TestRightViewModel @Inject constructor( val csvUri = csvUploadTask.storage.downloadUrl.await().toString() val logUri = logUploadTask.storage.downloadUrl.await().toString() - val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber } + // val serialNumber = Constants.STATICID.firstOrNull { it == deviceSerialNumber } testDetails?.csvPath = csvUri testDetails?.reportPath = logUri diff --git a/app/src/main/java/com/example/hpostesting/util/AppInitializer.kt b/app/src/main/java/com/example/hpostesting/util/AppInitializer.kt new file mode 100644 index 0000000..63f68b1 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/util/AppInitializer.kt @@ -0,0 +1,14 @@ +package com.example.hpostesting.util + +import android.content.Context + +object AppInitializer { + fun initialize(context: Context) { + val secureStorage = SecureStorage(context) + if (secureStorage.getPassword() == null || secureStorage.getAdminPassword() == null) { + // Store the shared password securely + secureStorage.storePassword("SMI@12345") + secureStorage.storeAdminPassword("SMI@Admin$") + } + } +} diff --git a/app/src/main/java/com/example/hpostesting/util/MyAuthenticator.kt b/app/src/main/java/com/example/hpostesting/util/MyAuthenticator.kt new file mode 100644 index 0000000..da739fe --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/util/MyAuthenticator.kt @@ -0,0 +1,44 @@ +package com.example.hpostesting.util + +import android.accounts.AbstractAccountAuthenticator +import android.accounts.Account +import android.accounts.AccountAuthenticatorResponse +import android.accounts.NetworkErrorException +import android.content.Context +import android.os.Bundle + +class MyAuthenticator(context: Context) : AbstractAccountAuthenticator(context) { + override fun editProperties(response: AccountAuthenticatorResponse?, accountType: String?): Bundle { + throw UnsupportedOperationException() + } + + override fun addAccount(response: AccountAuthenticatorResponse?, accountType: String?, authTokenType: String?, requiredFeatures: Array?, options: Bundle?): Bundle? { + // Add your logic to add an account + return null + } + + override fun confirmCredentials(response: AccountAuthenticatorResponse?, account: Account?, options: Bundle?): Bundle? { + // Add your logic to confirm credentials + return null + } + + override fun getAuthToken(response: AccountAuthenticatorResponse?, account: Account?, authTokenType: String?, options: Bundle?): Bundle? { + // Add your logic to get an authentication token + return null + } + + override fun getAuthTokenLabel(authTokenType: String?): String? { + // Label for the auth token type + return null + } + + override fun updateCredentials(response: AccountAuthenticatorResponse?, account: Account?, authTokenType: String?, options: Bundle?): Bundle? { + // Add your logic to update credentials + return null + } + + override fun hasFeatures(response: AccountAuthenticatorResponse?, account: Account?, features: Array?): Bundle? { + // Add your logic to check for specific account features + return null + } +} diff --git a/app/src/main/java/com/example/hpostesting/util/MyAuthenticatorService.kt b/app/src/main/java/com/example/hpostesting/util/MyAuthenticatorService.kt new file mode 100644 index 0000000..14c2e7e --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/util/MyAuthenticatorService.kt @@ -0,0 +1,12 @@ +package com.example.hpostesting.util + +import android.app.Service +import android.content.Intent +import android.os.IBinder + +class MyAuthenticatorService : Service() { + override fun onBind(intent: Intent?): IBinder? { + val authenticator = MyAuthenticator(this) + return authenticator.iBinder + } +} \ No newline at end of file diff --git a/app/src/main/java/com/example/hpostesting/util/SecureStorage.kt b/app/src/main/java/com/example/hpostesting/util/SecureStorage.kt new file mode 100644 index 0000000..d1ebbc3 --- /dev/null +++ b/app/src/main/java/com/example/hpostesting/util/SecureStorage.kt @@ -0,0 +1,33 @@ +package com.example.hpostesting.util + +import android.content.Context +import androidx.security.crypto.EncryptedSharedPreferences +import androidx.security.crypto.MasterKey + +class SecureStorage(context: Context) { + private val masterKey = MasterKey.Builder(context) + .setKeyScheme(MasterKey.KeyScheme.AES256_GCM) + .build() + + private val sharedPreferences = EncryptedSharedPreferences.create( + context, + "secure_prefs", + masterKey, + EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV, + EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM + ) + + fun storePassword(password: String) { + sharedPreferences.edit().putString("shared_password", password).apply() + } + fun storeAdminPassword(password: String) { + sharedPreferences.edit().putString("admin_password", password).apply() + } + fun getAdminPassword(): String? { + return sharedPreferences.getString("admin_password", null) + } + fun getPassword(): String? { + return sharedPreferences.getString("shared_password", null) + } + +} diff --git a/app/src/main/res/drawable-v24/internet.png b/app/src/main/res/drawable-v24/internet.png new file mode 100644 index 0000000000000000000000000000000000000000..4032a34313ba59ce0f220aaa0322aa828a5a41ea GIT binary patch literal 12662 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-v24/off.png b/app/src/main/res/drawable-v24/off.png new file mode 100644 index 0000000000000000000000000000000000000000..229b44ba8f164bd5de706e08ecaf6d0be2c4ed3c GIT binary patch literal 11842 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/activity_device.xml b/app/src/main/res/layout/activity_device.xml index 458cb98..c44bb01 100644 --- a/app/src/main/res/layout/activity_device.xml +++ b/app/src/main/res/layout/activity_device.xml @@ -23,18 +23,18 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - - - - - - - + + > + + + + + + +