diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index a586d9a..153965f 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -43,6 +43,10 @@
android:name="com.example.hpostesting.presentation.autodac.AutoDacActivity"
android:exported="false"
android:theme="@style/Theme.HPOS.NoActionBar" />
+
= android.os.Build.VERSION_CODES.S) {
- mPendingIntent = PendingIntent.getBroadcast(
+ val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+ PendingIntent.getBroadcast(
this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
)
} else {
- mPendingIntent = PendingIntent.getBroadcast(
+ PendingIntent.getBroadcast(
this,
0,
Intent(Constants.HOMOCUBE_USB_PERMISSION),
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 5698fd5..bdb2bb2 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
@@ -13,6 +13,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.deviceprovision.DeviceProvisionActivity
import com.example.hpostesting.presentation.diagnostics.DiagnosticsActivity
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import `in`.sminnovations.hpostesting.databinding.FragmentGalleryBinding
@@ -52,7 +53,7 @@ class GalleryFragment : Fragment() {
}
binding.btnDeviceProvision.setOnClickListener {
-// hemoCubeViewModel.deviceProvision()
+ startActivity(Intent(requireContext(), DeviceProvisionActivity::class.java))
}
binding.btnSubmit.setOnClickListener {
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 500924f..3793c62 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
@@ -130,17 +130,13 @@ class HomeFragment : Fragment() {
showUploadDialog(requireContext())
}
binding.btnNewKit.setOnClickListener {
-// with(sharedPreference.edit()) {
-// putString(Constants.KIT_NUMBER, "")
-// putInt(Constants.KIT_COUNT, 0)
-// apply()
-// }
-// startActivity(Intent(requireContext(), KitScanActivity::class.java))
-// requireActivity().finish()
- val password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "810516d8f4c7").toString()
- val userID = sharedPreference.getString(Constants.DEVICE_ID_API, "HCV-000-3001").toString()
- hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
- hemoCubeViewModel.login(createLoginRequestData(userID, password))
+ with(sharedPreference.edit()) {
+ putString(Constants.KIT_NUMBER, "")
+ putInt(Constants.KIT_COUNT, 0)
+ apply()
+ }
+ startActivity(Intent(requireContext(), KitScanActivity::class.java))
+ requireActivity().finish()
}
}
@@ -149,13 +145,13 @@ class HomeFragment : Fragment() {
val natsToken = sharedPreference.getString(Constants.NATS_TOKEN, "").toString()
val natsTokenExpireDate =
sharedPreference.getString(Constants.NATS_TOKEN_EXPIRE_DATE, "").toString()
- val password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "810516d8f4c7").toString()
- val userID = sharedPreference.getString(Constants.DEVICE_ID_API, "HCV-000-3001").toString()
+ val password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
+ val userID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
if (userID.isNotEmpty() && password.isNotEmpty()) {
if (accessToken.isEmpty() && natsToken.isEmpty()) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
- if (true) {
+ if (isTokenExpired(accessToken)) {
hemoCubeViewModel.login(createLoginRequestData(userID, password))
} else {
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
@@ -197,6 +193,7 @@ class HomeFragment : Fragment() {
Toast.makeText(
requireContext(), response.data.toString(), Toast.LENGTH_SHORT
).show()
+
}
is Result.Error -> {
@@ -240,7 +237,7 @@ class HomeFragment : Fragment() {
}
}
- fun isTokenExpired(token: String): Boolean {
+ private fun isTokenExpired(token: String): Boolean {
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
val jsonPayload = JSONObject(decodedPayload)
diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionActivity.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionActivity.kt
new file mode 100644
index 0000000..aae6d13
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionActivity.kt
@@ -0,0 +1,184 @@
+package com.example.hpostesting.presentation.deviceprovision
+
+import android.annotation.SuppressLint
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.ServiceConnection
+import android.hardware.usb.UsbDevice
+import android.hardware.usb.UsbDeviceConnection
+import android.hardware.usb.UsbManager
+import android.os.Bundle
+import android.os.IBinder
+import android.util.Log
+import android.view.Menu
+import android.widget.Toast
+import androidx.activity.viewModels
+import androidx.appcompat.app.AppCompatActivity
+import androidx.core.content.ContextCompat
+import androidx.core.view.get
+import com.example.hpostesting.data.DataHolder
+import com.example.hpostesting.data.constant.Constants
+import com.example.hpostesting.data.constant.LanguageManager
+import com.example.hpostesting.presentation.testRight.UsbService
+import com.hoho.android.usbserial.driver.UsbSerialDriver
+import com.hoho.android.usbserial.driver.UsbSerialProber
+import dagger.hilt.android.AndroidEntryPoint
+import `in`.sminnovations.hpostesting.R
+import `in`.sminnovations.hpostesting.databinding.ActivityAutoDacBinding
+
+@AndroidEntryPoint
+class DeviceProvisionActivity : AppCompatActivity() {
+ private lateinit var binding: ActivityAutoDacBinding
+ val viewModel: DeviceProvisionViewModel by viewModels()
+ private var myMenu: Menu? = null
+
+ private lateinit var mDriver: UsbSerialDriver
+ private var mConnection: UsbDeviceConnection? = null
+ lateinit var mService: UsbService
+
+ private val TAG = "HemoCube"
+
+ private val broadcastReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+
+ synchronized(this) {
+ val device: UsbDevice? = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
+
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ device?.apply {
+ connectUsb(true)
+ DataHolder.usbConnected.postValue(true)
+ }
+ } else {
+ onErrorReported("permission denied for device")
+ DataHolder.usbConnected.postValue(true)
+ }
+ }
+
+ }
+ }
+
+
+ private val connection = object : ServiceConnection {
+ override fun onServiceConnected(className: ComponentName, service: IBinder) {
+ val binder = service as UsbService.UsbServiceBinder
+ mService = binder.getService()
+ viewModel.isServiceConnected = true
+ mConnection.let { mService.connect(mDriver, mConnection!!) }
+ moveToNext()
+ }
+
+ override fun onServiceDisconnected(arg0: ComponentName) {
+ viewModel.isServiceConnected = false
+ }
+ }
+
+ override fun attachBaseContext(newBase: Context?) {
+ val languageCode = LanguageManager.getSavedLanguage(newBase!!)
+ LanguageManager.setLocale(newBase, languageCode)
+ super.attachBaseContext(newBase)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = ActivityAutoDacBinding.inflate(layoutInflater)
+ setContentView(binding.root)
+// setSupportActionBar(binding.myToolbar)
+ supportActionBar?.setDisplayHomeAsUpEnabled(true)
+ setupListener()
+ connectUsb(false)
+
+ }
+
+ private fun setupListener() {
+ DataHolder.usbConnected.observe(this) {
+ Log.d("USB OBSERVE", "HemoCube called -> $it")
+ if (it) {
+ myMenu?.get(0)?.icon =
+ ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_24)
+ } else {
+ myMenu?.get(0)?.icon =
+ ContextCompat.getDrawable(this, R.drawable.ic_baseline_usb_off_24)
+ Toast.makeText(this, "Device is Disconnected", Toast.LENGTH_SHORT).show()
+ }
+ }
+ }
+
+ fun connectUsb(permissionGranted: Boolean) {
+ Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
+ val manager = getSystemService(Context.USB_SERVICE) as UsbManager
+ val availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
+
+ if (availableDrivers.isEmpty()) {
+ onErrorReported("No Device is Connected")
+ } else {
+ mDriver = availableDrivers[0]
+ mConnection = manager.openDevice(mDriver.device)
+
+ if (mConnection == null) {
+ requestUserPermission(manager, mDriver.device)
+ } else {
+ setupService()
+ }
+ }
+ }
+
+
+ fun onErrorReported(msg: String) {
+ Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
+ if (!isFinishing) onBackPressed()
+ }
+
+
+ private fun moveToNext() {
+ if (supportFragmentManager.isDestroyed) return
+
+ supportFragmentManager.beginTransaction()
+ .replace(binding.fgAutoDac.id, DeviceProvisionFragment()).commit()
+ }
+
+ @SuppressLint("MutableImplicitPendingIntent")
+ private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
+ val mPendingIntent: PendingIntent = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
+ PendingIntent.getBroadcast(
+ this, 0, Intent(Constants.HOMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
+ )
+ } else {
+ PendingIntent.getBroadcast(
+ this,
+ 0,
+ Intent(Constants.HOMOCUBE_USB_PERMISSION),
+ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
+ )
+ }
+
+ val filter = IntentFilter(Constants.HOMOCUBE_USB_PERMISSION)
+ registerReceiver(broadcastReceiver, filter)
+ manager.requestPermission(device, mPendingIntent)
+ }
+
+
+ fun setupService() {
+ val intent = Intent(this, UsbService::class.java)
+ bindService(intent, connection, Context.BIND_AUTO_CREATE)
+ }
+
+
+ override fun onCreateOptionsMenu(menu: Menu?): Boolean {
+ menuInflater.inflate(R.menu.my_menu, menu)
+ return true
+ }
+
+ override fun onDestroy() {
+ super.onDestroy()
+ if (viewModel.isServiceConnected) {
+ mService.disconnect()
+ unbindService(connection)
+ viewModel.isServiceConnected = false
+ }
+ }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..e3bcf55
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionFragment.kt
@@ -0,0 +1,168 @@
+package com.example.hpostesting.presentation.deviceprovision
+
+import android.content.Context
+import android.content.Intent
+import android.content.SharedPreferences
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.Toast
+import androidx.fragment.app.Fragment
+import androidx.fragment.app.activityViewModels
+import com.example.hpostesting.data.Result
+import com.example.hpostesting.data.constant.Constants
+import com.example.hpostesting.data.constant.HemoCubeCommands
+import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
+import com.example.hpostesting.presentation.UsbServiceListener
+import com.example.hpostesting.presentation.dashboard.DashboardActivity
+import com.google.firebase.crashlytics.ktx.crashlytics
+import com.google.firebase.ktx.Firebase
+import `in`.sminnovations.hpostesting.databinding.FragmentDeviceProvisionBinding
+
+class DeviceProvisionFragment : Fragment() {
+
+ private var resultData: String = ""
+ private lateinit var binding: FragmentDeviceProvisionBinding
+ private val viewModel: DeviceProvisionViewModel by activityViewModels()
+ private lateinit var sharedPreferences: SharedPreferences
+ override fun onCreateView(
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentDeviceProvisionBinding.inflate(inflater, container, false)
+ sharedPreferences = requireContext().getSharedPreferences("HEMOCUBE", Context.MODE_PRIVATE)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+ initViews()
+ observeViewModel()
+ }
+
+ private fun initViews() {
+ listenToHemoCube()
+ getDeviceId()
+ binding.btnSubmit.setOnClickListener {
+ viewModel.deviceProvision(
+ DeviceProvisionRequest(
+ email = Constants.deviceProvisionEmail,
+ password = Constants.deviceProvisionPassword,
+ serialNumber = sharedPreferences.getString(Constants.DEVICE_ID, "").toString(),
+ uid = sharedPreferences.getString(Constants.DEVICE_ID, "").toString()
+ )
+ )
+ }
+ }
+
+ private fun observeViewModel() {
+
+ viewModel.deviceProvisionResponse.observe(viewLifecycleOwner) { response ->
+ when (response) {
+ is Result.Success -> {
+ if (response.data.result == "Success") {
+ with(sharedPreferences.edit()) {
+ putString(
+ Constants.DEVICE_ID_API,
+ response.data.data?.credentials?.username
+ )
+ putString(
+ Constants.DEVICE_PASSWORD_API,
+ response.data.data?.credentials?.password
+ )
+ putString(
+ Constants.NATS_TOKEN,
+ response.data.data?.device?.deviceUser?.natsToken
+ )
+ putString(
+ Constants.NATS_TOKEN_EXPIRE_DATE,
+ response.data.data?.device?.deviceUser?.natsTokenExpiry
+ )
+ apply()
+ }
+ startActivity(Intent(requireContext(), DashboardActivity::class.java))
+ Toast.makeText(
+ activity, "Device registered successfully", Toast.LENGTH_LONG
+ ).show()
+ } else {
+ Toast.makeText(
+ activity,
+ "An error occurred in device provision: ${response.data.message}",
+ Toast.LENGTH_LONG
+ ).show()
+ binding.btnSubmit.visibility = View.VISIBLE
+ }
+
+ }
+
+ is Result.Error -> {
+ response.exception.let { message ->
+ Toast.makeText(
+ activity,
+ "An error occurred in device provision: $message",
+ Toast.LENGTH_LONG
+ ).show()
+ }
+ }
+
+ is Result.Loading -> {
+ binding.btnSubmit.visibility = View.GONE
+ }
+
+ else -> {}
+ }
+ }
+ }
+
+
+ private fun getDeviceId() {
+ (activity as DeviceProvisionActivity).mService.sendAndListenToHemoCube(
+ HemoCubeCommands.getDeviceId,
+ object : UsbServiceListener {
+ override fun onUsbRead(data: ByteArray?) {}
+ override fun onUsbError(e: Exception?) {}
+ })
+ }
+
+ private fun listenToHemoCube() {
+
+ val fullReadOutput = StringBuilder()
+
+ try {
+ (activity as DeviceProvisionActivity).mService.listenToHemoCube(object : UsbServiceListener {
+ override fun onUsbRead(data: ByteArray?) {
+ data?.let {
+ val stringData = String(it)
+ fullReadOutput.append(stringData)
+ resultData += stringData
+ handleUsbData()
+ }
+ }
+
+ override fun onUsbError(e: Exception?) {}
+ })
+ } catch (e: Exception) {
+ Firebase.crashlytics.recordException(e)
+ }
+ }
+
+ private fun handleUsbData() {
+ when {
+ resultData.contains("SNE") -> {
+ val pattern = Regex("HPP1-\\d{4}-\\d{4}")
+ val matchResult = pattern.find(resultData)
+ val hardwareId = matchResult?.value
+
+ if (hardwareId.toString().length == 14) {
+ with(sharedPreferences.edit()) {
+ putString(Constants.DEVICE_ID, hardwareId)
+ apply()
+ }
+ activity?.runOnUiThread {
+ binding.btnSubmit.visibility = View.VISIBLE
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionViewModel.kt b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionViewModel.kt
new file mode 100644
index 0000000..8c4d0ac
--- /dev/null
+++ b/app/src/main/java/com/example/hpostesting/presentation/deviceprovision/DeviceProvisionViewModel.kt
@@ -0,0 +1,36 @@
+package com.example.hpostesting.presentation.deviceprovision
+
+import android.content.Context
+import androidx.lifecycle.LiveData
+import androidx.lifecycle.MutableLiveData
+import androidx.lifecycle.ViewModel
+import androidx.lifecycle.viewModelScope
+import com.example.hpostesting.data.NetworkStatusLiveData
+import com.example.hpostesting.data.Result
+import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
+import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
+import com.example.hpostesting.data.repository.DatabaseRepository
+import dagger.hilt.android.lifecycle.HiltViewModel
+import kotlinx.coroutines.launch
+import javax.inject.Inject
+
+@HiltViewModel
+class DeviceProvisionViewModel @Inject constructor(
+ private val databaseRepository: DatabaseRepository,
+ context: Context
+) : ViewModel() {
+
+ var isServiceConnected = false
+ private val _networkStatusLiveData = NetworkStatusLiveData(context)
+ val networkStatusLiveData: LiveData
+ get() = _networkStatusLiveData
+
+ val deviceProvisionResponse = MutableLiveData>()
+
+ fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
+ deviceProvisionResponse.postValue(Result.Loading())
+ databaseRepository.deviceProvision(deviceProvisionRequest).let {
+ deviceProvisionResponse.postValue(it)
+ }
+ }
+}
\ No newline at end of file
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 1b8e23c..6112ee8 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
@@ -20,8 +20,6 @@ import com.example.hpostesting.data.constant.Constants
import com.example.hpostesting.data.dao.HemoCubeBufferDao
import com.example.hpostesting.data.dao.HemoCubeDao
import com.example.hpostesting.data.model.Response
-import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionRequest
-import com.example.hpostesting.data.model.deviceprovision.DeviceProvisionResponse
import com.example.hpostesting.data.model.log.UploadLogsResponse
import com.example.hpostesting.data.model.login.LoginRequest
import com.example.hpostesting.data.model.login.LoginResponse
@@ -73,8 +71,6 @@ class HemoCubeViewModel @Inject constructor(
// startPeriodicCheckUpdate()
// }
- val deviceProvisionResponse = MutableLiveData>()
-
val loginResponse = MutableLiveData>()
val resultUpload = MutableLiveData>()
@@ -130,13 +126,6 @@ class HemoCubeViewModel @Inject constructor(
}
}
- fun deviceProvision(deviceProvisionRequest: DeviceProvisionRequest) = viewModelScope.launch {
- deviceProvisionResponse.postValue(Result.Loading())
- databaseRepository.deviceProvision(deviceProvisionRequest).let {
- deviceProvisionResponse.postValue(it)
- }
- }
-
fun login(loginRequest: LoginRequest) = viewModelScope.launch {
loginResponse.postValue(Result.Loading())
databaseRepository.login(loginRequest).let {
@@ -427,10 +416,10 @@ class HemoCubeViewModel @Inject constructor(
fun getBatteryTemperature(): Float? {
val batteryTemp: Float? = batteryStatus?.let { intent ->
- val temperature = intent?.getIntExtra(
+ val temperature = intent.getIntExtra(
BatteryManager.EXTRA_TEMPERATURE,
0
- ) ?: 0
+ )
temperature.toFloat() / 10
}
diff --git a/app/src/main/res/layout/fragment_device_provision.xml b/app/src/main/res/layout/fragment_device_provision.xml
new file mode 100644
index 0000000..fc8afc5
--- /dev/null
+++ b/app/src/main/res/layout/fragment_device_provision.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
\ No newline at end of file