A finished build keeps its notification, with an Install button on it

Handing an APK to the system installer means starting an activity, and
Android refuses one from the background: fired anyway it does nothing at
all, so a download that finished while the phone was in a pocket read as
an update that never landed. `updateComponent` now stops at
ReadyToInstall whenever this screen is not in front of anybody -- exactly
as it already did for the second APK of a project-wide update -- and that
state is drawn as a row of its own: no bar, dismissible, out of the
group, and carrying an Install action whose PendingIntent is the install
intent itself. An activity is the one press a notification may make from
any state.

Which is why the drawing moves from the service into WorkNotice: that
row outlives the last running thing, and something still alive has to
take it down. The list screen is that something. The service is now the
keep-alive and the one notification it is held up by, nothing else.

Two things had to be true for the row to come down again, and neither
was. continuePendingInstalls now begins by forgetting a download whose
install has already happened -- the installed copy's lastUpdateTime
against the downloaded file's mtime, rather than listening for an
install, since the same broadcast reports the removal the wrong-key case
is waiting for. Without it, pressing Install on the notification and then
returning to the app ran the whole install a second time; measured, not
feared. And registerPackageChangeReceiver dropped every arrival that was
an update: EXTRA_REPLACING marks the ADDED half of a replace and the
REPLACED that follows it, not only the REMOVED half the guard was written
for, so an in-place install reached nothing here until the screen next
resumed.

Verified on the emulator: Install pressed, app sent to the home screen,
build and download finish in the background, the row turns into
"Downloaded, waiting to install..." with the button, the service stops,
Install from the shade puts up the system installer, and the row goes
away by itself once the install lands -- with the app still in the
background, and with no second installer when it is opened again.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
iris-aiandClaude Opus 5 committed 2026-09-19 21:37:49 -04:00
1 parent ded6df559d
commit adaeb0c0ad
6 files changed
+449 -212

No files matched your search

+10 -5
View File
@@ -126,11 +126,16 @@ phone. Paths accept `~`, and are shown that way.
While anything is building, downloading or installing, the app keeps an
ongoing notification saying what is running and how far along it is — one
per thing, grouped together, each with its own build's count where the
command reports one. It is there to be watched, and it is also what keeps the work alive:
without it the app is an ordinary backgrounded process, and Android is
free to reclaim it partway through a build. It goes away by itself when
the last thing finishes. Refusing the notification permission costs the
watching and not the work.
command reports one. It is there to be watched, and it is also what keeps
the work alive: without it the app is an ordinary backgrounded process,
and Android is free to reclaim it partway through a build. Refusing the
notification permission costs the watching and not the work.
A build that finishes while you are somewhere else leaves its notification
up with an **Install** button on it, because Android will not let the app
put the installer on screen from the background. Pressing it installs, and
the notification goes away by itself — as the rest do when their work is
over.
### Updating this server itself