Fix: Fixed the update manager to work when reloading app.

Signed-off-by: HeCodes2Much <wayne6324@gmail.com>
This commit is contained in:
HeCodes2Much
2024-07-04 16:48:20 +01:00
parent 239aff3920
commit 69dc514407
3 changed files with 181 additions and 164 deletions

View File

@@ -0,0 +1,173 @@
package com.github.droidworksstudio.launcher.helper
import android.app.DownloadManager
import android.content.*
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import android.util.Log
import androidx.annotation.RequiresApi
import androidx.core.content.FileProvider
import androidx.fragment.app.Fragment
import com.github.droidworksstudio.common.showLongToast
import com.github.droidworksstudio.launcher.BuildConfig
import com.github.droidworksstudio.launcher.utils.Constants
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import okhttp3.*
import org.json.JSONObject
import java.io.File
import java.io.IOException
class UpdateManagerHelper(private val fragment: Fragment) {
private val sharedPreferences by lazy {
fragment.requireContext().getSharedPreferences("update_prefs", Context.MODE_PRIVATE)
}
private val context = fragment.requireContext()
private val activity = fragment.requireActivity()
fun checkForUpdates() {
val currentVersion = BuildConfig.VERSION_NAME
val url = "https://api.github.com/repos/DroidWorksStudio/EasyLauncher/releases/latest"
val request = Request.Builder().url(url).build()
OkHttpClient().newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
// Handle the error
Log.e("UpdateManager", "Failed to check for updates", e)
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
val json = response.body()?.string()
val jsonObject = JSONObject(json.toString())
val tagName = jsonObject.getString("tag_name")
val latestVersion = tagName.replace("v", "")
val assets = jsonObject.getJSONArray("assets")
val apkUrl = (assets.get(1) as JSONObject).getString("browser_download_url")
Log.d("UpdateManager", "Latest version: $latestVersion | Current version: $currentVersion")
if (latestVersion > currentVersion) {
val declinedVersion = sharedPreferences.getString("declined_version", "")
Log.d("UpdateManager", "Declined version: $declinedVersion")
if (latestVersion != declinedVersion) {
// Ask the user if they want to update
activity.runOnUiThread {
showUpdateDialog(latestVersion, apkUrl)
}
}
}
}
}
})
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun showUpdateDialog(latestVersion: String, apkUrl: String) {
MaterialAlertDialogBuilder(context).apply {
setTitle("Update Available")
setMessage("A new version of the app is available. Do you want to update?")
setPositiveButton("Update") { _, _ ->
downloadApk(apkUrl)
}
setNegativeButton("Later") { _, _ ->
// Save the declined version
with(sharedPreferences.edit()) {
putString("declined_version", latestVersion)
apply()
}
}
setCancelable(false)
show()
}
}
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private fun downloadApk(apkUrl: String) {
val request = DownloadManager.Request(Uri.parse(apkUrl)).apply {
setTitle("Downloading update")
setDescription("Your app is downloading the latest update")
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "${Constants.PACKAGE_NAME}.apk")
}
val manager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadId = manager.enqueue(request)
// Register a BroadcastReceiver to listen for completion of the download
val onComplete = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {
val query = DownloadManager.Query().setFilterById(downloadId)
val cursor = manager.query(query)
if (cursor != null && cursor.moveToFirst()) {
val statusIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
if (statusIndex != -1) {
val status = cursor.getInt(statusIndex)
if (status == DownloadManager.STATUS_SUCCESSFUL) {
// Download completed successfully, now call installApk()
requestInstallPermission()
}
}
}
cursor?.close()
}
}
}
context.registerReceiver(onComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), Context.RECEIVER_NOT_EXPORTED)
}
private fun requestInstallPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!context.packageManager.canRequestPackageInstalls()) {
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
data = Uri.parse("package:${context.packageName}")
}
@Suppress("DEPRECATION")
fragment.startActivityForResult(intent, Constants.REQUEST_INSTALL_PERMISSION)
} else {
// Permission already granted, proceed with installation
installApk()
}
} else {
// For devices below Android Oreo, installation permission is granted by default
installApk()
}
}
private fun installApk() {
val apkFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "${Constants.PACKAGE_NAME}.apk")
val apkUri = FileProvider.getUriForFile(context.applicationContext, "${context.packageName}.provider", apkFile)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(intent)
}
@Deprecated("Deprecated in Java")
fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == Constants.REQUEST_INSTALL_PERMISSION) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val canInstallPackages = context.packageManager.canRequestPackageInstalls()
if (canInstallPackages) {
// Permission granted, proceed with installation
installApk()
} else {
// Permission still not granted, handle accordingly
context.applicationContext.showLongToast("Please allow install permission to install.")
}
}
}
}
}

View File

