feat(PMInstaller): wait for uninstalls & fix PM session lifecycle bugs

- Support waiting for package uninstallation results
- Make DowngradeCheckStep wait for uninstall rather than erroring
- Relaunch PackageInstaller user action intents infinitely until result received (Workaround of bug on some ROMs where dismissing the PI dialog by clicking outside wouldn't invoke the callback with STATUS_FAILURE_ABORTED)
- Make PMIntentReceiver & PMResultReceiver non-exported to keep intents from leaking to other apps
- Handle uncaught exceptions thrown in the aforementioned receivers by returning the result back to the app (or logging) to prevent crashes
This commit is contained in:
rushiiMachine 2024-08-03 21:47:08 -07:00
parent 4ac24fe806
commit 2d3247e4b8
No known key found for this signature in database
GPG key ID: DCBE5952BB3B6420
44 changed files with 353 additions and 199 deletions

View file

@ -29,7 +29,9 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true">
<receiver android:name=".installers.pm.PMIntentReceiver" />
<receiver
android:name=".installers.pm.PMIntentReceiver"
android:exported="false" />
<provider
android:name="androidx.core.content.FileProvider"

View file

@ -7,16 +7,22 @@ import java.io.File
*/
interface Installer {
/**
* Starts an installation and forgets about it. A toast will be shown when the installation was completed.
* Starts an installation and forgets about it. A toast will be shown if the installation completes successfully.
* @param apks All APKs (including any splits) to merge into a single install.
* @param silent If this is an update, then the update will occur without user interaction.
*/
fun install(apks: List<File>, silent: Boolean = true)
/**
* Starts an installation and waits for it to finish with a result. A toast will be shown when the installation was completed.
* Starts an installation and waits for it to finish with a result. A toast will be shown for all result states.
* @param apks All APKs (including any splits) to merge into a single install.
* @param silent If this is an update, then the update will occur without user interaction.
*/
suspend fun waitInstall(apks: List<File>, silent: Boolean = true): InstallerResult
/**
* Triggers an uninstallation and waits for it to complete with a result. A toast will be shown for all result states.
* @param packageName The package name of the target package.
*/
suspend fun waitUninstall(packageName: String): InstallerResult
}

View file

@ -1,7 +1,7 @@
package com.aliucord.manager.installers
import android.content.Context
import android.os.Parcelable
import androidx.annotation.StringRes
import kotlinx.parcelize.Parcelize
/**
@ -26,16 +26,16 @@ sealed interface InstallerResult : Parcelable {
* This installation encountered an error and has been aborted.
* All implementors should implement [Parcelable].
*/
abstract class Error : InstallerResult {
abstract class Error : InstallerResult, Parcelable {
/**
* Loggable error that should not be shown to the user.
* The full internal error representation.
*/
abstract val debugReason: String
abstract fun getDebugReason(): String
/**
* Simplified + translatable user facing errors.
* Simplified + translatable user facing reason for the failure.
* If null is returned, then the [getDebugReason] will be used instead.
*/
@get:StringRes
abstract val localizedReason: Int
open fun getLocalizedReason(context: Context): String? = null
}
}

View file

@ -0,0 +1,14 @@
package com.aliucord.manager.installers
import android.content.Context
import com.aliucord.manager.R
import kotlinx.parcelize.Parcelize
@Parcelize
data class UnknownInstallerError(val error: Throwable) : InstallerResult.Error() {
override fun getDebugReason() = error.stackTraceToString()
// No localizations for exceptions, use short message anyway
override fun getLocalizedReason(context: Context) =
error.message ?: context.getString(R.string.install_error_unknown)
}

View file

@ -1,34 +1,34 @@
package com.aliucord.manager.installers.pm
import android.annotation.SuppressLint
import android.app.Application
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.*
import android.content.pm.PackageInstaller.SessionParams
import android.os.Build
import android.os.Process
import android.util.Log
import androidx.core.content.ContextCompat
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.installers.Installer
import com.aliucord.manager.installers.InstallerResult
import kotlinx.coroutines.suspendCancellableCoroutine
import com.aliucord.manager.util.isMiui
import kotlinx.coroutines.suspendCancellableCoroutine
import java.io.File
import kotlin.coroutines.resume
/**
* APK installer using the [PackageInstaller] from the system's [PackageManager] service.
*/
class PMInstaller(
val context: Context,
private val context: Application,
) : Installer {
init {
val pkgInstaller = context.packageManager.packageInstaller
private val _packageInstaller = context.packageManager.packageInstaller
// Destroy all open sessions that may have not been previously cleaned up
for (session in pkgInstaller.mySessions) {
Log.d(BuildConfig.TAG, "Deleting PackageInstaller session ${session.sessionId}")
pkgInstaller.abandonSession(session.sessionId)
init {
// Destroy all open sessions that may have not been previously cleaned up due to fatal errors
for (session in _packageInstaller.mySessions) {
Log.d(BuildConfig.TAG, "Deleting old PackageInstaller session ${session.sessionId}")
_packageInstaller.abandonSession(session.sessionId)
}
}
@ -36,29 +36,66 @@ class PMInstaller(
startInstall(createInstallSession(silent), apks, false)
}
override suspend fun waitInstall(apks: List<File>, silent: Boolean): InstallerResult {
override suspend fun waitInstall(apks: List<File>, silent: Boolean) = suspendCancellableCoroutine { continuation ->
// Create a new install session
val sessionId = createInstallSession(silent)
return suspendCancellableCoroutine { continuation ->
// This will receive parsed data forwarded by PMIntentReceiver
val relayReceiver = PMResultReceiver(sessionId, continuation)
// This will receive parsed data forwarded by PMIntentReceiver
val relayReceiver = PMResultReceiver(
sessionId = sessionId,
isUninstall = false,
onResult = { continuation.resume(it) },
)
// Unregister PMResultReceiver when this coroutine finishes
// additionally, cancel the install session entirely
continuation.invokeOnCancellation {
context.unregisterReceiver(relayReceiver)
context.packageManager.packageInstaller.abandonSession(sessionId)
}
ContextCompat.registerReceiver(
/* context = */ context,
/* receiver = */ relayReceiver,
/* filter = */ PMResultReceiver.intentFilter,
/* flags = */ ContextCompat.RECEIVER_NOT_EXPORTED,
)
@SuppressLint("UnspecifiedRegisterReceiverFlag")
if (Build.VERSION.SDK_INT >= 33) {
context.registerReceiver(relayReceiver, relayReceiver.filter, Context.RECEIVER_NOT_EXPORTED)
} else {
context.registerReceiver(relayReceiver, relayReceiver.filter)
}
startInstall(sessionId, apks, relay = true)
// Unregister PMResultReceiver when this coroutine finishes or error occurs
// Additionally, cancel the install session entirely
continuation.invokeOnCancellation { error ->
context.unregisterReceiver(relayReceiver)
context.packageManager.packageInstaller.abandonSession(sessionId)
}
startInstall(sessionId, apks, relay = true)
}
override suspend fun waitUninstall(packageName: String) = suspendCancellableCoroutine { continuation ->
val callbackIntent = Intent(context, PMIntentReceiver::class.java)
.putExtra(PMIntentReceiver.EXTRA_SESSION_ID, -1)
.putExtra(PMIntentReceiver.EXTRA_RELAY_ENABLED, true)
val pendingIntent = PendingIntent.getBroadcast(
/* context = */ context,
/* requestCode = */ 0,
/* intent = */ callbackIntent,
/* flags = */ PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
)
// This will receive parsed data forwarded by PMIntentReceiver
val relayReceiver = PMResultReceiver(
sessionId = -1,
isUninstall = true,
onResult = { continuation.resume(it) },
)
ContextCompat.registerReceiver(
/* context = */ context,
/* receiver = */ relayReceiver,
/* filter = */ PMResultReceiver.intentFilter,
/* flags = */ ContextCompat.RECEIVER_NOT_EXPORTED,
)
// Unregister PMResultReceiver when this coroutine is cancelled early
continuation.invokeOnCancellation { error ->
context.unregisterReceiver(relayReceiver)
}
_packageInstaller.uninstall(packageName, pendingIntent.intentSender)
}
/**
@ -70,13 +107,8 @@ class PMInstaller(
val params = SessionParams(SessionParams.MODE_FULL_INSTALL).apply {
setInstallLocation(PackageInfo.INSTALL_LOCATION_AUTO)
if (Build.VERSION.SDK_INT >= 24) {
setOriginatingUid(Process.myUid())
}
if (Build.VERSION.SDK_INT >= 26) {
setInstallReason(PackageManager.INSTALL_REASON_USER)
}
if (Build.VERSION.SDK_INT >= 24) setOriginatingUid(Process.myUid())
if (Build.VERSION.SDK_INT >= 26) setInstallReason(PackageManager.INSTALL_REASON_USER)
if (Build.VERSION.SDK_INT >= 31) {
setInstallScenario(PackageManager.INSTALL_SCENARIO_FAST)
@ -87,9 +119,7 @@ class PMInstaller(
}
}
if (Build.VERSION.SDK_INT >= 34) {
setPackageSource(PackageInstaller.PACKAGE_SOURCE_OTHER)
}
if (Build.VERSION.SDK_INT >= 34) setPackageSource(PackageInstaller.PACKAGE_SOURCE_OTHER)
}
return context.packageManager.packageInstaller.createSession(params)
@ -99,6 +129,7 @@ class PMInstaller(
* Start a [PackageInstaller] session for installation.
* @param apks The apks to install
* @param relay Whether to use the [PMResultReceiver] flow.
* @return The [PendingIntent] that was registered to the [PackageInstaller.Session]
*/
private fun startInstall(sessionId: Int, apks: List<File>, relay: Boolean) {
val callbackIntent = Intent(context, PMIntentReceiver::class.java)
@ -112,7 +143,7 @@ class PMInstaller(
/* flags = */ PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
)
context.packageManager.packageInstaller.openSession(sessionId).use { session ->
_packageInstaller.openSession(sessionId).use { session ->
val bufferSize = 1 * 1024 * 1024 // 1MiB
for (apk in apks) {

View file

@ -1,10 +1,10 @@
package com.aliucord.manager.installers.pm
import android.content.Context
import android.content.pm.PackageInstaller
import android.os.Parcelable
import com.aliucord.manager.R
import com.aliucord.manager.installers.InstallerResult
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize
/**
@ -13,8 +13,7 @@ import kotlinx.parcelize.Parcelize
*/
@Parcelize
data class PMInstallerError(val status: Int) : InstallerResult.Error(), Parcelable {
@IgnoredOnParcel
override val debugReason = when (status) {
override fun getDebugReason() = when (status) {
PackageInstaller.STATUS_FAILURE -> "Unknown failure"
PackageInstaller.STATUS_FAILURE_BLOCKED -> "Blocked"
PackageInstaller.STATUS_FAILURE_INVALID -> "Invalid package"
@ -25,15 +24,18 @@ data class PMInstallerError(val status: Int) : InstallerResult.Error(), Parcelab
else -> "Unknown code ($status)"
}
@IgnoredOnParcel
override val localizedReason = when (status) {
PackageInstaller.STATUS_FAILURE -> R.string.install_error_unknown
PackageInstaller.STATUS_FAILURE_BLOCKED -> R.string.install_error_blocked
PackageInstaller.STATUS_FAILURE_INVALID -> R.string.install_error_invalid
PackageInstaller.STATUS_FAILURE_CONFLICT -> R.string.install_error_conflict
PackageInstaller.STATUS_FAILURE_STORAGE -> R.string.install_error_storage
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> R.string.install_error_incompatible
/* PackageInstaller.STATUS_FAILURE_TIMEOUT */ 8 -> R.string.install_error_timeout
else -> R.string.install_error_unknown
override fun getLocalizedReason(context: Context): String {
val string = when (status) {
PackageInstaller.STATUS_FAILURE -> R.string.install_error_unknown
PackageInstaller.STATUS_FAILURE_BLOCKED -> R.string.install_error_blocked
PackageInstaller.STATUS_FAILURE_INVALID -> R.string.install_error_invalid
PackageInstaller.STATUS_FAILURE_CONFLICT -> R.string.install_error_conflict
PackageInstaller.STATUS_FAILURE_STORAGE -> R.string.install_error_storage
PackageInstaller.STATUS_FAILURE_INCOMPATIBLE -> R.string.install_error_incompatible
/* PackageInstaller.STATUS_FAILURE_TIMEOUT */ 8 -> R.string.install_error_timeout
else -> R.string.install_error_unknown
}
return context.getString(string)
}
}

View file

@ -1,66 +1,97 @@
package com.aliucord.manager.installers.pm
import android.app.PendingIntent
import android.content.*
import android.content.pm.PackageInstaller
import android.util.Log
import android.widget.Toast
import com.aliucord.manager.BuildConfig
import com.aliucord.manager.R
import com.aliucord.manager.installers.InstallerResult
import com.aliucord.manager.util.showToast
import com.aliucord.manager.installers.UnknownInstallerError
/**
* This class is used as a callback receiver for [PackageInstaller] events,
* registered as a [PendingIntent]. If [PMIntentReceiver.EXTRA_RELAY_ENABLED] is set to true on
* incoming intents, then the incoming intent will be parsed and relayed as an intent intended for [PMResultReceiver]
* that was registered dynamically with the correct session id, which will handle the relayed result and return
* it as a callback back to the application.
*/
class PMIntentReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
val realSessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1)
val expectedSessionId = intent.getIntExtra(EXTRA_SESSION_ID, -2)
val expectedSessionId = intent.getIntExtra(EXTRA_SESSION_ID, -1)
if (realSessionId != expectedSessionId) return
try {
handleSessionIntent(context, intent, expectedSessionId)
} catch (error: Throwable) {
if (intent.getBooleanExtra(EXTRA_RELAY_ENABLED, false)) {
val relayIntent = Intent(PMResultReceiver.ACTION_RECEIVE_RESULT)
.setPackage(BuildConfig.APPLICATION_ID)
.putExtra(PMResultReceiver.EXTRA_SESSION_ID, expectedSessionId)
.putExtra(PMResultReceiver.EXTRA_RESULT, UnknownInstallerError(error))
context.sendBroadcast(relayIntent)
} else {
Log.e(BuildConfig.TAG, "[PMIntentReceiver] Failed to handle intent", error)
}
}
}
private fun handleSessionIntent(context: Context, intent: Intent, sessionId: Int) {
val status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -999)
// Launch the user action intent and forward it to PMResultReceiver to keep relaunching it
if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) {
@Suppress("DEPRECATION")
val confirmationIntent = intent
.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)!!
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(confirmationIntent)
if (intent.getBooleanExtra(EXTRA_RELAY_ENABLED, false)) {
val relayIntent = Intent(PMResultReceiver.ACTION_RECEIVE_INTENT)
.setPackage(BuildConfig.APPLICATION_ID)
.putExtra(PMResultReceiver.EXTRA_SESSION_ID, sessionId)
.putExtra(PMResultReceiver.EXTRA_USER_ACTION_INTENT, confirmationIntent)
context.sendBroadcast(relayIntent)
}
return
}
// Handle install result
val installerResult = when (status) {
-999 -> {
// Invalid intent
null
}
PackageInstaller.STATUS_PENDING_USER_ACTION -> {
@Suppress("DEPRECATION")
val confirmationIntent = intent
.getParcelableExtra<Intent>(Intent.EXTRA_INTENT)!!
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context.startActivity(confirmationIntent)
null // no result yet
}
PackageInstaller.STATUS_SUCCESS -> {
context.showToast(R.string.installer_success)
InstallerResult.Success
}
PackageInstaller.STATUS_FAILURE_ABORTED -> {
context.showToast(R.string.installer_aborted)
InstallerResult.Cancelled(systemTriggered = true)
}
PackageInstaller.STATUS_SUCCESS -> InstallerResult.Success
PackageInstaller.STATUS_FAILURE_ABORTED -> InstallerResult.Cancelled(systemTriggered = true)
else -> {
Log.w(BuildConfig.TAG, "Install failed with error code $status")
Log.w(BuildConfig.TAG, "PM failed with error code $status")
if (status <= PackageInstaller.STATUS_SUCCESS)
null // Unknown status code (not an error)
else {
if (status <= PackageInstaller.STATUS_SUCCESS) {
// Unknown status code (not an error)
return
} else {
PMInstallerError(status).also {
context.showToast(it.localizedReason)
Toast.makeText(
/* context = */ context,
/* text = */ it.getLocalizedReason(context),
/* duration = */ Toast.LENGTH_LONG
).show()
}
}
}
}
// Forward result to PMResultReceiver if relaying is enabled and have a real result
if (installerResult != null && intent.getBooleanExtra(EXTRA_RELAY_ENABLED, false)) {
if (intent.getBooleanExtra(EXTRA_RELAY_ENABLED, false)) {
val relayIntent = Intent(PMResultReceiver.ACTION_RECEIVE_RESULT)
.setPackage(BuildConfig.APPLICATION_ID)
.putExtra(PMResultReceiver.EXTRA_SESSION_ID, sessionId)
.putExtra(PMResultReceiver.EXTRA_RESULT, installerResult)
.putExtra(PMResultReceiver.EXTRA_SESSION_ID, realSessionId)
context.sendBroadcast(relayIntent)
}

View file

@ -1,33 +1,102 @@
package com.aliucord.manager.installers.pm
import android.content.*
import android.content.pm.PackageInstaller
import com.aliucord.manager.R
import com.aliucord.manager.installers.InstallerResult
import kotlin.coroutines.Continuation
import kotlin.coroutines.resume
import com.aliucord.manager.installers.UnknownInstallerError
import com.aliucord.manager.util.showToast
import kotlinx.coroutines.*
import java.util.concurrent.atomic.AtomicBoolean
/**
* This receiver is meant to be registered dynamically in combination with [PMIntentReceiver] in order to
* relay parsed [PackageInstaller] results back to the running application.
* Additionally, it will handle restarting [PackageInstaller] user action intents infinitely until
* we have received a result from the system.
*/
class PMResultReceiver(
private val sessionId: Int,
private val continuation: Continuation<InstallerResult>,
private val isUninstall: Boolean,
private val onResult: (InstallerResult) -> Unit,
) : BroadcastReceiver() {
/**
* The intent filter this receiver should be registered with to work properly.
* Keep re-launching the user action intent until we have received a result from the PM.
* This is necessary because on some ROMs there is no callback intent sent when the user
* clicks outside of the package installer dialog, forcing us to keep relaunching the dialog
* until the user has clicked one of the buttons, after which the intent has been 'used up' and won't show anymore.
*/
val filter = IntentFilter(ACTION_RECEIVE_RESULT)
private val resultReceived = AtomicBoolean(false)
@Suppress("DEPRECATION")
override fun onReceive(context: Context, intent: Intent) {
if (intent.action != ACTION_RECEIVE_RESULT) return
if (intent.getIntExtra(EXTRA_SESSION_ID, -1) != sessionId) return
val result = intent.getParcelableExtra<InstallerResult>(EXTRA_RESULT)
try {
when (intent.action) {
ACTION_RECEIVE_INTENT -> handleIntent(context, intent)
ACTION_RECEIVE_RESULT -> handleResult(context, intent)
}
} catch (t: Throwable) {
resultReceived.set(true)
context.unregisterReceiver(this)
onResult(UnknownInstallerError(t))
}
}
private fun handleIntent(context: Context, intent: Intent) {
@Suppress("DEPRECATION")
val confirmationIntent = intent.getParcelableExtra<Intent>(EXTRA_USER_ACTION_INTENT)
?: return
continuation.resume(result)
// No result yet, keep relaunching user action intent
CoroutineScope(Dispatchers.Default).launch {
while (true) {
context.startActivity(confirmationIntent)
delay(1000)
if (resultReceived.get()) break
}
}
}
private fun handleResult(context: Context, intent: Intent) {
@Suppress("DEPRECATION")
val result = intent.getParcelableExtra<InstallerResult>(EXTRA_RESULT) ?: return
resultReceived.set(true)
// Show toast for successful and aborted sessions
when (result) {
InstallerResult.Success -> {
context.showToast(if (!isUninstall) R.string.installer_install_success else R.string.installer_uninstall_success)
}
// The reason we don't do this in PMIntentReceiver is we can't tell whether it was
// an old session that for which `abandonSession(...)` was called
is InstallerResult.Cancelled -> {
context.showToast(if (!isUninstall) R.string.installer_install_aborted else R.string.installer_uninstall_aborted)
}
else -> {}
}
context.unregisterReceiver(this)
onResult(result)
}
companion object {
const val ACTION_RECEIVE_INTENT = "com.aliucord.manager.RELAY_PM_INTENT"
const val ACTION_RECEIVE_RESULT = "com.aliucord.manager.RELAY_PM_RESULT"
const val EXTRA_RESULT = "installerResult"
const val EXTRA_SESSION_ID = "sessionId"
const val EXTRA_USER_ACTION_INTENT = "userActionIntent"
/**
* The intent filter this receiver should be registered with to work properly.
*/
val intentFilter = IntentFilter().apply {
addAction(ACTION_RECEIVE_INTENT)
addAction(ACTION_RECEIVE_RESULT)
}
}
}

View file

@ -75,7 +75,7 @@ class InstallStep(private val options: PatchOptions) : Step(), KoinComponent {
)
when (result) {
is InstallerResult.Error -> throw Error("Failed to install APKs: ${result.debugReason}")
is InstallerResult.Error -> throw Error("Failed to install APKs: ${result.getDebugReason()}")
is InstallerResult.Cancelled -> {
// The install screen is automatically closed immediately once cleanup finishes
state = StepState.Skipped

View file

@ -1,12 +1,14 @@
package com.aliucord.manager.patcher.steps.prepare
import android.content.Context
import android.content.pm.PackageManager.NameNotFoundException
import com.aliucord.manager.R
import com.aliucord.manager.installers.InstallerResult
import com.aliucord.manager.manager.InstallerManager
import com.aliucord.manager.patcher.StepRunner
import com.aliucord.manager.patcher.steps.StepGroup
import com.aliucord.manager.patcher.steps.base.Step
import com.aliucord.manager.patcher.steps.base.StepState
import com.aliucord.manager.patcher.util.uninstallApk
import com.aliucord.manager.ui.screens.patchopts.PatchOptions
import com.aliucord.manager.util.getPackageVersion
import com.aliucord.manager.util.showToast
@ -21,6 +23,7 @@ import org.koin.core.component.inject
*/
class DowngradeCheckStep(private val options: PatchOptions) : Step(), KoinComponent {
private val context: Context by inject()
private val installers: InstallerManager by inject()
override val group = StepGroup.Prepare
override val localizedName = R.string.patch_step_downgrade_check
@ -30,7 +33,7 @@ class DowngradeCheckStep(private val options: PatchOptions) : Step(), KoinCompon
context.getPackageVersion(options.packageName)
}
// Package is not installed
catch (_: Throwable) {
catch (_: NameNotFoundException) {
state = StepState.Skipped
return
}
@ -38,16 +41,25 @@ class DowngradeCheckStep(private val options: PatchOptions) : Step(), KoinCompon
val targetVersion = container
.getStep<FetchInfoStep>()
.data.versionCode.toIntOrNull()
?: throw IllegalArgumentException("Invalid fetched Aliucord target Discord version")
?: throw IllegalArgumentException("Invalid remote target Discord version")
if (currentVersion > targetVersion) {
context.uninstallApk(options.packageName)
withContext(Dispatchers.Main) {
context.showToast(R.string.installer_uninstall_new)
}
throw Error("Newer version of Aliucord must be uninstalled prior to installing an older version")
when (val result = installers.getActiveInstaller().waitUninstall(options.packageName)) {
is InstallerResult.Error -> throw Error("Failed to uninstall Aliucord: ${result.getDebugReason()}")
is InstallerResult.Cancelled -> {
withContext(Dispatchers.Main) {
context.showToast(R.string.installer_uninstall_new)
}
throw Error("Newer versions of Aliucord must be uninstalled prior to installing an older version")
}
else -> {}
}
}
}
}

View file

@ -1,15 +0,0 @@
package com.aliucord.manager.patcher.util
import android.content.Context
import android.content.Intent
import android.net.Uri
// TODO: move this to PMInstaller
fun Context.uninstallApk(packageName: String) {
val packageURI = Uri.parse("package:$packageName")
val uninstallIntent = Intent(Intent.ACTION_DELETE, packageURI).apply {
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
}
startActivity(uninstallIntent)
}

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Αποτυχία ανάκτησης έκδοσης</string>
<string name="installer_file_save_success">Αποθηκεύτηκε στο %s</string>
<string name="installer_file_save_failed">Απέτυχε η αποθήκευση στο %s</string>
<string name="installer_success">Επιτυχής εγκατάσταση του Aliucord</string>
<string name="installer_aborted">Εγκατάλειψη εγκατάστασης Aliucord</string>
<string name="installer_install_success">Επιτυχής εγκατάσταση του Aliucord</string>
<string name="installer_install_aborted">Εγκατάλειψη εγκατάστασης Aliucord</string>
<string name="installer_dl_verify_fail">Αποτυχία επαλήθευσης λήψης</string>
<string name="installer_uninstall_new">Παρακαλώ απεγκαταστήστε την τρέχουσα έκδοση του Aliucord σας για να συνεχίσετε!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Error al recuperar la versión</string>
<string name="installer_file_save_success">Guardado como %s</string>
<string name="installer_file_save_failed">Error al guardar %s</string>
<string name="installer_success">Aliucord instalado con éxito</string>
<string name="installer_aborted">Se abortó la instalación de Aliucord</string>
<string name="installer_install_success">Aliucord instalado con éxito</string>
<string name="installer_install_aborted">Se abortó la instalación de Aliucord</string>
<string name="installer_dl_verify_fail">Error al verificar la descarga</string>
<string name="installer_uninstall_new">¡Por favor, desinstala tu versión actual de Aliucord para continuar!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Échec de récupération de la version</string>
<string name="installer_file_save_success">Enregistré dans %s</string>
<string name="installer_file_save_failed">Échec de l\'enregistrement de %s</string>
<string name="installer_success">Aliucord installé avec succès</string>
<string name="installer_aborted">Installation d\'Aliucord interrompue</string>
<string name="installer_install_success">Aliucord installé avec succès</string>
<string name="installer_install_aborted">Installation d\'Aliucord interrompue</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Veuillez désinstaller votre version actuelle d\'Aliucord pour continuer !</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Gagal untuk mendapatkan versi</string>
<string name="installer_file_save_success">Disimpan di %s</string>
<string name="installer_file_save_failed">Gagal untuk menyimpan %s</string>
<string name="installer_success">Berhasil memasang Aliucord</string>
<string name="installer_aborted">Pemasangan Aliucord dibatalkan</string>
<string name="installer_install_success">Berhasil memasang Aliucord</string>
<string name="installer_install_aborted">Pemasangan Aliucord dibatalkan</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Silahkan copot versi Aliucord Anda saat ini untuk melanjutkan!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -70,8 +70,8 @@
<string name="version_load_fail">バージョンの取得に失敗しました</string>
<string name="installer_file_save_success">%sに保存しました</string>
<string name="installer_file_save_failed">%sの保存に失敗しました</string>
<string name="installer_success">Aliucordのインストールに成功しました</string>
<string name="installer_aborted">Aliucordのインストールが中断されました</string>
<string name="installer_install_success">Aliucordのインストールに成功しました</string>
<string name="installer_install_aborted">Aliucordのインストールが中断されました</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">続行するには現在のバージョンのAliucordをアンインストールしてください!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Aliucord tabıslı ornatıldı</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Aliucord tabıslı ornatıldı</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">버전을 가져오지 못했어요</string>
<string name="installer_file_save_success">%s에 저장했어요</string>
<string name="installer_file_save_failed">%s을(를) 저장하지 못했어요</string>
<string name="installer_success">Aliucord 설치를 완료했어요</string>
<string name="installer_aborted">Aliucord 설치를 중단했어요</string>
<string name="installer_install_success">Aliucord 설치를 완료했어요</string>
<string name="installer_install_aborted">Aliucord 설치를 중단했어요</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">계속하려면 Aliucord의 현재 버전을 설치 삭제해 주세요!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Nie można pobrać wersji</string>
<string name="installer_file_save_success">Zapisano do %s</string>
<string name="installer_file_save_failed">Nie można zapisać %s</string>
<string name="installer_success">Pomyślnie zainstalowano Aliucord</string>
<string name="installer_aborted">Przerwano instalację Aliucord</string>
<string name="installer_install_success">Pomyślnie zainstalowano Aliucord</string>
<string name="installer_install_aborted">Przerwano instalację Aliucord</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Odinstaluj aktualną wersję Aliucorda, aby kontynuować!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Falha ao obter versão</string>
<string name="installer_file_save_success">Salvo em %s</string>
<string name="installer_file_save_failed">Falha ao salvar %s</string>
<string name="installer_success">Aliucord instalado com sucesso</string>
<string name="installer_aborted">Instalação do Aliucord abortada</string>
<string name="installer_install_success">Aliucord instalado com sucesso</string>
<string name="installer_install_aborted">Instalação do Aliucord abortada</string>
<string name="installer_dl_verify_fail">Falha ao verificar o download</string>
<string name="installer_uninstall_new">Por favor, desinstale a versão atual do Aliucord para continuar!</string>
<string name="installer_minimization_warning">Uma vez que as otimizações da bateria não foram desativadas, minimizar esta tela poderá abortar o processo de instalação!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Falha ao recuperar versão</string>
<string name="installer_file_save_success">Guardado em %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">O Aliucord foi instalado com sucesso</string>
<string name="installer_aborted">Abortar a instalação de Aliucord</string>
<string name="installer_install_success">O Aliucord foi instalado com sucesso</string>
<string name="installer_install_aborted">Abortar a instalação de Aliucord</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Por favor, desinstale a versão atual do Aliucord de modo a continuar o processo!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Не удалось получить версию</string>
<string name="installer_file_save_success">Сохранено в %s</string>
<string name="installer_file_save_failed">Не удалось сохранить в %s</string>
<string name="installer_success">Aliucord успешно установлен</string>
<string name="installer_aborted">Установка Aliucord отменена</string>
<string name="installer_install_success">Aliucord успешно установлен</string>
<string name="installer_install_aborted">Установка Aliucord отменена</string>
<string name="installer_dl_verify_fail">Не удалось верифицировать скачивание</string>
<string name="installer_uninstall_new">Пожалуйста, удалите вашу текущую версию Aliucord, чтобы продолжить!</string>
<string name="installer_minimization_warning">Поскольку оптимизация работы аккумулятора не была отключена, сворачивание этого экрана может прервать процесс установки!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Sürüm alınamadı</string>
<string name="installer_file_save_success">%s\'a Kaydedildi</string>
<string name="installer_file_save_failed">%s Kaydedilemedi</string>
<string name="installer_success">Aliucord başarıyla indirildi</string>
<string name="installer_aborted">Aliucord kurulumu iptal edildi</string>
<string name="installer_install_success">Aliucord başarıyla indirildi</string>
<string name="installer_install_aborted">Aliucord kurulumu iptal edildi</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Devam etmek için şimdiki Aliucord sürümünüzü
lütfen silin!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Failed to retrieve version</string>
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Aborted Aliucord installation</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Aborted Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">Không truy xuất được phiên bản</string>
<string name="installer_file_save_success">Đã lưu vào %s</string>
<string name="installer_file_save_failed">Lưu trữ thất bại %s</string>
<string name="installer_success">Aliucord đã được cài đặt thành công</string>
<string name="installer_aborted">Đã hủy bỏ cài đặt Aliucord</string>
<string name="installer_install_success">Aliucord đã được cài đặt thành công</string>
<string name="installer_install_aborted">Đã hủy bỏ cài đặt Aliucord</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">Vui lòng gỡ cài đặt phiên bản Aliucord hiện tại của bạn để tiếp tục!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">獲得版本失敗</string>
<string name="installer_file_save_success">儲存到 %s</string>
<string name="installer_file_save_failed">儲存到 %s 失敗</string>
<string name="installer_success">成功地安裝 Aliucord</string>
<string name="installer_aborted">中斷 Aliucord 安裝</string>
<string name="installer_install_success">成功地安裝 Aliucord</string>
<string name="installer_install_aborted">中斷 Aliucord 安裝</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">請解除安裝目前版本的 Aliucord 以繼續!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -69,8 +69,8 @@
<string name="version_load_fail">獲得版本失敗</string>
<string name="installer_file_save_success">儲存到 %s</string>
<string name="installer_file_save_failed">儲存到 %s 失敗</string>
<string name="installer_success">成功地安裝 Aliucord</string>
<string name="installer_aborted">中斷 Aliucord 安裝</string>
<string name="installer_install_success">成功地安裝 Aliucord</string>
<string name="installer_install_aborted">中斷 Aliucord 安裝</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_uninstall_new">請解除安裝目前版本的 Aliucord 以繼續!</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>

View file

@ -80,19 +80,21 @@
<string name="installer_file_save_success">Saved to %s</string>
<string name="installer_file_save_failed">Failed to save %s</string>
<string name="installer_success">Successfully installed Aliucord</string>
<string name="installer_aborted">Cancelled Aliucord installation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_install_success">Successfully installed Aliucord</string>
<string name="installer_install_aborted">Cancelled Aliucord installation</string>
<string name="installer_uninstall_new">Please uninstall your current version of Aliucord in order to continue!</string>
<string name="installer_uninstall_success">Successfully uninstalled Aliucord</string>
<string name="installer_uninstall_aborted">Cancelled uninstallation</string>
<string name="installer_dl_verify_fail">Failed to verify download</string>
<string name="installer_minimization_warning">Since battery optimizations have not been disabled, minimizing this screen may abort the installation process!</string>
<string name="install_error_unknown">Failed to install (Unknown reason)</string>
<string name="install_error_unknown">Installer failure (Unknown reason)</string>
<string name="install_error_blocked">Installation was blocked</string>
<string name="install_error_invalid">One or more APKs were invalid or corrupt</string>
<string name="install_error_conflict">Conflicts with an existing app, usually due to mismatched signatures</string>
<string name="install_error_storage">Not enough available storage to install</string>
<string name="install_error_incompatible">Application is incompatible with this device</string>
<string name="install_error_timeout">Installation timed out</string>
<string name="install_error_timeout">Installer timed out</string>
<string name="install_group_prepare">Prepare</string>
<string name="install_group_download">Download dependencies</string>
@ -100,7 +102,7 @@
<string name="install_group_install">Install APK</string>
<string name="patch_step_fetch_kt_version">Fetching target Discord version</string>
<string name="patch_step_downgrade_check">Checking for older installations</string>
<string name="patch_step_downgrade_check">Checking for newer installations</string>
<string name="patch_step_dl_kt_apk">Downloading Discord APK</string>
<string name="patch_step_dl_kotlin">Downloading Kotlin Stdlib</string>
<string name="patch_step_dl_injector">Downloading Aliucord Injector</string>