You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
143 lines
5.8 KiB
Kotlin
143 lines
5.8 KiB
Kotlin
/*
|
|
* Copyright (c) 2023 to present Androidacy and contributors. Names, logos, icons, and the Androidacy name are all trademarks of Androidacy and may not be used without license. See LICENSE for more information.
|
|
*/
|
|
|
|
package com.fox2code.mmm
|
|
|
|
import com.fox2code.mmm.androidacy.AndroidacyRepoData
|
|
import com.fox2code.mmm.utils.io.Files.Companion.write
|
|
import com.fox2code.mmm.utils.io.net.Http.Companion.doHttpGet
|
|
import org.json.JSONObject
|
|
import timber.log.Timber
|
|
import java.io.File
|
|
import java.io.FileInputStream
|
|
import java.io.IOException
|
|
import java.io.InputStream
|
|
|
|
@Suppress("unused")
|
|
class AppUpdateManager private constructor() {
|
|
var changes: String? = null
|
|
private val compatDataId = HashMap<String, Int>()
|
|
private val updateLock = Any()
|
|
private val compatFile: File = File(MainApplication.INSTANCE!!.filesDir, "compat.txt")
|
|
private var latestRelease: Int?
|
|
private var lastChecked: Long
|
|
|
|
init {
|
|
latestRelease = MainApplication.bootSharedPreferences
|
|
?.getInt("latest_vcode", BuildConfig.VERSION_CODE)
|
|
lastChecked = 0
|
|
if (compatFile.isFile) {
|
|
try {
|
|
parseCompatibilityFlags(FileInputStream(compatFile))
|
|
} catch (ignored: IOException) {
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return true if should show a notification
|
|
fun checkUpdate(force: Boolean): Boolean {
|
|
if (!BuildConfig.ENABLE_AUTO_UPDATER) return false
|
|
if (!force && peekShouldUpdate()) return true
|
|
val lastChecked = lastChecked
|
|
if (lastChecked != 0L && // Avoid spam calls by putting a 60 seconds timer
|
|
lastChecked < System.currentTimeMillis() - 60000L
|
|
) return force && peekShouldUpdate()
|
|
synchronized(updateLock) {
|
|
Timber.d("Checking for app updates")
|
|
if (lastChecked != this.lastChecked) return peekShouldUpdate()
|
|
// make a request to https://production-api.androidacy.com/amm/updates/check with appVersionCode and token/device_id/client_id
|
|
var token = AndroidacyRepoData.token
|
|
if (!AndroidacyRepoData.instance.isValidToken(token)) {
|
|
Timber.w("Invalid token, not checking for updates")
|
|
token = AndroidacyRepoData.instance.requestNewToken()
|
|
}
|
|
val deviceId = AndroidacyRepoData.generateDeviceId()
|
|
val clientId = BuildConfig.ANDROIDACY_CLIENT_ID
|
|
val url =
|
|
"https://production-api.androidacy.com/amm/updates/check?appVersionCode=${BuildConfig.VERSION_CODE}&token=$token&device_id=$deviceId&client_id=$clientId"
|
|
val response = doHttpGet(url, false)
|
|
// convert response to string
|
|
val responseString = String(response, Charsets.UTF_8)
|
|
Timber.d("Response: $responseString")
|
|
// json response has a boolean shouldUpdate and an int latestVersion
|
|
JSONObject(responseString).let {
|
|
if (it.getBoolean("shouldUpdate")) {
|
|
latestRelease = it.getInt("latestVersion")
|
|
MainApplication.bootSharedPreferences?.edit()
|
|
?.putInt("latest_vcode", latestRelease!!)?.apply()
|
|
}
|
|
this.changes = it.getString("changelog")
|
|
}
|
|
}
|
|
return peekShouldUpdate()
|
|
}
|
|
|
|
fun checkUpdateCompat() {
|
|
compatDataId.clear()
|
|
try {
|
|
write(compatFile, ByteArray(0))
|
|
} catch (e: IOException) {
|
|
Timber.e(e)
|
|
}
|
|
// There once lived an implementation that used a GitHub API to get the compatibility flags. It was removed because it was too slow and the API was rate limited.
|
|
Timber.w("Remote compatibility data flags are not implemented.")
|
|
}
|
|
|
|
fun peekShouldUpdate(): Boolean {
|
|
if (!BuildConfig.ENABLE_AUTO_UPDATER || BuildConfig.DEBUG) return false
|
|
// Convert both BuildConfig.VERSION_NAME and latestRelease to int
|
|
var currentVersion = 0
|
|
var latestVersion = 0
|
|
try {
|
|
currentVersion = BuildConfig.VERSION_CODE
|
|
latestVersion = latestRelease!!
|
|
} catch (ignored: NumberFormatException) {
|
|
}
|
|
return currentVersion < latestVersion
|
|
}
|
|
|
|
fun peekHasUpdate(): Boolean {
|
|
return if (!BuildConfig.ENABLE_AUTO_UPDATER || BuildConfig.DEBUG) false else peekShouldUpdate()
|
|
}
|
|
|
|
@Suppress("UNUSED_PARAMETER")
|
|
@Throws(IOException::class)
|
|
private fun parseCompatibilityFlags(inputStream: InputStream) {
|
|
compatDataId.clear()
|
|
Timber.d("Not implemented")
|
|
}
|
|
|
|
fun getCompatibilityFlags(moduleId: String): Int {
|
|
val compatFlags = compatDataId[moduleId]
|
|
return compatFlags ?: 0
|
|
}
|
|
|
|
@Suppress("MemberVisibilityCanBePrivate")
|
|
companion object {
|
|
const val FLAG_COMPAT_LOW_QUALITY = 0x0001
|
|
const val FLAG_COMPAT_NO_EXT = 0x0002
|
|
const val FLAG_COMPAT_MAGISK_CMD = 0x0004
|
|
const val FLAG_COMPAT_NEED_32BIT = 0x0008
|
|
const val FLAG_COMPAT_MALWARE = 0x0010
|
|
const val FLAG_COMPAT_NO_ANSI = 0x0020
|
|
const val FLAG_COMPAT_FORCE_ANSI = 0x0040
|
|
const val FLAG_COMPAT_FORCE_HIDE = 0x0080
|
|
const val FLAG_COMPAT_MMT_REBORN = 0x0100
|
|
const val FLAG_COMPAT_ZIP_WRAPPER = 0x0200
|
|
const val RELEASES_API_URL =
|
|
"https://api.github.com/repos/Androidacy/MagiskModuleManager/releases/latest"
|
|
val appUpdateManager = AppUpdateManager()
|
|
fun getFlagsForModule(moduleId: String): Int {
|
|
return appUpdateManager.getCompatibilityFlags(moduleId)
|
|
}
|
|
|
|
@JvmStatic
|
|
fun shouldForceHide(repoId: String): Boolean {
|
|
return if (BuildConfig.DEBUG || repoId.startsWith("repo_") || repoId == "magisk_alt_repo") false else !repoId.startsWith(
|
|
"repo_"
|
|
) && appUpdateManager.getCompatibilityFlags(repoId) and FLAG_COMPAT_FORCE_HIDE != 0
|
|
}
|
|
}
|
|
}
|