@@ -2,24 +2,17 @@ package com.github.droidworksstudio.launcher.ui.activities
import android.Manifest import android.Manifest
import android.annotation.SuppressLint import android.annotation.SuppressLint
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.content.SharedPreferences import android.content.SharedPreferences
import android.content.pm.ActivityInfo import android.content.pm.ActivityInfo
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.location.Location import android.location.Location
import android.location.LocationListener import android.location.LocationListener
import android.location.LocationManager import android.location.LocationManager
import android.net.Uri
import android.os.Build import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Environment
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.provider.Settings
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS import android.view.WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
@@ -29,7 +22,6 @@ import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.lifecycle.lifecycleScope import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.findNavController import androidx.navigation.findNavController
@@ -38,8 +30,6 @@ import androidx.navigation.ui.AppBarConfiguration
import androidx.navigation.ui.navigateUp import androidx.navigation.ui.navigateUp
import com.github.droidworksstudio.common.hasInternetPermission import com.github.droidworksstudio.common.hasInternetPermission
import com.github.droidworksstudio.common.isTablet import com.github.droidworksstudio.common.isTablet
import com.github.droidworksstudio.common.showLongToast
import com.github.droidworksstudio.launcher.BuildConfig
import com.github.droidworksstudio.launcher.R import com.github.droidworksstudio.launcher.R
import com.github.droidworksstudio.launcher.databinding.ActivityMainBinding import com.github.droidworksstudio.launcher.databinding.ActivityMainBinding
import com.github.droidworksstudio.launcher.helper.AppHelper import com.github.droidworksstudio.launcher.helper.AppHelper
@@ -47,17 +37,8 @@ import com.github.droidworksstudio.launcher.helper.PreferenceHelper
import com.github.droidworksstudio.launcher.utils.Constants import com.github.droidworksstudio.launcher.utils.Constants
import com.github.droidworksstudio.launcher.viewmodel.AppViewModel import com.github.droidworksstudio.launcher.viewmodel.AppViewModel
import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel import com.github.droidworksstudio.launcher.viewmodel.PreferenceViewModel
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import dagger.hilt.android.AndroidEntryPoint import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.JSONObject
import java.io.File
import java.io.IOException
import javax.inject.Inject import javax.inject.Inject
@@ -130,7 +111,6 @@ class MainActivity : AppCompatActivity(), LocationListener {
} }
handler.removeCallbacks(saveLocationRunnable) handler.removeCallbacks(saveLocationRunnable)
} }
} }
override fun onDestroy() { override fun onDestroy() {
@@ -282,7 +262,6 @@ class MainActivity : AppCompatActivity(), LocationListener {
backToHomeScreen() backToHomeScreen()
if (applicationContext.hasInternetPermission()) { if (applicationContext.hasInternetPermission()) {
checkLocationPermission() checkLocationPermission()
checkForUpdates()
} }
setupDataBase() setupDataBase()
observeUI() observeUI()
@@ -311,147 +290,4 @@ class MainActivity : AppCompatActivity(), LocationListener {
if (navController.currentDestination?.id != R.id.HomeFragment) if (navController.currentDestination?.id != R.id.HomeFragment)
navController.navigate(R.id.HomeFragment) navController.navigate(R.id.HomeFragment)
} }
private fun checkForUpdates() {
val currentVersion = BuildConfig.VERSION_NAME
val url = "https://api.github.com/repos/DroidWorksStudio/EasyLauncher/releases/latest"
val request = Request.Builder().url(url).build()
OkHttpClient().newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
// Handle the error
}
@SuppressLint("NewApi")
override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
val json = response.body()?.string()
val jsonObject = JSONObject(json.toString())
val tagName = jsonObject.getString("tag_name")
val latestVersion = tagName.replace("v", "")
val assets = jsonObject.getJSONArray("assets")
val apkUrl = (assets.get(1) as JSONObject).getString("browser_download_url")
if (latestVersion > currentVersion) {
val sharedPreferences = getSharedPreferences("update_prefs", Context.MODE_PRIVATE)
val declinedVersion = sharedPreferences.getString("declined_version", "")
if (latestVersion != declinedVersion) {
// Ask the user if they want to update
runOnUiThread {
showUpdateDialog(latestVersion, apkUrl)
}
}
}
}
}
})
}
@SuppressLint("NewApi")
fun showUpdateDialog(latestVersion: String, apkUrl: String) {
MaterialAlertDialogBuilder(this).apply {
setTitle("Update Available")
setMessage("A new version of the app is available. Do you want to update?")
setPositiveButton("Update") { _, _ ->
downloadApk(apkUrl)
}
setNegativeButton("Later") { _, _ ->
// Save the declined version
val sharedPreferences = getSharedPreferences("update_prefs", Context.MODE_PRIVATE)
with(sharedPreferences.edit()) {
putString("declined_version", latestVersion)
apply()
}
}
setCancelable(false)
show()
}
}
@SuppressLint("NewApi")
private fun downloadApk(apkUrl: String) {
val request = DownloadManager.Request(Uri.parse(apkUrl)).apply {
setTitle("Downloading update")
setDescription("Your app is downloading the latest update")
setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "${Constants.PACKAGE_NAME}.apk")
}
val manager = getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
val downloadId = manager.enqueue(request)
// Register a BroadcastReceiver to listen for completion of the download
val onComplete = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val action = intent.action
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE == action) {
val query = DownloadManager.Query().setFilterById(downloadId)
val cursor = manager.query(query)
if (cursor != null && cursor.moveToFirst()) {
val statusIndex = cursor.getColumnIndex(DownloadManager.COLUMN_STATUS)
if (statusIndex != -1) {
val status = cursor.getInt(statusIndex)
if (status == DownloadManager.STATUS_SUCCESSFUL) {
// Download completed successfully, now call installApk()
requestInstallPermission()
}
}
}
cursor?.close()
}
}
}
registerReceiver(onComplete, IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE), RECEIVER_EXPORTED)
}
private fun requestInstallPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!packageManager.canRequestPackageInstalls()) {
val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
data = Uri.parse("package:$packageName")
}
@Suppress("DEPRECATION")
startActivityForResult(intent, Constants.REQUEST_INSTALL_PERMISSION)
return
} else {
// Permission already granted, proceed with installation
installApk()
}
} else {
// For devices below Android Oreo, installation permission is granted by default
installApk()
}
}
private fun installApk() {
val apkFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "${Constants.PACKAGE_NAME}.apk")
val apkUri = FileProvider.getUriForFile(applicationContext, "$packageName.provider", apkFile)
val intent = Intent(Intent.ACTION_VIEW).apply {
setDataAndType(apkUri, "application/vnd.android.package-archive")
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(intent)
}
@Deprecated("Deprecated in Java")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == Constants.REQUEST_INSTALL_PERMISSION) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val canInstallPackages = packageManager.canRequestPackageInstalls()
if (canInstallPackages) {
// Permission granted, proceed with installation
installApk()
} else {
// Permission still not granted, handle accordingly
applicationContext.showLongToast("Please allow install permission to install.")
}
}
}
}
} }

