Skip to content

Keep the job and state through a recreate - #192

Merged
zeevy merged 3 commits into
masterfrom
fix/187-188-lifecycle-state
Oct 10, 2026
Merged

zeevy merged 3 commits into
masterfrom
fix/187-188-lifecycle-state

Conversation

@zeevy

@zeevy zeevy commented Oct 10, 2026

Copy link
Copy Markdown
Owner

Fixes #187 and #188. #191 was tested and closed as not a real crash.

#188 - stale state after the switch from Bluetooth to USB

  • restartInUsbMode() starts UsbConnectionActivity and then finishes. Android destroys the old activity after the new one has read MachineStatusListener, FileSenderListener and ConsoleLoggerListener, and the old onDestroy() replaced them. The USB screen kept the old objects.
  • Now GrblActivity.onCreate resets them only on a fresh start (savedInstanceState == null), and onDestroy no longer does.

#187 - a fold, rotation or resize stopped a running job

  • Android 16 ignores the portrait lock and resizeableActivity=false on large screens, so the activity is recreated. onDestroy() then stopped the streaming service and the serial service, and sent $10=1.
  • Now those run only when isFinishing(). The serial service is started, so it outlives the unbind and the new activity binds to it again.
  • After a recreate during a job the new activity now shows "Connected" when the link is up, sets keep screen on again, and does not show the battery dialog (it covered the Stop button).

Checked

  • Emulator (API 37), with throwaway builds (not committed) that enable the file and start buttons with no machine:
  • Pixel 6a (Android 17) with GRBL 1.1f on USB OTG, no motors, this code under a separate package name: an 83-line job, dark mode switched twice mid-job (two activity relaunches). The streaming and USB services kept the same instances, the job ran to 100% (83/83, 1:53), the toolbar stayed "Connected", no battery dialog, no crash.
  • ./gradlew build passes.

Not covered: on a phone (not a large screen) a display density or size change makes Android restart the whole process, because the activities are non-resizable. That stops a job too, but it is system behaviour, not this code.

GrblActivity.onDestroy() reset MachineStatusListener, FileSenderListener
and ConsoleLoggerListener. After the switch from Bluetooth to USB, the
new UsbConnectionActivity reads them in onCreate and the old activity is
destroyed after that, so the USB screen kept the replaced objects: its
status card stopped updating and the streaming service did not see the
selected file.

Reset them in onCreate when there is no saved state (a fresh start)
instead. A recreate keeps them.

Fixes #188
onDestroy() stopped the streaming service and the serial service on
every destroy. Android 16 ignores the portrait lock and the resizable
flag on large screens, so a fold, rotation or window resize recreated
the activity and stopped a running job in the middle.

Stop them, and send $10=1, only when the activity is finishing. The
serial service is started, so it outlives the unbind and the new
activity binds to it again.

Fixes #187
Now that a job and the connection survive a recreate, the new activity
must show them:

- Toolbar: show "Connected" when the USB port or the Bluetooth link is
  still up after the service binds again.
- Keep screen on: set it again when a job is running, as the window is
  new and StreamingStartedEvent is sent only once.
- Battery dialog: ask only on a fresh start, so it does not cover the
  Stop button in the middle of a job.

Refs #187
@zeevy
zeevy merged commit 9a1fdc9 into master Oct 10, 2026
12 checks passed
@zeevy
zeevy deleted the fix/187-188-lifecycle-state branch October 10, 2026 03:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A fold, rotation or resize stops a running job and resets the app state

2 participants