Skip to content

Releases: gi-os/BrightSports

LightSports v1.24.38

Choose a tag to compare

@github-actions github-actions released this 28 Aug 01:57

Scores were still landing ten minutes late with the live ticker shipped, switched on, and working
perfectly whenever anyone looked at it. That last part is the whole bug.

An inexact alarm cannot start a foreground service. There are two ways this app checks a score:
the alarm chain, which survives Doze and is throttled to roughly one firing every nine minutes, and
the live ticker, which is not throttled and checks every thirty to sixty seconds. The alarm chain is
what hands over to the ticker when a followed game starts. Android 12 onwards refuses a foreground
service started from the background — unless the broadcast that started it came from an exact
alarm. This app used the inexact variant, deliberately, because it needs no permission.

So the handover was refused every time the phone was asleep. Which is the only phone the ticker was
ever written for. Open the app during a game and the ticker came straight up, because a visible
activity is allowed to start one; put the phone in a pocket and it never ran at all. The app had two
speeds and reached the fast one exactly when you were already looking at the score.

Alarms are exact now. Not for the precision — both variants sit under the same nine-minute Doze
floor and nothing about the schedule changes. It is for the exemption that comes with them. The
permission is granted at install and asks the user nothing.

And a refusal was making things slower, not merely not faster. When the service could not go
foreground it stopped itself, and stopping is what arms the next alarm — from a field that was still
zero, which means the fifteen-minute backstop. So every poll that found a live game pushed the next
one from two minutes out to fifteen, over and over, for the length of the game. A refused fast path
was actively degrading the slow one. It hands back at two minutes now.

Settings can finally answer "why was that late". A new Delivery section says which of the two
paths ran last and how long ago — Live — every 30–60s or Alarms — up to 9 min — and, underneath,
what is standing in the way if anything is. None of this was visible before: a refusal was one line
in a logcat nobody has attached to a phone in their pocket.

Battery optimisation is one tap. An app the phone has stopped putting to sleep is not in Doze at
all, so the nine-minute floor stops existing and the alarm chain runs at its stated two minutes even
if the ticker never comes up. Optional, asked for from Settings and never at launch. If LightOS
opens nothing, the row gives you the adb line.

Worth checking while you are in there: the spoiler delay is on by default at five minutes, and it
is added to everything above.

Full Changelog: v1.23.37...v1.24.38

LightSports v1.23.37

Choose a tag to compare

@github-actions github-actions released this 26 Aug 22:02

Two reports, one cause: a score from yesterday still on the lock screen, and two cards for the
same match — the score, and a "starting soon" sitting next to it.

The removal was scheduled on the full-time whistle, and only if the phone saw it. A card got a
removal time on the one poll where the game went from live to final. Miss that poll — asleep, in
Doze, out of signal — and nothing ever wrote one: once the game rolled out of the scoreboard
window its snapshot went too, so the transition could never be observed again, and the card sat
there indefinitely. A Phillies game from the day before is exactly that.

The clock now starts when a card is posted, which needs no transition to be caught. Every later
card for the same game pushes it out, and so does the game still being in progress — so a quiet
second half never loses the score, and the rule ends up being the simple one: an hour after the
last thing worth saying.

And the shade is now a second source of truth. Anything in it that nothing is tracking and that
is over an hour old gets cleared. That is what removes the cards already stuck on your phone, which
no amount of new tracking would have reached. The live ticker's own card is excluded — it is the
receipt for a running service, not news.

"Starting soon" goes at kickoff. It had no way to leave: with a league set to final-only there
is no later card to replace it, so it stayed in the shade beside the score for the whole game and
read as two notifications about one match. It is dropped the moment the game goes live.

And it is never posted late. Being due and being still true are different questions, and a
phone that was asleep is the gap between them — a "starts in 15 minutes" held in the queue used to
post on the next wake-up, announcing a game already in the second inning. Schedule alerts now carry
an expiry: "starting soon" dies at kickoff, "they're under way" after ten minutes. A score has no
expiry, because a score is still a score whenever you read it.

Opening the app sweeps. A poll is what normally clears things, and a poll needs an alarm that
fired — which is precisely what has not been happening on a phone showing yesterday's game.

Full Changelog: v1.23.36...v1.23.37

LightSports v1.23.36

Choose a tag to compare

@github-actions github-actions released this 26 Aug 21:25

Two reports, one cause: a score from yesterday still on the lock screen, and two cards for the
same match — the score, and a "starting soon" sitting next to it.

The removal was scheduled on the full-time whistle, and only if the phone saw it. A card got a
removal time on the one poll where the game went from live to final. Miss that poll — asleep, in
Doze, out of signal — and nothing ever wrote one: once the game rolled out of the scoreboard
window its snapshot went too, so the transition could never be observed again, and the card sat
there indefinitely. A Phillies game from the day before is exactly that.

The clock now starts when a card is posted, which needs no transition to be caught. Every later
card for the same game pushes it out, and so does the game still being in progress — so a quiet
second half never loses the score, and the rule ends up being the simple one: an hour after the
last thing worth saying.

And the shade is now a second source of truth. Anything in it that nothing is tracking and that
is over an hour old gets cleared. That is what removes the cards already stuck on your phone, which
no amount of new tracking would have reached. The live ticker's own card is excluded — it is the
receipt for a running service, not news.

