Files
Escape-penacony-standalone/app/src/main/java/com/catlas/escapepenacony/data/UpdateManager.kt
T

184 lines
6.9 KiB
Kotlin

package com.catlas.escapepenacony.data
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.os.Environment
import android.provider.Settings
import androidx.core.content.FileProvider
import com.catlas.escapepenacony.BuildConfig
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import org.json.JSONObject
import java.io.File
import java.io.FileOutputStream
import java.net.HttpURLConnection
import java.net.URL
data class ReleaseInfo(
val tagName: String,
val releaseTitle: String,
val changelog: String,
val apkDownloadUrl: String,
val isNewer: Boolean
)
object UpdateManager {
private const val GITHUB_RELEASES_API =
"https://api.github.com/repos/CAtlas0784/Escape-penacony/releases/latest"
private const val GITHUB_RAW_SCENES_URL =
"https://raw.githubusercontent.com/CAtlas0784/Escape-penacony/main/scenes.json"
suspend fun checkForAppUpdate(currentVersion: String = BuildConfig.VERSION_NAME): Result<ReleaseInfo?> =
withContext(Dispatchers.IO) {
try {
val url = URL(GITHUB_RELEASES_API)
val conn = url.openConnection() as HttpURLConnection
conn.connectTimeout = 8000
conn.readTimeout = 8000
conn.setRequestProperty("Accept", "application/vnd.github.v3+json")
conn.setRequestProperty("User-Agent", "Escape-Penacony-Android-App")
if (conn.responseCode == 200) {
val body = conn.inputStream.bufferedReader().use { it.readText() }
val json = JSONObject(body)
val tagName = json.getString("tag_name")
val title = json.optString("name", tagName)
val changelog = json.optString("body", "No changelog provided.")
var downloadUrl = ""
val assets = json.optJSONArray("assets")
if (assets != null) {
for (i in 0 until assets.length()) {
val asset = assets.getJSONObject(i)
val name = asset.optString("name", "")
if (name.endsWith(".apk", ignoreCase = true)) {
downloadUrl = asset.getString("browser_download_url")
break
}
}
}
val isNewer = isNewerVersion(currentVersion, tagName)
Result.success(
ReleaseInfo(
tagName = tagName,
releaseTitle = title,
changelog = changelog,
apkDownloadUrl = downloadUrl,
isNewer = isNewer
)
)
} else {
Result.success(null)
}
} catch (e: Exception) {
e.printStackTrace()
Result.failure(e)
}
}
suspend fun downloadApk(
context: Context,
downloadUrl: String,
onProgress: (Int) -> Unit
): Result<File> = withContext(Dispatchers.IO) {
try {
val url = URL(downloadUrl)
val conn = url.openConnection() as HttpURLConnection
conn.connectTimeout = 15000
conn.readTimeout = 15000
conn.setRequestProperty("User-Agent", "Escape-Penacony-Android-App")
val fileLength = conn.contentLength
val dir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS) ?: context.filesDir
val apkFile = File(dir, "Escape-penacony-update.apk")
conn.inputStream.use { input ->
FileOutputStream(apkFile).use { output ->
val buffer = ByteArray(8 * 1024)
var total: Long = 0
var count: Int
while (input.read(buffer).also { count = it } != -1) {
total += count
if (fileLength > 0) {
val progress = ((total * 100) / fileLength).toInt()
withContext(Dispatchers.Main) {
onProgress(progress)
}
}
output.write(buffer, 0, count)
}
}
}
Result.success(apkFile)
} catch (e: Exception) {
e.printStackTrace()
Result.failure(e)
}
}
fun promptInstallApk(context: Context, apkFile: File) {
// Android 8.0+ Check Unknown App Sources permission
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
if (!context.packageManager.canRequestPackageInstalls()) {
val settingsIntent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES).apply {
data = Uri.parse("package:${context.packageName}")
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
context.startActivity(settingsIntent)
return
}
}
val apkUri: Uri = FileProvider.getUriForFile(
context,
"${context.packageName}.fileprovider",
apkFile
)
val installIntent = 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(installIntent)
}
suspend fun fetchLatestScenesJson(): Result<String> = withContext(Dispatchers.IO) {
try {
val url = URL(GITHUB_RAW_SCENES_URL)
val conn = url.openConnection() as HttpURLConnection
conn.connectTimeout = 8000
conn.readTimeout = 8000
conn.setRequestProperty("User-Agent", "Escape-Penacony-Android-App")
if (conn.responseCode == 200) {
val content = conn.inputStream.bufferedReader().use { it.readText() }
Result.success(content)
} else {
Result.failure(Exception("HTTP error ${conn.responseCode}"))
}
} catch (e: Exception) {
Result.failure(e)
}
}
private fun isNewerVersion(current: String, latest: String): Boolean {
val c = current.removePrefix("v").split(".").map { it.toIntOrNull() ?: 0 }
val l = latest.removePrefix("v").split(".").map { it.toIntOrNull() ?: 0 }
val maxLen = maxOf(c.size, l.size)
for (i in 0 until maxLen) {
val cv = c.getOrElse(i) { 0 }
val lv = l.getOrElse(i) { 0 }
if (lv > cv) return true
if (lv < cv) return false
}
return false
}
}