Compare commits

...

8 Commits

Author SHA1 Message Date
Mariya
7ba0124f1a Issue fixed related to Toast 2024-01-05 18:24:36 +05:30
Mariya Varghese
f9b8df970d Merge branch 'preprod-temp' into 'preprod-temp-App-Updation'
# Conflicts:
#   app/src/main/java/com/example/hpostesting/presentation/dashboard/DashboardActivity.kt
2024-01-04 07:44:40 +00:00
Mariya
46d2c2f57b App update Issue fixed, its updated successfully within one app itself 2024-01-04 13:00:47 +05:30
Mariya
18ed6c4e11 App update using api added 2024-01-04 12:10:20 +05:30
Mariya
b0d348cf6d Implement - In app update after getting the new update link from check update response 2024-01-03 14:49:41 +05:30
Mariya
214a834740 Merge branch 'preprod-temp' into preprod-temp-App-Updation 2024-01-03 12:55:38 +05:30
Mariya
dfbcb4af6a error resolved 2024-01-03 12:52:28 +05:30
Mariya
ba45346fba Implement - In app update after getting the new update link from check update response 2024-01-02 17:09:22 +05:30
7 changed files with 183 additions and 13 deletions

View File

@@ -19,8 +19,8 @@ android {
applicationId "in.sminnovations.hpostesting" applicationId "in.sminnovations.hpostesting"
minSdk 21 minSdk 21
targetSdk 34 targetSdk 34
versionCode 56 versionCode 26
versionName "2.1.56" versionName "2.1.26"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
@@ -83,7 +83,7 @@ dependencies {
implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'androidx.preference:preference-ktx:1.2.1' implementation 'androidx.preference:preference-ktx:1.2.1'
implementation 'com.google.android.play:core:1.10.3' implementation 'com.google.android.play:core:1.10.3'
implementation 'io.nats:jnats:2.11.2'
@@ -139,4 +139,6 @@ dependencies {
implementation "androidx.preference:preference-ktx:1.2.1" implementation "androidx.preference:preference-ktx:1.2.1"
implementation 'io.nats:jnats:2.11.2' implementation 'io.nats:jnats:2.11.2'
implementation 'com.google.android.play:core:1.10.3'
} }

View File

@@ -5,6 +5,8 @@
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
<uses-permission <uses-permission
android:name="android.permission.BATTERY_STATS" android:name="android.permission.BATTERY_STATS"
tools:ignore="ProtectedPermissions" /> tools:ignore="ProtectedPermissions" />
@@ -62,7 +64,17 @@
android:exported="false" android:exported="false"
android:label="@string/title_activity_dashboard" android:label="@string/title_activity_dashboard"
android:theme="@style/Theme.HPOS.NoActionBar" android:theme="@style/Theme.HPOS.NoActionBar"
tools:ignore="MissingClass" /> tools:ignore="AppLinkUrlError,MissingClass">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="content" />
<data android:scheme="file" />
<data android:mimeType="application/vnd.android.package-archive" />
</intent-filter>
</activity>
<service <service
android:name="com.example.hpostesting.presentation.testRight.UsbService" android:name="com.example.hpostesting.presentation.testRight.UsbService"
@@ -114,6 +126,17 @@
android:screenOrientation="portrait" android:screenOrientation="portrait"
android:stateNotNeeded="true" android:stateNotNeeded="true"
tools:replace="android:screenOrientation" /> tools:replace="android:screenOrientation" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.example.hpostesting.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application> </application>
</manifest> </manifest>

View File

@@ -64,7 +64,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
if (batLevel < 40) { if (batLevel < 40) {
Toast.makeText( Toast.makeText(
view.context, view.context,
context?.getString(R.string.low_battery_warning), view.context.getString(R.string.low_battery_warning),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
return@setOnClickListener return@setOnClickListener
@@ -73,7 +73,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
if (userList.testStatus!!) { if (userList.testStatus!!) {
Toast.makeText( Toast.makeText(
view.context, view.context,
context?.getString(R.string.test_already_conducted), view.context.getString(R.string.test_already_conducted),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} else { } else {
@@ -81,13 +81,14 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) { if (isBetween15And30Minutes(userList.incubationTime) < Constants.INCUBATION_TIME_MIN) {
Toast.makeText( Toast.makeText(
view.context, view.context,
context?.getString(R.string.incubation_not_completed), view.context.getString(R.string.incubation_not_completed),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} else if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) { } else
if (isBetween15And30Minutes(userList.incubationTime) > Constants.INCUBATION_TIME_MAX) {
Toast.makeText( Toast.makeText(
view.context, view.context,
context?.getString(R.string.incubation_crossed_30_minutes), view.context.getString(R.string.incubation_crossed_30_minutes),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} else { } else {
@@ -102,7 +103,7 @@ class OfflineUserListAdapter(private val view: View, private val batLevel: Int)
} else { } else {
Toast.makeText( Toast.makeText(
view.context, view.context,
context?.getString(R.string.incubation_not_started), view.context.getString(R.string.incubation_not_started),
Toast.LENGTH_SHORT Toast.LENGTH_SHORT
).show() ).show()
} }

View File

@@ -1,32 +1,47 @@
package com.example.hpostesting.presentation.dashboard package com.example.hpostesting.presentation.dashboard
import android.app.DownloadManager
import android.content.BroadcastReceiver
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.net.Uri
import android.os.Bundle import android.os.Bundle
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.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.FileProvider
import androidx.drawerlayout.widget.DrawerLayout import androidx.drawerlayout.widget.DrawerLayout
import androidx.navigation.findNavController import androidx.navigation.findNavController
import androidx.navigation.ui.AppBarConfiguration import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp import androidx.navigation.ui.navigateUp
import androidx.navigation.ui.setupActionBarWithNavController import androidx.navigation.ui.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController import androidx.navigation.ui.setupWithNavController
import com.example.hpostesting.data.Result
import com.example.hpostesting.data.constant.LanguageManager import com.example.hpostesting.data.constant.LanguageManager
import com.example.hpostesting.presentation.hemocube.HemoCubeViewModel
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.google.android.play.core.appupdate.AppUpdateManager
import com.google.android.play.core.appupdate.AppUpdateManagerFactory
import com.google.firebase.appdistribution.FirebaseAppDistribution import com.google.firebase.appdistribution.FirebaseAppDistribution
import com.google.firebase.appdistribution.FirebaseAppDistributionException import com.google.firebase.appdistribution.FirebaseAppDistributionException
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
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.ActivityDashboardBinding import `in`.sminnovations.hpostesting.databinding.ActivityDashboardBinding
import okhttp3.ResponseBody
import java.io.File
@AndroidEntryPoint @AndroidEntryPoint
class DashboardActivity : AppCompatActivity() { class DashboardActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityDashboardBinding private lateinit var binding: ActivityDashboardBinding
private var downloadId: Long = 0
private val hemocubeViewModel: HemoCubeViewModel by viewModels()
override fun attachBaseContext(newBase: Context?) { override fun attachBaseContext(newBase: Context?) {
val languageCode = LanguageManager.getSavedLanguage(newBase!!) val languageCode = LanguageManager.getSavedLanguage(newBase!!)
LanguageManager.setLocale(newBase, languageCode) LanguageManager.setLocale(newBase, languageCode)
@@ -40,6 +55,42 @@ class DashboardActivity : AppCompatActivity() {
setContentView(binding.root) setContentView(binding.root)
setSupportActionBar(binding.appBarDashboard.toolbar) setSupportActionBar(binding.appBarDashboard.toolbar)
hemocubeViewModel.deviceUpdate.observe(this) { result ->
when (result) {
is Result.Success -> {
// Handle success
// val apkUrl = result.data
val apkUrl = "https://dl.dropboxusercontent.com/s/fi/1c3nn7t0co431hicl3hrt/app-debug.apk?rlkey=e4uf13ty1dpcked614vy1aaqp&dl=0"
initiateUpdate(apkUrl)
Log.d("ApI", "APK URL: $apkUrl")
Toast.makeText(
this,
"APK UPLOAD ${result.data}",
Toast.LENGTH_SHORT
).show()
// The APK URL LiveData will be updated automatically
}
is Result.Error -> {
result.exception.let { message ->
Toast.makeText(this, "An error occurred: $message", Toast.LENGTH_LONG)
.show()
}
}
is Result.Loading -> {
}
else -> {
}
}
}
val drawerLayout: DrawerLayout = binding.drawerLayout val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_dashboard) val navController = findNavController(R.id.nav_host_fragment_content_dashboard)
@@ -52,6 +103,8 @@ class DashboardActivity : AppCompatActivity() {
setupActionBarWithNavController(navController, appBarConfiguration) setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController) navView.setupWithNavController(navController)
} }
override fun onCreateOptionsMenu(menu: Menu): Boolean { override fun onCreateOptionsMenu(menu: Menu): Boolean {
@@ -65,6 +118,82 @@ class DashboardActivity : AppCompatActivity() {
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp() return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
} }
private fun initiateUpdate(responseBody: String) {
// Extract the URL from the ResponseBody
val apkUrl = responseBody
// Check if the extracted APK URL is valid
if (!isValidHttpUrl(apkUrl)) {
// Handle the case where the URL is not valid
return
}
val request = DownloadManager.Request(Uri.parse(apkUrl))
request.setTitle("App Update")
request.setDescription("Downloading update...")
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
request.setDestinationInExternalFilesDir(this, "Updates", "update.apk")
val downloadManager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
downloadId = downloadManager.enqueue(request)
// Register a BroadcastReceiver to receive the download complete event
val filter = IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
registerReceiver(downloadReceiver, filter)
}
// Function to check if a URL has a valid HTTP/HTTPS scheme
// Function to extract the APK URL from the ResponseBody
private fun extractApkUrl(responseBody: ResponseBody): String {
// Assuming your ResponseBody contains the APK URL as a string
return responseBody.string()
}
// Function to check if a URL has a valid HTTP/HTTPS scheme
private fun isValidHttpUrl(url: String): Boolean {
return url.startsWith("http://") || url.startsWith("https://")
}
private val downloadReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val id = intent?.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1)
if (id == downloadId) {
// Install the downloaded APK
installApk()
}
}
}
private fun installApk() {
val file = File(getExternalFilesDir("Updates"), "update.apk")
file.setReadable(true, false) // Ensure the file is readable
val uri: Uri = FileProvider.getUriForFile(
this,
"com.example.hpostesting.fileprovider",
file
)
// Create an intent to install the APK
val installIntent = Intent(Intent.ACTION_INSTALL_PACKAGE)
installIntent.data = uri
installIntent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or
Intent.FLAG_ACTIVITY_NEW_TASK or
Intent.FLAG_ACTIVITY_CLEAR_TOP
installIntent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true)
// Start the installation
startActivity(installIntent)
Log.d("InstallApk", "Install Intent URI: $uri")
Log.d("InstallApk", "Package Name: $packageName")
}
override fun onDestroy() {
super.onDestroy()
unregisterReceiver(downloadReceiver)
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
@@ -104,4 +233,7 @@ class DashboardActivity : AppCompatActivity() {
// Toast.makeText(this, "App Update: Success!", Toast.LENGTH_SHORT).show() // Toast.makeText(this, "App Update: Success!", Toast.LENGTH_SHORT).show()
} }
} }
} }

View File

@@ -24,6 +24,7 @@ import com.example.hpostesting.data.model.login.LoginResponse
import com.example.hpostesting.data.model.patient.HemoCubeTestData import com.example.hpostesting.data.model.patient.HemoCubeTestData
import com.example.hpostesting.data.model.patient.UserData import com.example.hpostesting.data.model.patient.UserData
import com.example.hpostesting.data.model.updates.CheckUpdateRequest import com.example.hpostesting.data.model.updates.CheckUpdateRequest
import com.example.hpostesting.data.model.updates.DeviceUpdateRequest
import com.example.hpostesting.presentation.KitScanActivity import com.example.hpostesting.presentation.KitScanActivity
import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter import com.example.hpostesting.presentation.adapter.OfflineUserListAdapter
import com.example.hpostesting.presentation.adapter.UserListAdapter import com.example.hpostesting.presentation.adapter.UserListAdapter
@@ -150,6 +151,7 @@ class HomeFragment : Fragment() {
} else { } else {
hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData()) hemoCubeViewModel.checkUpdate(createCheckUpdateRequestData())
hemoCubeViewModel.uploadLogs() hemoCubeViewModel.uploadLogs()
hemoCubeViewModel.deviceUpdate(createDeviceRequestData())
} }
} }
hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response -> hemoCubeViewModel.loginResponse.observe(viewLifecycleOwner) { response ->
@@ -260,6 +262,13 @@ class HomeFragment : Fragment() {
) )
} }
private fun createDeviceRequestData(): DeviceUpdateRequest {
return DeviceUpdateRequest(
serial_no = Constants.serialNumber
)
}
private fun setUserId() { private fun setUserId() {
binding.btnSubmit.setOnClickListener { binding.btnSubmit.setOnClickListener {
val userId = binding.userId.text.toString() val userId = binding.userId.text.toString()

View File

@@ -156,7 +156,7 @@ class HemoCubeViewModel @Inject constructor(
val logFile = logFileManager.createLogFile().let { file -> val logFile = logFileManager.createLogFile().let { file ->
val requestBody = file?.asRequestBody("multipart/form-data".toMediaTypeOrNull()) val requestBody = file?.asRequestBody("multipart/form-data".toMediaTypeOrNull())
val multipartFile = val multipartFile =
requestBody?.let { MultipartBody.Part.createFormData("logFile", file.name, it) } requestBody?.let { MultipartBody.Part.createFormData("logFile", file?.name, it) }
multipartFile?.let { partFile -> multipartFile?.let { partFile ->
databaseRepository.uploadLogs(partFile).let { result -> databaseRepository.uploadLogs(partFile).let { result ->
uploadLogs.postValue(result) uploadLogs.postValue(result)

View File

@@ -0,0 +1,3 @@
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-files-path name="Updates" path="." />
</paths>