diff --git a/app/apk/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt b/app/apk/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt index ec961670a..7b7324d18 100644 --- a/app/apk/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt +++ b/app/apk/src/main/java/com/topjohnwu/magisk/ui/install/InstallViewModel.kt @@ -14,9 +14,8 @@ import com.topjohnwu.magisk.BR import com.topjohnwu.magisk.R import com.topjohnwu.magisk.arch.BaseViewModel import com.topjohnwu.magisk.core.AppContext -import com.topjohnwu.magisk.core.BuildConfig +import com.topjohnwu.magisk.core.BuildConfig.APP_VERSION_CODE import com.topjohnwu.magisk.core.Config -import com.topjohnwu.magisk.core.Const import com.topjohnwu.magisk.core.Info import com.topjohnwu.magisk.core.base.ContentResultCallback import com.topjohnwu.magisk.core.ktx.toast @@ -70,17 +69,16 @@ class InstallViewModel(svc: NetworkService, markwon: Markwon) : BaseViewModel() init { viewModelScope.launch(Dispatchers.IO) { try { - val file = File(AppContext.cacheDir, "${BuildConfig.APP_VERSION_CODE}.md") - val text = when { - file.exists() -> file.readText() + val noteFile = File(AppContext.cacheDir, "${APP_VERSION_CODE}.md") + val noteText = when { + noteFile.exists() -> noteFile.readText() else -> { - val str = if (Const.APP_IS_CANARY) Info.update.note - else svc.fetchString(Const.Url.CHANGELOG_URL) - file.writeText(str) - str + val note = svc.fetchUpdate(APP_VERSION_CODE).note + noteFile.writeText(note) + note } } - val spanned = markwon.toMarkdown(text) + val spanned = markwon.toMarkdown(noteText) withContext(Dispatchers.Main) { notes = spanned } diff --git a/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt b/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt index 4b7136dc7..ea6f00eab 100644 --- a/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt +++ b/app/apk/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt @@ -151,15 +151,7 @@ object UpdateChannel : BaseSettingsItem.Selector() { } override val title = CoreR.string.settings_update_channel_title.asText() - override val entryRes = CoreR.array.update_channel - override fun entries(res: Resources): Array { - return super.entries(res).let { - if (!Const.APP_IS_CANARY && !BuildConfig.DEBUG) - it.copyOfRange(0, Config.Value.CANARY_CHANNEL) - else it - } - } } object UpdateChannelUrl : BaseSettingsItem.Input() { diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/Config.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/Config.kt index f5f929390..ca911597b 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/Config.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/Config.kt @@ -33,7 +33,7 @@ object Config : PreferenceConfig, DBConfig { const val SU_REAUTH = "su_reauth" const val SU_TAPJACK = "su_tapjack" const val CHECK_UPDATES = "check_update" - const val UPDATE_CHANNEL = "update_channel" + const val RELEASE_CHANNEL = "release_channel" const val CUSTOM_CHANNEL = "custom_channel" const val LOCALE = "locale" const val DARK_THEME = "dark_theme_extended" @@ -48,7 +48,7 @@ object Config : PreferenceConfig, DBConfig { SU_AUTO_RESPONSE, SU_REAUTH, SU_TAPJACK) } - object Value { + object OldValue { // Update channels const val DEFAULT_CHANNEL = -1 const val STABLE_CHANNEL = 0 @@ -56,6 +56,15 @@ object Config : PreferenceConfig, DBConfig { const val CUSTOM_CHANNEL = 2 const val CANARY_CHANNEL = 3 const val DEBUG_CHANNEL = 4 + } + + object Value { + // Update channels + const val DEFAULT_CHANNEL = -1 + const val STABLE_CHANNEL = 0 + const val BETA_CHANNEL = 1 + const val DEBUG_CHANNEL = 2 + const val CUSTOM_CHANNEL = 3 // root access mode const val ROOT_ACCESS_DISABLED = 0 @@ -86,14 +95,6 @@ object Config : PreferenceConfig, DBConfig { val TIMEOUT_LIST = longArrayOf(0, -1, 10, 20, 30, 60) } - private val defaultChannel = - if (BuildConfig.DEBUG) - Value.DEBUG_CHANNEL - else if (Const.APP_IS_CANARY) - Value.CANARY_CHANNEL - else - Value.DEFAULT_CHANNEL - @JvmField var keepVerity = false @JvmField var keepEnc = false @JvmField var recovery = false @@ -109,7 +110,7 @@ object Config : PreferenceConfig, DBConfig { private var checkUpdatePrefs by preference(Key.CHECK_UPDATES, true) private var localePrefs by preference(Key.LOCALE, "") var doh by preference(Key.DOH, false) - var updateChannel by preferenceStrInt(Key.UPDATE_CHANNEL, defaultChannel) + var updateChannel by preference(Key.RELEASE_CHANNEL, Value.DEFAULT_CHANNEL) var customChannelUrl by preference(Key.CUSTOM_CHANNEL, "") var downloadDir by preference(Key.DOWNLOAD_DIR, "") var randName by preference(Key.RAND_NAME, true) @@ -148,6 +149,7 @@ object Config : PreferenceConfig, DBConfig { var suTapjack by preference(Key.SU_TAPJACK, true) private const val SU_FINGERPRINT = "su_fingerprint" + private const val UPDATE_CHANNEL = "update_channel" fun toBundle(): Bundle { val map = prefs.all - Key.NO_MIGRATION @@ -183,17 +185,23 @@ object Config : PreferenceConfig, DBConfig { } prefs.edit { - // Settings migration + // Migrate su_fingerprint if (prefs.getBoolean(SU_FINGERPRINT, false)) suBiometric = true remove(SU_FINGERPRINT) - prefs.getString(Key.UPDATE_CHANNEL, null).also { - if (it == null || - it.toInt() > Value.DEBUG_CHANNEL || - it.toInt() < Value.DEFAULT_CHANNEL) { - putString(Key.UPDATE_CHANNEL, defaultChannel.toString()) + + // Migrate update_channel + prefs.getString(UPDATE_CHANNEL, null)?.let { + val channel = when (it.toInt()) { + OldValue.STABLE_CHANNEL -> Value.STABLE_CHANNEL + OldValue.CANARY_CHANNEL, OldValue.BETA_CHANNEL -> Value.BETA_CHANNEL + OldValue.DEBUG_CHANNEL -> Value.DEBUG_CHANNEL + OldValue.CUSTOM_CHANNEL -> Value.CUSTOM_CHANNEL + else -> Value.DEFAULT_CHANNEL } + putInt(Key.RELEASE_CHANNEL, channel) } + remove(UPDATE_CHANNEL) } } } diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/Const.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/Const.kt index c3eeef9fc..55814b407 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/Const.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/Const.kt @@ -21,18 +21,14 @@ object Const { // Misc val USER_ID = Process.myUid() / 100000 - val APP_IS_CANARY get() = Version.isCanary(APP_VERSION_CODE) object Version { const val MIN_VERSION = "v22.0" const val MIN_VERCODE = 22000 - fun atLeast_24_0() = Info.env.versionCode >= 24000 || isCanary() - fun atLeast_25_0() = Info.env.versionCode >= 25000 || isCanary() - fun atLeast_28_0() = Info.env.versionCode >= 28000 || isCanary() - fun isCanary() = isCanary(Info.env.versionCode) - - fun isCanary(ver: Int) = ver > 0 && ver % 100 != 0 + fun atLeast_24_0() = Info.env.versionCode >= 24000 + fun atLeast_25_0() = Info.env.versionCode >= 25000 + fun atLeast_28_0() = Info.env.versionCode >= 28000 } object ID { @@ -44,8 +40,6 @@ object Const { const val PATREON_URL = "https://www.patreon.com/topjohnwu" const val SOURCE_CODE_URL = "https://github.com/topjohnwu/Magisk" - const val CHANGELOG_URL = "https://topjohnwu.github.io/Magisk/releases/${APP_VERSION_CODE}.md" - const val GITHUB_API_URL = "https://api.github.com/" const val GITHUB_PAGE_URL = "https://topjohnwu.github.io/magisk-files/" const val INVALID_URL = "https://example.com/" diff --git a/app/core/src/main/java/com/topjohnwu/magisk/core/repository/NetworkService.kt b/app/core/src/main/java/com/topjohnwu/magisk/core/repository/NetworkService.kt index effd34dfe..183755f85 100644 --- a/app/core/src/main/java/com/topjohnwu/magisk/core/repository/NetworkService.kt +++ b/app/core/src/main/java/com/topjohnwu/magisk/core/repository/NetworkService.kt @@ -1,8 +1,8 @@ package com.topjohnwu.magisk.core.repository +import com.topjohnwu.magisk.core.BuildConfig import com.topjohnwu.magisk.core.Config import com.topjohnwu.magisk.core.Config.Value.BETA_CHANNEL -import com.topjohnwu.magisk.core.Config.Value.CANARY_CHANNEL import com.topjohnwu.magisk.core.Config.Value.CUSTOM_CHANNEL import com.topjohnwu.magisk.core.Config.Value.DEBUG_CHANNEL import com.topjohnwu.magisk.core.Config.Value.DEFAULT_CHANNEL @@ -24,21 +24,25 @@ class NetworkService( ) { suspend fun fetchUpdate() = safe { var info = when (Config.updateChannel) { - DEFAULT_CHANNEL, STABLE_CHANNEL -> fetchStableUpdate() + DEFAULT_CHANNEL -> if (BuildConfig.DEBUG) fetchDebugUpdate() else fetchStableUpdate() + STABLE_CHANNEL -> fetchStableUpdate() BETA_CHANNEL -> fetchBetaUpdate() - CANARY_CHANNEL -> fetchCanaryUpdate() DEBUG_CHANNEL -> fetchDebugUpdate() CUSTOM_CHANNEL -> fetchCustomUpdate(Config.customChannelUrl) else -> throw IllegalArgumentException() } if (info.versionCode < Info.env.versionCode && - Config.updateChannel == DEFAULT_CHANNEL) { + Config.updateChannel == DEFAULT_CHANNEL && + !BuildConfig.DEBUG + ) { Config.updateChannel = BETA_CHANNEL info = fetchBetaUpdate() } info } + suspend fun fetchUpdate(version: Int) = findRelease { it.versionCode == version }.asInfo() + // Keep going through all release pages until we find a match private suspend inline fun findRelease(predicate: (Release) -> Boolean): Release? { var page = 1 @@ -58,14 +62,13 @@ class NetworkService( } } - suspend fun fetchUpdate(version: Int) = findRelease { it.versionCode == version }?.asInfo() - - private inline fun Release.asInfo( + private inline fun Release?.asInfo( selector: (ReleaseAssets) -> Boolean = { // Default selector picks the non-debug APK it.name.run { endsWith(".apk") && !contains("debug") } }): UpdateInfo { - return if (tag[0] == 'v') asPublicInfo(selector) + return if (this == null) UpdateInfo() + else if (tag[0] == 'v') asPublicInfo(selector) else asCanaryInfo(selector) } @@ -89,20 +92,16 @@ class NetworkService( ) } - // Version number: canary == debug >= beta >= stable + // Version number: debug == beta >= stable // Find the latest non-prerelease private suspend fun fetchStableUpdate() = api.fetchLatestRelease().asInfo() - // Find the latest non-canary release - private suspend fun fetchBetaUpdate() = findRelease { it.tag[0] == 'v' }!!.asInfo() - // Find the latest release, regardless whether it's prerelease - private suspend fun fetchCanary() = findRelease { true }!! + private suspend fun fetchBetaUpdate() = findRelease { true }.asInfo() - private suspend fun fetchCanaryUpdate() = fetchCanary().asInfo() - - private suspend fun fetchDebugUpdate() = fetchCanary().asInfo { it.name == "app-debug.apk" } + private suspend fun fetchDebugUpdate() = + findRelease { true }.asInfo { it.name == "app-debug.apk" } private suspend fun fetchCustomUpdate(url: String): UpdateInfo { val info = raw.fetchUpdateJson(url).magisk diff --git a/app/core/src/main/res/values/arrays.xml b/app/core/src/main/res/values/arrays.xml index bcb4917cf..e64e4970c 100644 --- a/app/core/src/main/res/values/arrays.xml +++ b/app/core/src/main/res/values/arrays.xml @@ -63,9 +63,7 @@ @string/settings_update_stable @string/settings_update_beta + @string/settings_update_debug @string/settings_update_custom - Canary - Debug - diff --git a/app/core/src/main/res/values/strings.xml b/app/core/src/main/res/values/strings.xml index f384e52bd..74170bd69 100644 --- a/app/core/src/main/res/values/strings.xml +++ b/app/core/src/main/res/values/strings.xml @@ -139,6 +139,7 @@ Update Channel Stable Beta + Debug Custom Insert a custom channel URL Run parts of Magisk in the zygote daemon