Update install failures become visible: blocked, aborted, failed (D-155)
The PackageInstaller session's final status now reaches UpdateRepository: InstallResultReceiver hands it by session id to the waiting AndroidApkInstaller call (ApkInstaller.install returns a PendingInstall). installOutcome() maps STATUS_FAILURE_BLOCKED to UpdateFailure.Blocked, STATUS_FAILURE_ABORTED back to Available without an error, and every other failure to UpdateFailure.Install with the installer's EXTRA_STATUS_MESSAGE. The cached APK is deleted once the installer answers, so "Try again" downloads again. UpdateBanner's Failed variant shows the reason on S-4 and S-22; two core:design strings (en/sv) with their docs/ux/strings.csv rows. Unit tests for the mapping, the repository outcomes and the receiver; goldens: update_banner re-recorded, S-17-install-blocked, S-17-install-failed and s22_about_install_blocked new. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TQd3pEP9UeN2uifbHknQ7B
This commit is contained in:
@@ -127,6 +127,7 @@ import se.hagstedt.kvitt.model.ColorToken
|
||||
import se.hagstedt.kvitt.model.ExpenseEffect
|
||||
import se.hagstedt.kvitt.model.Share
|
||||
import se.hagstedt.kvitt.model.SplitMode
|
||||
import se.hagstedt.kvitt.model.UpdateFailure
|
||||
import se.hagstedt.kvitt.model.UpdateState
|
||||
import kotlinx.datetime.LocalDate
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -300,6 +301,8 @@ fun UpdateBannerSheet() {
|
||||
UpdateBanner(UpdateState.Available(Samples.update), online = false, {}, {}, {})
|
||||
UpdateBanner(UpdateState.Downloading(Samples.update, 0.64f), online = true, {}, {}, {})
|
||||
UpdateBanner(UpdateState.Failed(Samples.update), online = true, {}, {}, {})
|
||||
UpdateBanner(UpdateState.Failed(Samples.update, UpdateFailure.Blocked), online = true, {}, {}, {})
|
||||
UpdateBanner(UpdateState.Failed(Samples.update, UpdateFailure.Install(Samples.INSTALLER_MESSAGE)), online = true, {}, {}, {})
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
||||
@@ -102,6 +102,9 @@ object Samples {
|
||||
|
||||
val update = UpdateInfo(versionCode = 12, versionName = "1.2", sizeBytes = 8_400_000)
|
||||
|
||||
/** A real `EXTRA_STATUS_MESSAGE` of a signature mismatch (D-155). */
|
||||
const val INSTALLER_MESSAGE = "INSTALL_FAILED_UPDATE_INCOMPATIBLE: Existing package se.hagstedt.kvitt signatures do not match newer version; ignoring!"
|
||||
|
||||
val ratioShares = listOf(Share(jacob.id, 20_600, 5000), Share(anna.id, 20_600, 5000))
|
||||
val icaShares = listOf(Share(jacob.id, 62_380, 5000), Share(anna.id, 62_380, 5000))
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ import se.hagstedt.kvitt.design.format.RelativeTime
|
||||
import se.hagstedt.kvitt.design.icon.KvittIcon
|
||||
import se.hagstedt.kvitt.design.theme.KvittDimens
|
||||
import se.hagstedt.kvitt.model.SyncSummary
|
||||
import se.hagstedt.kvitt.model.UpdateFailure
|
||||
import se.hagstedt.kvitt.model.UpdateState
|
||||
import kotlin.time.Instant
|
||||
|
||||
@@ -184,7 +185,9 @@ fun Banner(
|
||||
|
||||
/**
|
||||
* The in-app update banner (design-spec §3.6, S-17): Available (Lantern, "Uppdatera" disabled offline with "Kräver
|
||||
* anslutning" as body), Downloading (progress, no actions), Failed (Error, "Försök igen"). NeedsInstallPermission looks
|
||||
* anslutning" as body), Downloading (progress, no actions), Failed (Error, "Försök igen"; the title and body follow the
|
||||
* reason, D-155: download, blocked by the phone's security settings, or another install failure with the installer's
|
||||
* own message). NeedsInstallPermission looks
|
||||
* like Available. Nothing for [UpdateState.None].
|
||||
*/
|
||||
@Composable
|
||||
@@ -226,9 +229,16 @@ fun UpdateBanner(state: UpdateState, online: Boolean, onUpdate: () -> Unit, onLa
|
||||
},
|
||||
)
|
||||
}
|
||||
is UpdateState.Failed -> Banner(BannerKind.Error, KvittIcon.Error, stringResource(R.string.update_failed), modifier) { content ->
|
||||
KvittButton(stringResource(R.string.update_later), onLater, kind = ButtonKind.Text, contentColor = content)
|
||||
KvittButton(stringResource(R.string.common_retry), onRetry, kind = ButtonKind.ErrorFilled, icon = KvittIcon.Refresh)
|
||||
is UpdateState.Failed -> {
|
||||
val (title, body) = when (val reason = state.reason) {
|
||||
UpdateFailure.Download -> stringResource(R.string.update_failed) to null
|
||||
UpdateFailure.Blocked -> stringResource(R.string.update_install_failed) to stringResource(R.string.update_install_blocked)
|
||||
is UpdateFailure.Install -> stringResource(R.string.update_install_failed) to reason.detail
|
||||
}
|
||||
Banner(BannerKind.Error, KvittIcon.Error, title, modifier, body = body) { content ->
|
||||
KvittButton(stringResource(R.string.update_later), onLater, kind = ButtonKind.Text, contentColor = content)
|
||||
KvittButton(stringResource(R.string.common_retry), onRetry, kind = ButtonKind.ErrorFilled, icon = KvittIcon.Refresh)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -328,6 +328,10 @@
|
||||
<string name="update_downloading_spoken">Laddar ner version %1$s</string>
|
||||
<!-- AC-16.4 -->
|
||||
<string name="update_failed">Nedladdningen misslyckades. Försök igen.</string>
|
||||
<!-- D-155: the installer refused or failed; the banner's body is the reason -->
|
||||
<string name="update_install_failed">Kunde inte installera uppdateringen</string>
|
||||
<!-- D-155: STATUS_FAILURE_BLOCKED (device policy or package verifier); Android's own setting names per locale -->
|
||||
<string name="update_install_blocked">Installationen blockerades av telefonens säkerhetsinställningar (Auto Blocker eller Installera okända appar). Ändra inställningen och försök igen.</string>
|
||||
<string name="update_permission_title">Tillåt installation</string>
|
||||
<!-- AC-16.3; bold the two Android setting names with <annotation>; Android's own labels per locale -->
|
||||
<string name="update_permission_body">Kvitt uppdateras direkt från er server, inte från Play Butik. Därför frågar Android en gång om Kvitt får <b>Installera okända appar</b>. Slå på <b>Tillåt från den här källan</b> och gå sedan tillbaka till Kvitt. Uppdateringen fortsätter av sig själv.</string>
|
||||
|
||||
@@ -330,6 +330,10 @@
|
||||
<string name="update_downloading_spoken">Downloading version %1$s</string>
|
||||
<!-- AC-16.4 -->
|
||||
<string name="update_failed">Download failed, try again</string>
|
||||
<!-- D-155: the installer refused or failed; the banner's body is the reason -->
|
||||
<string name="update_install_failed">Could not install the update</string>
|
||||
<!-- D-155: STATUS_FAILURE_BLOCKED (device policy or package verifier); Android's own setting names per locale -->
|
||||
<string name="update_install_blocked">The phone\'s security settings blocked the installation (Auto Blocker or Install unknown apps). Change the setting and try again.</string>
|
||||
<string name="update_permission_title">Allow installation</string>
|
||||
<!-- AC-16.3; bold the two Android setting names with <annotation>; Android's own labels per locale -->
|
||||
<string name="update_permission_body">Kvitt updates straight from your own server, not from the Play Store, so Android asks once whether Kvitt may <b>Install unknown apps</b>. Turn on <b>Allow from this source</b> and come back to Kvitt. The update continues by itself.</string>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 48 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 51 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 51 KiB |
Reference in New Issue
Block a user