integration for apk file with checksum added
This commit is contained in:
@@ -23,6 +23,7 @@ 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.ResponseBody
|
import okhttp3.ResponseBody
|
||||||
|
import retrofit2.Response
|
||||||
import retrofit2.http.Body
|
import retrofit2.http.Body
|
||||||
import retrofit2.http.GET
|
import retrofit2.http.GET
|
||||||
import retrofit2.http.Multipart
|
import retrofit2.http.Multipart
|
||||||
@@ -45,7 +46,7 @@ interface MolbioResultApi {
|
|||||||
@POST("deviceService/device/getUpdate")
|
@POST("deviceService/device/getUpdate")
|
||||||
suspend fun deviceUpdate(
|
suspend fun deviceUpdate(
|
||||||
@Body deviceUpdateRequest: DeviceUpdateRequest,
|
@Body deviceUpdateRequest: DeviceUpdateRequest,
|
||||||
): ResponseBody
|
): Response<ResponseBody>
|
||||||
|
|
||||||
@GET("deviceService/device/getClientCertificate")
|
@GET("deviceService/device/getClientCertificate")
|
||||||
suspend fun downloadClientCertificate(
|
suspend fun downloadClientCertificate(
|
||||||
|
|||||||
@@ -93,8 +93,8 @@ class DatabaseRepository @Inject constructor(
|
|||||||
return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) }
|
return safeApiCall { molbioResultApi.checkUpdate(checkUpdateRequest) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody> {
|
override suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): retrofit2.Response<ResponseBody> {
|
||||||
return safeApiCall { molbioResultApi.deviceUpdate(deviceUpdateRequest) }
|
return molbioResultApi.deviceUpdate(deviceUpdateRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse> {
|
override suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse> {
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ interface Repository {
|
|||||||
|
|
||||||
suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse>
|
suspend fun checkUpdate(checkUpdateRequest: CheckUpdateRequest): Result<CheckUpdateResponse>
|
||||||
|
|
||||||
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): Result<ResponseBody>
|
suspend fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest): retrofit2.Response<ResponseBody>
|
||||||
suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse>
|
suspend fun deviceDiagnostics(deviceDiagnosticsRequest: DeviceDiagnosticsRequest): Result<DeviceDiagnosticsResponse>
|
||||||
suspend fun downloadClientCertificate(): Result<ResponseBody>
|
suspend fun downloadClientCertificate(): Result<ResponseBody>
|
||||||
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse>
|
suspend fun uploadLogs(logFile: MultipartBody.Part): Result<UploadLogsResponse>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
package com.example.hpostesting.presentation
|
package com.example.hpostesting.presentation
|
||||||
|
|
||||||
import android.Manifest
|
import android.Manifest
|
||||||
|
import android.annotation.SuppressLint
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.pm.PackageManager
|
import android.content.pm.PackageManager
|
||||||
@@ -33,6 +34,7 @@ import com.example.hpostesting.util.MyUtils
|
|||||||
import `in`.sminnovations.hpostesting.R
|
import `in`.sminnovations.hpostesting.R
|
||||||
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
|
import `in`.sminnovations.hpostesting.databinding.ActivitySplashBinding
|
||||||
|
|
||||||
|
@SuppressLint("CustomSplashScreen")
|
||||||
class SplashActivity : AppCompatActivity() {
|
class SplashActivity : AppCompatActivity() {
|
||||||
|
|
||||||
private lateinit var binding: ActivitySplashBinding
|
private lateinit var binding: ActivitySplashBinding
|
||||||
@@ -64,6 +66,7 @@ class SplashActivity : AppCompatActivity() {
|
|||||||
requestPermissions()
|
requestPermissions()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressLint("HardwareIds")
|
||||||
private fun setupStaticConstants() {
|
private fun setupStaticConstants() {
|
||||||
DataHolder.mobileUniqueId =
|
DataHolder.mobileUniqueId =
|
||||||
Settings.Secure.getString(
|
Settings.Secure.getString(
|
||||||
|
|||||||
@@ -35,7 +35,9 @@ import androidx.navigation.ui.setupActionBarWithNavController
|
|||||||
import androidx.navigation.ui.setupWithNavController
|
import androidx.navigation.ui.setupWithNavController
|
||||||
import com.example.hpostesting.util.Result
|
import com.example.hpostesting.util.Result
|
||||||
import com.example.hpostesting.data.constant.Constants
|
import com.example.hpostesting.data.constant.Constants
|
||||||
|
import com.example.hpostesting.data.constant.DataHolder
|
||||||
import com.example.hpostesting.data.constant.LanguageManager
|
import com.example.hpostesting.data.constant.LanguageManager
|
||||||
|
import com.example.hpostesting.data.model.login.LoginRequest
|
||||||
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
|
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
|
||||||
import com.example.hpostesting.presentation.utils.NatsManager
|
import com.example.hpostesting.presentation.utils.NatsManager
|
||||||
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
|
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
|
||||||
@@ -49,6 +51,7 @@ import `in`.sminnovations.hpostesting.BuildConfig
|
|||||||
import `in`.sminnovations.hpostesting.R
|
import `in`.sminnovations.hpostesting.R
|
||||||
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
|
import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.security.MessageDigest
|
||||||
|
|
||||||
interface NatsMessageCallback {
|
interface NatsMessageCallback {
|
||||||
fun onMessageReceived(topic: String, message: String)
|
fun onMessageReceived(topic: String, message: String)
|
||||||
@@ -106,43 +109,34 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
|
|||||||
nats.sub("server.hpos.${deviceId}.ping")
|
nats.sub("server.hpos.${deviceId}.ping")
|
||||||
nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG")
|
nats.pub("server.hpos.${deviceId}.ping", "THIS IS A TEST MSG")
|
||||||
|
|
||||||
hemocubeViewModel.deviceUpdate.observe(this) { result ->
|
hemocubeViewModel.deviceUpdate.observe(this) {
|
||||||
when (result) {
|
Log.d("DashboardLogs",it.toString())
|
||||||
is Result.Success -> {
|
|
||||||
// Handle success
|
var apk = it
|
||||||
val apk = result.data
|
val file = File(getExternalFilesDir("Downloads"), "update.apk")
|
||||||
val file = File(getExternalFilesDir("Updates"), "update.apk")
|
file.setReadable(true, false)
|
||||||
file.setReadable(true, false) // Ensure the file is readable
|
|
||||||
|
// Write APK to file
|
||||||
apk.byteStream().use { input ->
|
apk.byteStream().use { input ->
|
||||||
file.outputStream().use { output ->
|
file.outputStream().use { output ->
|
||||||
input.copyTo(output)
|
input.copyTo(output)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Log.d("Responsebodyformat", "Responsebodyformat: ")
|
|
||||||
installApk(file)
|
|
||||||
Log.e("ApI", "APK URL: $apk")
|
|
||||||
Toast.makeText(
|
|
||||||
this,
|
|
||||||
"${result.data}",
|
|
||||||
Toast.LENGTH_SHORT
|
|
||||||
).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
is Result.Error -> {
|
|
||||||
result.exception.let { message ->
|
|
||||||
Toast.makeText(this, "An error occurred On Updating App: $message", Toast.LENGTH_LONG)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
hemocubeViewModel.deviceUpdateheader.observe(this){
|
||||||
|
val apkFile = File(getExternalFilesDir("Downloads"), "update.apk")
|
||||||
|
val expectedChecksum = it.get("Checksum") // Provide your expected checksum here
|
||||||
|
val algorithm = "SHA-256" // Choose the algorithm you want to use (e.g., MD5, SHA-1, SHA-256)
|
||||||
|
|
||||||
is Result.Loading -> {
|
val isIntegrityVerified = verifyChecksum(apkFile, expectedChecksum!!, algorithm)
|
||||||
}
|
if (isIntegrityVerified) {
|
||||||
|
println("APK integrity verified: The file has not been tampered with.")
|
||||||
else -> {
|
installApk(apkFile)
|
||||||
|
} else {
|
||||||
|
println("APK integrity check failed: The file may have been tampered with.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val drawerLayout: DrawerLayout = binding.drawerLayout
|
val drawerLayout: DrawerLayout = binding.drawerLayout
|
||||||
val navView: NavigationView = binding.navView
|
val navView: NavigationView = binding.navView
|
||||||
@@ -175,7 +169,24 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
|
|||||||
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
|
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun calculateChecksum(file: File, algorithm: String): String {
|
||||||
|
val digest = MessageDigest.getInstance(algorithm)
|
||||||
|
val inputStream = file.inputStream()
|
||||||
|
val buffer = ByteArray(8192)
|
||||||
|
var bytesRead = inputStream.read(buffer)
|
||||||
|
while (bytesRead != -1) {
|
||||||
|
digest.update(buffer, 0, bytesRead)
|
||||||
|
bytesRead = inputStream.read(buffer)
|
||||||
|
}
|
||||||
|
val checksumBytes = digest.digest()
|
||||||
|
return checksumBytes.joinToString("") { "%02x".format(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function to verify checksum
|
||||||
|
fun verifyChecksum(file: File, expectedChecksum: String, algorithm: String): Boolean {
|
||||||
|
val actualChecksum = calculateChecksum(file, algorithm)
|
||||||
|
return actualChecksum.equals(expectedChecksum, ignoreCase = true)
|
||||||
|
}
|
||||||
private fun installApk(file: File) {
|
private fun installApk(file: File) {
|
||||||
val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
|
val pInfo = baseContext.packageManager.getPackageInfo(baseContext.packageName, 0)
|
||||||
val uri: Uri = FileProvider.getUriForFile(
|
val uri: Uri = FileProvider.getUriForFile(
|
||||||
@@ -284,4 +295,6 @@ class DashboardActivity : AppCompatActivity(), IDataCollector {
|
|||||||
"N/A"
|
"N/A"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -374,7 +374,7 @@ class HomeFragment : Fragment() {
|
|||||||
//isTokenAvailable = true
|
//isTokenAvailable = true
|
||||||
// hemoCubeViewModel.startPeriodicCheckUpdate()
|
// hemoCubeViewModel.startPeriodicCheckUpdate()
|
||||||
}
|
}
|
||||||
} else if (userID == "deviceIDAPI" && password == "devicePasswordAPI" && deviceId.isNotEmpty()) {
|
} else if (userID == "" && password == "" && deviceId.isNotEmpty()) {
|
||||||
fetchDeviceCredentials()
|
fetchDeviceCredentials()
|
||||||
} else if (file.exists()) {
|
} else if (file.exists()) {
|
||||||
val encryptedString = file.readText()
|
val encryptedString = file.readText()
|
||||||
@@ -385,6 +385,12 @@ class HomeFragment : Fragment() {
|
|||||||
userID = credentials[0]
|
userID = credentials[0]
|
||||||
password = credentials[1]
|
password = credentials[1]
|
||||||
deviceId = credentials[0]
|
deviceId = credentials[0]
|
||||||
|
|
||||||
|
with(sharedPreference.edit()) {
|
||||||
|
putString(Constants.DEVICE_ID_API, credentials[0])
|
||||||
|
putString(Constants.DEVICE_PASSWORD_API, credentials[1])
|
||||||
|
apply()
|
||||||
|
}
|
||||||
// Toast.makeText(context, "DECRYPTED: $credentials", Toast.LENGTH_SHORT).show()
|
// Toast.makeText(context, "DECRYPTED: $credentials", Toast.LENGTH_SHORT).show()
|
||||||
if (!isTokenAvailable) {
|
if (!isTokenAvailable) {
|
||||||
callLogin(userID, password)
|
callLogin(userID, password)
|
||||||
@@ -506,6 +512,10 @@ class HomeFragment : Fragment() {
|
|||||||
when (response) {
|
when (response) {
|
||||||
is Result.Success -> {
|
is Result.Success -> {
|
||||||
val updatedversion = response.data.data?.version.toString()
|
val updatedversion = response.data.data?.version.toString()
|
||||||
|
with(sharedPreference.edit()) {
|
||||||
|
putString("version", response.data.data?.version)
|
||||||
|
apply()
|
||||||
|
}
|
||||||
val currentversion =
|
val currentversion =
|
||||||
context?.let { ctx ->
|
context?.let { ctx ->
|
||||||
val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
|
val packageInfo = ctx.packageManager.getPackageInfo(ctx.packageName, 0)
|
||||||
@@ -535,6 +545,7 @@ class HomeFragment : Fragment() {
|
|||||||
Toast.LENGTH_LONG
|
Toast.LENGTH_LONG
|
||||||
)
|
)
|
||||||
.show()
|
.show()
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Toast.makeText(
|
Toast.makeText(
|
||||||
activity,
|
activity,
|
||||||
|
|||||||
@@ -27,9 +27,12 @@ import android.view.ViewGroup
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.fragment.app.activityViewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import com.example.hpostesting.data.constant.Constants
|
import com.example.hpostesting.data.constant.Constants
|
||||||
import com.example.hpostesting.data.constant.DataHolder
|
import com.example.hpostesting.data.constant.DataHolder
|
||||||
|
import com.example.hpostesting.data.model.login.LoginRequest
|
||||||
|
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
|
||||||
import `in`.sminnovations.hpostesting.R
|
import `in`.sminnovations.hpostesting.R
|
||||||
import `in`.sminnovations.hpostesting.databinding.FragmentLoginBinding
|
import `in`.sminnovations.hpostesting.databinding.FragmentLoginBinding
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@@ -49,6 +52,7 @@ class LoginFragment : Fragment() {
|
|||||||
private var _binding: FragmentLoginBinding? = null
|
private var _binding: FragmentLoginBinding? = null
|
||||||
private val binding get() = _binding!!
|
private val binding get() = _binding!!
|
||||||
private lateinit var sharedPreference: SharedPreferences
|
private lateinit var sharedPreference: SharedPreferences
|
||||||
|
private val hemoCubeViewModel: HemoCubeViewModel by activityViewModels()
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater, container: ViewGroup?,
|
inflater: LayoutInflater, container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?,
|
savedInstanceState: Bundle?,
|
||||||
@@ -113,7 +117,9 @@ class LoginFragment : Fragment() {
|
|||||||
|
|
||||||
if (loginId.isNotBlank() && password.isNotBlank()) {
|
if (loginId.isNotBlank() && password.isNotBlank()) {
|
||||||
performLogin(loginId, password)
|
performLogin(loginId, password)
|
||||||
|
var Password = sharedPreference.getString(Constants.DEVICE_PASSWORD_API, "").toString()
|
||||||
|
var UserID = sharedPreference.getString(Constants.DEVICE_ID_API, "").toString()
|
||||||
|
hemoCubeViewModel.login(createLoginRequestData(UserID, Password))
|
||||||
} else {
|
} else {
|
||||||
if (loginId.isBlank()) {
|
if (loginId.isBlank()) {
|
||||||
binding.loginId.error = R.string.enter_proper_login_id.toString()
|
binding.loginId.error = R.string.enter_proper_login_id.toString()
|
||||||
@@ -124,7 +130,17 @@ class LoginFragment : Fragment() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private fun createLoginRequestData(userID: String, password: String): LoginRequest {
|
||||||
|
|
||||||
|
val pInfo = requireActivity().packageManager.getPackageInfo(
|
||||||
|
requireActivity().packageName, 0
|
||||||
|
)
|
||||||
|
val version = pInfo.versionName
|
||||||
|
var labname = sharedPreference.getString(Constants.LABNAME,"")
|
||||||
|
return LoginRequest(
|
||||||
|
password = password, serialNumber = userID, username = userID, version = version, lab = labname,location = DataHolder.ipAddress.toString()
|
||||||
|
)
|
||||||
|
}
|
||||||
private fun isUserLoggedIn(): Boolean {
|
private fun isUserLoggedIn(): Boolean {
|
||||||
return sharedPreference.getString(Constants.USER_ID, "")?.isNotBlank() == true
|
return sharedPreference.getString(Constants.USER_ID, "")?.isNotBlank() == true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
|
|||||||
import kotlinx.coroutines.CoroutineExceptionHandler
|
import kotlinx.coroutines.CoroutineExceptionHandler
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import okhttp3.Headers
|
||||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||||
import okhttp3.MultipartBody
|
import okhttp3.MultipartBody
|
||||||
import okhttp3.RequestBody.Companion.asRequestBody
|
import okhttp3.RequestBody.Companion.asRequestBody
|
||||||
@@ -93,7 +94,8 @@ class HemoCubeViewModel @Inject constructor(
|
|||||||
|
|
||||||
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
|
val checkUpdate = MutableLiveData<Result<CheckUpdateResponse>>()
|
||||||
|
|
||||||
val deviceUpdate = MutableLiveData<Result<ResponseBody>>()
|
val deviceUpdate = MutableLiveData<ResponseBody>()
|
||||||
|
val deviceUpdateheader = MutableLiveData<Headers>()
|
||||||
val downloadcertificate = MutableLiveData<Result<ResponseBody>>()
|
val downloadcertificate = MutableLiveData<Result<ResponseBody>>()
|
||||||
|
|
||||||
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
|
val uploadLogs = MutableLiveData<Result<UploadLogsResponse>?>()
|
||||||
@@ -259,9 +261,11 @@ class HemoCubeViewModel @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
|
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
|
||||||
deviceUpdate.postValue(Result.Loading())
|
//deviceUpdate.postValue(Result.Loading())
|
||||||
repository.deviceUpdate(deviceUpdateRequest).let {
|
repository.deviceUpdate(deviceUpdateRequest).let {
|
||||||
deviceUpdate.postValue(it)
|
deviceUpdate.postValue(it.body())
|
||||||
|
deviceUpdateheader.postValue(it.headers())
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ class TrueHemeViewModel @Inject constructor(
|
|||||||
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
|
fun deviceUpdate(deviceUpdateRequest: DeviceUpdateRequest) = viewModelScope.launch {
|
||||||
deviceUpdate.postValue(Result.Loading())
|
deviceUpdate.postValue(Result.Loading())
|
||||||
repository.deviceUpdate(deviceUpdateRequest).let {
|
repository.deviceUpdate(deviceUpdateRequest).let {
|
||||||
deviceUpdate.postValue(it)
|
// deviceUpdate.postValue(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user