Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95b3a072b4 | ||
|
|
be21430d0a | ||
|
|
466d0e2afc | ||
|
|
45fd4861f4 | ||
|
|
1a3bb67dce | ||
|
|
3dd247b15d |
@@ -157,7 +157,7 @@ dependencies {
|
|||||||
implementation("com.squareup.okhttp3:okhttp:4.9.3")
|
implementation("com.squareup.okhttp3:okhttp:4.9.3")
|
||||||
|
|
||||||
implementation "androidx.preference:preference-ktx:1.2.1"
|
implementation "androidx.preference:preference-ktx:1.2.1"
|
||||||
implementation 'io.nats:jnats:2.11.2'
|
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.1'
|
||||||
|
|
||||||
implementation("androidx.work:work-runtime-ktx:2.9.0")
|
implementation("androidx.work:work-runtime-ktx:2.9.0")
|
||||||
|
|
||||||
@@ -165,4 +165,6 @@ dependencies {
|
|||||||
implementation 'com.google.android.play:core:1.10.3'
|
implementation 'com.google.android.play:core:1.10.3'
|
||||||
|
|
||||||
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
implementation fileTree(dir: 'libs', include: ['*.aar'])
|
||||||
|
implementation 'io.nats:jnats:2.11.4'
|
||||||
|
|
||||||
}
|
}
|
||||||
Binary file not shown.
@@ -4,15 +4,15 @@
|
|||||||
"type": "APK",
|
"type": "APK",
|
||||||
"kind": "Directory"
|
"kind": "Directory"
|
||||||
},
|
},
|
||||||
"applicationId": "com.example.hpos",
|
"applicationId": "in.sminnovations.hpostesting.quality",
|
||||||
"variantName": "release",
|
"variantName": "release",
|
||||||
"elements": [
|
"elements": [
|
||||||
{
|
{
|
||||||
"type": "SINGLE",
|
"type": "SINGLE",
|
||||||
"filters": [],
|
"filters": [],
|
||||||
"attributes": [],
|
"attributes": [],
|
||||||
"versionCode": 1,
|
"versionCode": 101,
|
||||||
"versionName": "1.0",
|
"versionName": "2.1.101",
|
||||||
"outputFile": "app-release.apk"
|
"outputFile": "app-release.apk"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -7,8 +7,11 @@ import com.example.hpostesting.data.model.updates.CheckUpdateRequest
|
|||||||
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
|
import com.example.hpostesting.data.model.updates.CheckUpdateResponse
|
||||||
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
|
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
|
||||||
import okhttp3.MultipartBody
|
import okhttp3.MultipartBody
|
||||||
|
import okhttp3.Response
|
||||||
import okhttp3.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Header
|
||||||
import retrofit2.http.Multipart
|
import retrofit2.http.Multipart
|
||||||
import retrofit2.http.POST
|
import retrofit2.http.POST
|
||||||
import retrofit2.http.PUT
|
import retrofit2.http.PUT
|
||||||
@@ -31,6 +34,10 @@ interface MolbioResultApi {
|
|||||||
@Body deviceUpdateRequest: DeviceUpdateRequest
|
@Body deviceUpdateRequest: DeviceUpdateRequest
|
||||||
): ResponseBody
|
): ResponseBody
|
||||||
|
|
||||||
|
@GET("deviceService/device/getClientCertificate")
|
||||||
|
suspend fun downloadClientCertificate(
|
||||||
|
): ResponseBody
|
||||||
|
|
||||||
@Multipart
|
@Multipart
|
||||||
@POST("deviceService/device/uploadLogs")
|
@POST("deviceService/device/uploadLogs")
|
||||||
suspend fun uploadLogs(
|
suspend fun uploadLogs(
|
||||||
|
|||||||
@@ -77,6 +77,9 @@ class DatabaseRepository @Inject constructor(
|
|||||||
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) }
|
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun downloadClientCertificate(): Result<ResponseBody> {
|
||||||
|
return safeApiCall { molbioResultApi.downloadClientCertificate() }
|
||||||
|
}
|
||||||
override suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> {
|
override suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse> {
|
||||||
return safeApiCall { molbioResultApi.uploadLogs(logFile) }
|
return safeApiCall { molbioResultApi.uploadLogs(logFile) }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,5 +45,6 @@ interface Repository {
|
|||||||
|
|
||||||
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody>
|
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody>
|
||||||
|
|
||||||
|
suspend fun downloadClientCertificate(): Result<ResponseBody>
|
||||||
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse>
|
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse>
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.example.hpostesting.presentation
|
package com.example.hpostesting.presentation
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
|
import com.example.hpostesting.presentation.assurance.AssuranceControlsActivity
|
||||||
import com.example.hpostesting.presentation.dashboard.DashboardActivity
|
import com.example.hpostesting.presentation.dashboard.DashboardActivity
|
||||||
import io.nats.client.AuthHandler
|
import io.nats.client.AuthHandler
|
||||||
import io.nats.client.Connection
|
import io.nats.client.Connection
|
||||||
@@ -9,9 +12,21 @@ import io.nats.client.NKey
|
|||||||
import io.nats.client.Nats
|
import io.nats.client.Nats
|
||||||
import io.nats.client.Options
|
import io.nats.client.Options
|
||||||
import io.nats.client.support.SSLUtils
|
import io.nats.client.support.SSLUtils
|
||||||
|
import java.io.BufferedInputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.nio.charset.StandardCharsets
|
import java.nio.charset.StandardCharsets
|
||||||
|
import java.nio.file.Paths
|
||||||
import java.security.GeneralSecurityException
|
import java.security.GeneralSecurityException
|
||||||
|
import java.security.KeyStore
|
||||||
|
import java.security.SecureRandom
|
||||||
|
import java.security.cert.CertificateFactory
|
||||||
|
import javax.net.ssl.KeyManager
|
||||||
|
import javax.net.ssl.KeyManagerFactory
|
||||||
|
import javax.net.ssl.SSLContext
|
||||||
|
import javax.net.ssl.TrustManager
|
||||||
|
import javax.net.ssl.TrustManagerFactory
|
||||||
|
|
||||||
|
|
||||||
class NatsManager(datacollector: DashboardActivity) {
|
class NatsManager(datacollector: DashboardActivity) {
|
||||||
@@ -21,11 +36,50 @@ class NatsManager(datacollector: DashboardActivity) {
|
|||||||
val datacollector = datacollector
|
val datacollector = datacollector
|
||||||
var connect = false
|
var connect = false
|
||||||
|
|
||||||
|
private fun createSSLContext(): SSLContext {
|
||||||
|
val keyStorePassword = "prime24".toCharArray() // Change as necessary
|
||||||
|
val clientCertPath = "/storage/sdcard0/Download/client.p12"
|
||||||
|
|
||||||
|
// Load client certificate and key
|
||||||
|
val keyStore = KeyStore.getInstance("PKCS12")
|
||||||
|
FileInputStream(clientCertPath).use { keyStoreInputStream ->
|
||||||
|
keyStore.load(keyStoreInputStream, keyStorePassword)
|
||||||
|
}
|
||||||
|
val caCertPath = "/storage/sdcard0/Android/data/in.sminnovations.hpostesting.quality/files/NATS/clientCertificate/client-cert.pem"
|
||||||
|
val caCert = FileInputStream(caCertPath).use { inputStream ->
|
||||||
|
val certificateFactory = CertificateFactory.getInstance("X.509")
|
||||||
|
certificateFactory.generateCertificate(inputStream)
|
||||||
|
}
|
||||||
|
|
||||||
|
val trustStore = KeyStore.getInstance(KeyStore.getDefaultType()).apply {
|
||||||
|
load(null, null) // Initialize the keystore
|
||||||
|
setCertificateEntry("caCert", caCert) // Add the CA certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize key manager factory
|
||||||
|
val kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm())
|
||||||
|
kmf.init(keyStore, keyStorePassword)
|
||||||
|
|
||||||
|
// Initialize trust manager factory
|
||||||
|
val tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm())
|
||||||
|
tmf.init(trustStore)
|
||||||
|
|
||||||
|
// Initialize SSLContext
|
||||||
|
val sslContext = SSLContext.getInstance("TLS")
|
||||||
|
sslContext.init(kmf.keyManagers, tmf.trustManagers, SecureRandom())
|
||||||
|
|
||||||
|
return sslContext
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
fun connect() {
|
fun connect() {
|
||||||
Log.d(TAG, "TRY TO CONNECT")
|
Log.d(TAG, "TRY TO CONNECT")
|
||||||
Thread {
|
Thread {
|
||||||
|
|
||||||
val seedString = "SUAEB5PUWNS6C2HUV3MFI6HUDEAPGPFPBHMI73NHIQATCDD2BWALVEZXZ4"
|
val seedString = "SUAJH5VMO6GDRQA6QTXCLIJMS74IWIUTU3NJVYIOTZF2LBWUPD77DA2ZEA"
|
||||||
|
Log.e("seedString",seedString)
|
||||||
val seedBytes = seedString.toCharArray()
|
val seedBytes = seedString.toCharArray()
|
||||||
|
|
||||||
val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere
|
val theNKey = NKey.fromSeed(seedBytes) // really should load from somewhere
|
||||||
@@ -70,6 +124,11 @@ class NatsManager(datacollector: DashboardActivity) {
|
|||||||
connect = true
|
connect = true
|
||||||
datacollector.setConnect(true)
|
datacollector.setConnect(true)
|
||||||
|
|
||||||
|
if (nc?.status == Connection.Status.CONNECTED) {
|
||||||
|
Log.e("NATSCONNECTION", "NATS is successfully connected.")
|
||||||
|
} else {
|
||||||
|
Log.e("NATSCONNECTION", "NATS is not connected. Current status: ${nc?.status}")
|
||||||
|
}
|
||||||
|
|
||||||
nc?.publish(
|
nc?.publish(
|
||||||
"server.hpos.HCV-000-3001.ping",
|
"server.hpos.HCV-000-3001.ping",
|
||||||
@@ -84,6 +143,7 @@ class NatsManager(datacollector: DashboardActivity) {
|
|||||||
println("PRITIMOI SARKAR $msg")
|
println("PRITIMOI SARKAR $msg")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
d?.subscribe("device.hpos.HCV-000-3001.update") { msg ->
|
d?.subscribe("device.hpos.HCV-000-3001.update") { msg ->
|
||||||
val response = String(msg.data, StandardCharsets.UTF_8)
|
val response = String(msg.data, StandardCharsets.UTF_8)
|
||||||
datacollector.setResponse(response)
|
datacollector.setResponse(response)
|
||||||
@@ -117,7 +177,7 @@ class NatsManager(datacollector: DashboardActivity) {
|
|||||||
} catch (exp: Exception) {
|
} catch (exp: Exception) {
|
||||||
println(exp.printStackTrace())
|
println(exp.printStackTrace())
|
||||||
connect = false
|
connect = false
|
||||||
datacollector.setConnect(true)
|
datacollector.setConnect(false)
|
||||||
}
|
}
|
||||||
}.start()
|
}.start()
|
||||||
|
|
||||||
|
|||||||
@@ -3,14 +3,19 @@ package com.example.hpostesting.presentation.assurance
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import com.example.hpostesting.presentation.NatsManager
|
||||||
|
import com.example.hpostesting.presentation.dashboard.IDataCollector
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import `in`.sminnovations.hpostesting.databinding.ActivityAssuranceControlsBinding
|
import `in`.sminnovations.hpostesting.databinding.ActivityAssuranceControlsBinding
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class AssuranceControlsActivity: AppCompatActivity() {
|
class AssuranceControlsActivity: AppCompatActivity(), IDataCollector {
|
||||||
lateinit var binding: ActivityAssuranceControlsBinding
|
lateinit var binding: ActivityAssuranceControlsBinding
|
||||||
lateinit var sharedPreference: SharedPreferences
|
lateinit var sharedPreference: SharedPreferences
|
||||||
|
lateinit var nats: NatsManager
|
||||||
|
var responses: String = ""
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
@@ -24,5 +29,21 @@ class AssuranceControlsActivity: AppCompatActivity() {
|
|||||||
.replace(binding.fgAssuranceControls.id, AssuranceControlsFragment())
|
.replace(binding.fgAssuranceControls.id, AssuranceControlsFragment())
|
||||||
.commit()
|
.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nats = NatsManager(this)
|
||||||
|
// nats.connect()
|
||||||
|
// nats.pub("server.hpos.HCV-000-3001.ping", "THIS IS A TEST MSG")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setConnect(connect: Boolean) {
|
||||||
|
if(connect){
|
||||||
|
Log.i("NATS Connection", connect.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setResponse(response: String) {
|
||||||
|
|
||||||
|
responses = responses+response+"\n"
|
||||||
|
println(responses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -43,11 +43,19 @@ import com.google.firebase.perf.ktx.performance
|
|||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import `in`.sminnovations.hpostesting.R
|
import `in`.sminnovations.hpostesting.R
|
||||||
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
|
import `in`.sminnovations.hpostesting.databinding.FragmentHomeBinding
|
||||||
|
import okhttp3.ResponseBody
|
||||||
import org.json.JSONObject
|
import org.json.JSONObject
|
||||||
|
import java.io.BufferedOutputStream
|
||||||
|
import java.io.File
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import java.io.FileOutputStream
|
||||||
|
import java.net.URL
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import java.util.zip.ZipEntry
|
||||||
|
import java.util.zip.ZipInputStream
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
class HomeFragment : Fragment() {
|
class HomeFragment : Fragment() {
|
||||||
@@ -62,7 +70,6 @@ class HomeFragment : Fragment() {
|
|||||||
private val homeViewModel: HemoCubeViewModel by activityViewModels()
|
private val homeViewModel: HemoCubeViewModel by activityViewModels()
|
||||||
|
|
||||||
private var isTokenAvailable = false
|
private var isTokenAvailable = false
|
||||||
|
|
||||||
private lateinit var sharedPreference: SharedPreferences
|
private lateinit var sharedPreference: SharedPreferences
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?,
|
||||||
@@ -203,7 +210,7 @@ class HomeFragment : Fragment() {
|
|||||||
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
|
hemoCubeViewModel.deviceUpdate(createDeviceUpdateRequestData())
|
||||||
hemoCubeViewModel.uploadLogs()
|
hemoCubeViewModel.uploadLogs()
|
||||||
hemoCubeViewModel.startPeriodicCheckUpdate()
|
hemoCubeViewModel.startPeriodicCheckUpdate()
|
||||||
|
hemoCubeViewModel.downloadClientCertificate()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -213,6 +220,11 @@ class HomeFragment : Fragment() {
|
|||||||
Toast.LENGTH_SHORT
|
Toast.LENGTH_SHORT
|
||||||
).show()
|
).show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response ->
|
hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response ->
|
||||||
when (response) {
|
when (response) {
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
@@ -267,6 +279,41 @@ class HomeFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
hemoCubeViewModel.downloadcertificate.observe(viewLifecycleOwner) { response ->
|
||||||
|
when (response) {
|
||||||
|
is Result.Success -> {
|
||||||
|
val url = response.data
|
||||||
|
|
||||||
|
val fileName = "nats_certificate.zip"
|
||||||
|
val downloadDirectory = "NATS"
|
||||||
|
val file = downloadFile(url, requireContext(), fileName, downloadDirectory)
|
||||||
|
Toast.makeText(requireContext(), "NATS certificate Downloaded", Toast.LENGTH_SHORT).show()
|
||||||
|
|
||||||
|
val unzipDirectoryPath = requireContext().getExternalFilesDir(null)?.absolutePath + "/$downloadDirectory"
|
||||||
|
unzip(file.absolutePath, unzipDirectoryPath)
|
||||||
|
Toast.makeText(requireContext(), "NATS certificate Extracted", Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
is Result.Error -> {
|
||||||
|
response.exception.let { message ->
|
||||||
|
Toast.makeText(
|
||||||
|
activity,
|
||||||
|
"An error occurred in nats download: $message",
|
||||||
|
Toast.LENGTH_LONG
|
||||||
|
)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
is Result.Loading -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
else -> {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
|
hemoCubeViewModel.resultUpload.observe(viewLifecycleOwner) {
|
||||||
when (it) {
|
when (it) {
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
@@ -291,8 +338,11 @@ class HomeFragment : Fragment() {
|
|||||||
else -> {}
|
else -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun isTokenExpired(token: String): Boolean {
|
private fun isTokenExpired(token: String): Boolean {
|
||||||
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
val parts = token.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||||
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
|
val decodedPayload = String(Base64.decode(parts[1], Base64.DEFAULT))
|
||||||
@@ -342,6 +392,60 @@ class HomeFragment : Fragment() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun downloadFile(responseBody: ResponseBody, context: Context, fileName: String, downloadDirectory: String): File {
|
||||||
|
// Ensure the download directory exists
|
||||||
|
val fileDir = File(context.getExternalFilesDir(null), downloadDirectory)
|
||||||
|
if (!fileDir.exists()) {
|
||||||
|
fileDir.mkdirs()
|
||||||
|
}
|
||||||
|
val file = File(fileDir, fileName)
|
||||||
|
Log.d("Download", "Starting download to $file")
|
||||||
|
responseBody.byteStream().use { inputStream ->
|
||||||
|
FileOutputStream(file).use { outputStream ->
|
||||||
|
inputStream.copyTo(outputStream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// After download
|
||||||
|
Log.d("Download", "Download completed to ${file.absolutePath}")
|
||||||
|
|
||||||
|
return file
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private fun unzip(zipFilePath: String, destDirectory: String) {
|
||||||
|
val destDir = File(destDirectory)
|
||||||
|
if (!destDir.exists()) {
|
||||||
|
destDir.mkdir()
|
||||||
|
}
|
||||||
|
ZipInputStream(FileInputStream(zipFilePath)).use { zipIn ->
|
||||||
|
var entry: ZipEntry? = zipIn.nextEntry
|
||||||
|
while (entry != null) {
|
||||||
|
val filePath = destDirectory + File.separator + entry.name
|
||||||
|
if (!entry.isDirectory) {
|
||||||
|
extractFile(zipIn, filePath)
|
||||||
|
} else {
|
||||||
|
val dir = File(filePath)
|
||||||
|
dir.mkdir()
|
||||||
|
}
|
||||||
|
zipIn.closeEntry()
|
||||||
|
entry = zipIn.nextEntry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun extractFile(zipIn: ZipInputStream, filePath: String) {
|
||||||
|
BufferedOutputStream(FileOutputStream(filePath)).use { bos ->
|
||||||
|
val bytesIn = ByteArray(4096)
|
||||||
|
var read: Int
|
||||||
|
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
||||||
|
bos.write(bytesIn, 0, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setUserId() {
|
private fun setUserId() {
|
||||||
binding.btnSubmit.setOnClickListener {
|
binding.btnSubmit.setOnClickListener {
|
||||||
val userId = binding.userId.text.toString()
|
val userId = binding.userId.text.toString()
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import android.content.Context
|
|||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.util.Log
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
@@ -74,6 +75,11 @@ class DeviceProvisionFragment : Fragment() {
|
|||||||
Constants.NATS_TOKEN,
|
Constants.NATS_TOKEN,
|
||||||
response.data.data?.device?.deviceUser?.natsToken
|
response.data.data?.device?.deviceUser?.natsToken
|
||||||
)
|
)
|
||||||
|
response.data.data?.device?.deviceUser?.natsToken?.let {
|
||||||
|
Log.e("natstoken",
|
||||||
|
it
|
||||||
|
)
|
||||||
|
}
|
||||||
putString(
|
putString(
|
||||||
Constants.NATS_TOKEN_EXPIRE_DATE,
|
Constants.NATS_TOKEN_EXPIRE_DATE,
|
||||||
response.data.data?.device?.deviceUser?.natsTokenExpiry
|
response.data.data?.device?.deviceUser?.natsTokenExpiry
|
||||||
|
|||||||
@@ -79,6 +79,7 @@ class HemoCubeViewModel @Inject constructor(
|
|||||||
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
|
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
|
||||||
|
|
||||||
val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
|
val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
|
||||||
|
val downloadcertificate = MutableLiveData<Result<ResponseBody>>()
|
||||||
|
|
||||||
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
|
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
|
||||||
|
|
||||||
@@ -141,6 +142,9 @@ class HemoCubeViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
|
fun checkUpdate(checkUpdateRequest: CheckUpdateRequest) = viewModelScope.launch {
|
||||||
checkUpdate.postValue(Result.Loading())
|
checkUpdate.postValue(Result.Loading())
|
||||||
repository.checkUpdate(checkUpdateRequest).let {
|
repository.checkUpdate(checkUpdateRequest).let {
|
||||||
@@ -155,6 +159,17 @@ class HemoCubeViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fun downloadClientCertificate() = viewModelScope.launch {
|
||||||
|
downloadcertificate.postValue(Result.Loading())
|
||||||
|
repository.downloadClientCertificate().let {
|
||||||
|
downloadcertificate.postValue(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun startPeriodicCheckUpdate() {
|
fun startPeriodicCheckUpdate() {
|
||||||
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
|
val periodicRequest = PeriodicWorkRequestBuilder<CheckUpdateWorker>(
|
||||||
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES
|
repeatInterval = 1, repeatIntervalTimeUnit = TimeUnit.MINUTES
|
||||||
|
|||||||
@@ -11,12 +11,14 @@ import android.content.ServiceConnection
|
|||||||
import android.hardware.usb.UsbDevice
|
import android.hardware.usb.UsbDevice
|
||||||
import android.hardware.usb.UsbDeviceConnection
|
import android.hardware.usb.UsbDeviceConnection
|
||||||
import android.hardware.usb.UsbManager
|
import android.hardware.usb.UsbManager
|
||||||
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import android.view.Menu
|
import android.view.Menu
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.activity.viewModels
|
import androidx.activity.viewModels
|
||||||
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.get
|
import androidx.core.view.get
|
||||||
@@ -43,6 +45,7 @@ open class HemocubeActivity : AppCompatActivity() {
|
|||||||
private val TAG = "HemoCube"
|
private val TAG = "HemoCube"
|
||||||
|
|
||||||
private val broadcastReceiver = object : BroadcastReceiver() {
|
private val broadcastReceiver = object : BroadcastReceiver() {
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
@@ -81,6 +84,7 @@ open class HemocubeActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
binding = ActivityHemocubeBinding.inflate(layoutInflater)
|
binding = ActivityHemocubeBinding.inflate(layoutInflater)
|
||||||
@@ -105,6 +109,7 @@ open class HemocubeActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
open fun connectUsb(permissionGranted: Boolean) {
|
open fun connectUsb(permissionGranted: Boolean) {
|
||||||
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
|
Log.d(TAG, "connectUsb() called, permission variable = $permissionGranted")
|
||||||
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
|
val manager = getSystemService(Context.USB_SERVICE) as UsbManager
|
||||||
@@ -125,32 +130,40 @@ open class HemocubeActivity : AppCompatActivity() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@SuppressLint("MutableImplicitPendingIntent")
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
|
@SuppressLint("UnspecifiedImmutableFlag")
|
||||||
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
|
private fun requestUserPermission(manager: UsbManager, device: UsbDevice) {
|
||||||
val mPendingIntent: PendingIntent
|
val mPendingIntent: PendingIntent
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
|
val pendingIntentFlags = when {
|
||||||
mPendingIntent = PendingIntent.getBroadcast(
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||||
this, 0, Intent(Constants.HEMOCUBE_USB_PERMISSION), PendingIntent.FLAG_MUTABLE
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
}
|
||||||
} else {
|
else -> {
|
||||||
mPendingIntent = PendingIntent.getBroadcast(
|
|
||||||
this,
|
|
||||||
0,
|
|
||||||
Intent(Constants.HEMOCUBE_USB_PERMISSION),
|
|
||||||
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mPendingIntent = PendingIntent.getBroadcast(
|
||||||
|
this,
|
||||||
|
0,
|
||||||
|
Intent(Constants.HEMOCUBE_USB_PERMISSION),
|
||||||
|
pendingIntentFlags
|
||||||
|
)
|
||||||
|
|
||||||
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
|
val filter = IntentFilter(Constants.HEMOCUBE_USB_PERMISSION)
|
||||||
registerReceiver(broadcastReceiver, filter)
|
registerReceiver(broadcastReceiver, filter, RECEIVER_EXPORTED)
|
||||||
|
|
||||||
|
// Request permission
|
||||||
manager.requestPermission(device, mPendingIntent)
|
manager.requestPermission(device, mPendingIntent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
fun setupService() {
|
fun setupService() {
|
||||||
val intent = Intent(this, UsbService::class.java)
|
val intent = Intent(this, UsbService::class.java)
|
||||||
bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
bindService(intent, connection, Context.BIND_AUTO_CREATE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequiresApi(Build.VERSION_CODES.O)
|
||||||
open fun reconnectDevice() {
|
open fun reconnectDevice() {
|
||||||
mService.disconnect()
|
mService.disconnect()
|
||||||
unbindService(connection)
|
unbindService(connection)
|
||||||
|
|||||||
Reference in New Issue
Block a user