"Starting soon" goes at kickoff. It had no way to leave: with a league set to final-only there
is no later card to replace it, so it stayed in the shade beside the score for the whole game and
read as two notifications about one match. It is dropped the moment the game goes live.

And it is never posted late. Being due and being still true are different questions, and a
phone that was asleep is the gap between them — a "starts in 15 minutes" held in the queue used to
post on the next wake-up, announcing a game already in the second inning. Schedule alerts now carry
an expiry: "starting soon" dies at kickoff, "they're under way" after ten minutes. A score has no
expiry, because a score is still a score whenever you read it.

Opening the app sweeps. A poll is what normally clears things, and a poll needs an alarm that
fired — which is precisely what has not been happening on a phone showing yesterday's game.

Full Changelog: v1.22.35...v1.23.36

LightSports v1.22.35

Choose a tag to compare

@github-actions github-actions released this 26 Aug 19:47

BrightControl v3.65 grew a heads-up box of its own. It reads the shade and puts the same box over
the screen for whatever posted — including the notification this app raises a moment before it
draws its own. So with both switched on, a goal was one buzz and two boxes, one landing on top
of the other.

This one now stands aside. BrightControl says who is drawing the box; when it is, the box here
is skipped. The setting is untouched — it still reads as yours, and the row shows CONTROL rather
than pretending to be on while nothing appears. Turn banners off over there and this app's box
comes straight back, with nothing to set here.

The buzz and the notification never change. Both happen before the gate, and both have to: the
notification is the record BrightControl reads and the janitor clears an hour after full time. If
BrightControl's listener grant ever lapses, this app has still buzzed and still filled the shade.

And it checks BrightControl is really there. A remembered claim from an app that has since been
uninstalled would have silenced this box for good, with nothing on the phone to explain why.

Full Changelog: v1.21.34...v1.22.35

LightSports v1.21.34

Choose a tag to compare

@github-actions github-actions released this 25 Aug 18:58

No uninstall. This is an ordinary update. v1.20 was signed with a brand-new certificate, which
meant it could only be installed by removing the app first and losing followed teams, alert settings and the score snapshot.
That cost was not worth what it bought, so it has been withdrawn. v1.21 is signed with the same
certificate every release before v1.20 used, and it installs straight over the copy on your phone.

If you already uninstalled and installed v1.20, this one will not go over it — uninstall once more
and install v1.21, and that is the end of it.

What this does and does not fix. The signing key is no longer committed to this repository and
the file is gitignored, so a fresh clone does not hand it out. But it is still in this repository's
git history and always will be, so treat it as public: anyone determined enough can still build an
APK this phone would accept as an update. Closing that for real needs an APK Signature Scheme v3
rotation — signing with a new key while carrying a proof-of-rotation signed by the old one, which
Android accepts as a normal update — and that is a separate change, done carefully, not bundled in
behind an uninstall.

Everything else in v1.20 stands and is still here.

Full Changelog: v1.20.33...v1.21.34

LightSports v1.20.33

Choose a tag to compare

@github-actions github-actions released this 25 Aug 17:37

You have to uninstall BrightSports and install it again. Not an update — a full
uninstall first. Android identifies an app by its package name and the certificate it was
signed with, so a build signed with a different key is a different app as far as the phone
is concerned. Installing this one over the old one fails with a bare Failure: Invalid and
no explanation. Uninstall, then install; it is a one-time cost and no release after this one
asks for it again.

Uninstalling clears the app's data, which here means your followed teams, alert settings and
the score snapshot the background poller keeps. Note down what you follow before you start.

Why. The release key was committed to this repository with its password written three
lines under it in app/build.gradle.kts. Anyone who cloned it could build an APK that
Android would accept as an update to the one on your phone — which is the entire protection
Android offers, handed out with the source. The old key is retired. The new one is a CI
secret: the workflow decodes it at build time, keystore/*.jks is gitignored so a checkout
cannot commit it back, and the certificate the release actually carries is checked against
signing-fingerprint.txt before anything is published.

A build without the secret — a branch check, a local clone — still compiles and still
produces an APK. It just is not signed with the release key and will not install over one.
That is the right way for it to fail.

Also in this build. Every GitHub Action the workflows use is pinned to a commit SHA
rather than a moving tag, so a retagged or compromised action cannot quietly change what
builds your APK. check.yml declares read-only permissions. And the release body is these
notes now rather than an auto-generated commit list — RELEASE_NOTES.md was being written
every version and read by nothing, which is why a release this disruptive could otherwise
have shipped with no warning on it at all.

Scores, leagues, alerts and the notification janitor are untouched.

Full Changelog: v1.19.32...v1.20.33

LightSports v1.19.32

Choose a tag to compare

@github-actions github-actions released this 25 Aug 00:23

Full Changelog: v1.19.31...v1.19.32

LightSports v1.19.31

Choose a tag to compare

@github-actions github-actions released this 16 Aug 23:15

Full Changelog: v1.18.30...v1.19.31

LightSports v1.18.30

Choose a tag to compare

@github-actions github-actions released this 16 Aug 15:49

Full Changelog: v1.17.29...v1.18.30

LightSports v1.17.29

Choose a tag to compare

@github-actions github-actions released this 14 Aug 01:24

Full Changelog: v1.16.28...v1.17.29