View File

@@ -37,6 +37,7 @@ import com.github.droidworksstudio.launcher.databinding.FragmentHomeBinding
import com.github.droidworksstudio.launcher.helper.AppHelper import com.github.droidworksstudio.launcher.helper.AppHelper
import com.github.droidworksstudio.launcher.helper.FingerprintHelper import com.github.droidworksstudio.launcher.helper.FingerprintHelper
import com.github.droidworksstudio.launcher.helper.PreferenceHelper import com.github.droidworksstudio.launcher.helper.PreferenceHelper
import com.github.droidworksstudio.launcher.helper.UpdateManagerHelper
import com.github.droidworksstudio.launcher.listener.OnItemClickedListener import com.github.droidworksstudio.launcher.listener.OnItemClickedListener
import com.github.droidworksstudio.launcher.listener.OnSwipeTouchListener import com.github.droidworksstudio.launcher.listener.OnSwipeTouchListener
import com.github.droidworksstudio.launcher.listener.ScrollEventListener import com.github.droidworksstudio.launcher.listener.ScrollEventListener
@@ -73,6 +74,7 @@ class HomeFragment : Fragment(),
@Inject @Inject
lateinit var appHelper: AppHelper lateinit var appHelper: AppHelper
@Inject @Inject
lateinit var fingerHelper: FingerprintHelper lateinit var fingerHelper: FingerprintHelper
@@ -83,6 +85,7 @@ class HomeFragment : Fragment(),
private lateinit var batteryReceiver: BroadcastReceiver private lateinit var batteryReceiver: BroadcastReceiver
private lateinit var biometricPrompt: BiometricPrompt private lateinit var biometricPrompt: BiometricPrompt
private lateinit var updateManager: UpdateManagerHelper
private lateinit var context: Context private lateinit var context: Context
@@ -106,6 +109,9 @@ class HomeFragment : Fragment(),
setupRecyclerView() setupRecyclerView()
observeSwipeTouchListener() observeSwipeTouchListener()
observeUserInterfaceSettings() observeUserInterfaceSettings()
updateManager = UpdateManagerHelper(this)
updateManager.checkForUpdates()
} }
@SuppressLint("ClickableViewAccessibility") @SuppressLint("ClickableViewAccessibility")
@@ -479,6 +485,8 @@ class HomeFragment : Fragment(),
binding.nestScrollView.hideKeyboard() binding.nestScrollView.hideKeyboard()
observeUserInterfaceSettings() observeUserInterfaceSettings()
observeFavoriteAppList() observeFavoriteAppList()
updateManager.checkForUpdates()
} }
override fun onAppClicked(appInfo: AppInfo) { override fun onAppClicked(appInfo: AppInfo) {