From 924b84a4d5522c28a4409863d96796e51a86a525 Mon Sep 17 00:00:00 2001 From: Reactorcoremeltdown Date: Wed, 22 Jul 2026 23:52:14 +0200 Subject: [PATCH] Keep MIDI input alive with the screen off / app backgrounded (v0.21.1) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit MIDI (and the MIDI clock) were started in onStart and stopped in onStop, so turning the screen off — which drives the Activity to onStop — closed the MIDI ports and dropped controller input. Move their lifecycle to onCreate/onDestroy so input persists for the Activity's whole lifetime; onStop keeps only the project autosave. The audio engine already runs a continuous output stream via the started PlaybackService, which keeps the process alive (verified at PERSISTENT_SERVICE_ADJ when backgrounded) to receive events with the screen off. USB MIDI needs no runtime permission, so it works unconditionally. Trade-off: the controller stays claimed by the app while backgrounded, and is released only when the Activity is torn down (task removed / finishing). Co-Authored-By: Claude Opus 4.8 --- app/build.gradle.kts | 4 ++-- .../space/rcmd/android/sizzle/MainActivity.kt | 21 ++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 766d19c..4ed85b7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -22,8 +22,8 @@ android { // (android.media.midi) and AAudio low-latency audio we rely on. minSdk = 26 targetSdk = 34 - versionCode = 47 - versionName = "0.21.0" + versionCode = 48 + versionName = "0.21.1" // We provide our own instrumentation runner if/when tests are added. testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" diff --git a/app/src/main/java/space/rcmd/android/sizzle/MainActivity.kt b/app/src/main/java/space/rcmd/android/sizzle/MainActivity.kt index c93831d..e00ea40 100644 --- a/app/src/main/java/space/rcmd/android/sizzle/MainActivity.kt +++ b/app/src/main/java/space/rcmd/android/sizzle/MainActivity.kt @@ -75,10 +75,13 @@ class MainActivity : ComponentActivity() { SizzleAppUi(viewModel) } } - } - override fun onStart() { - super.onStart() + // Start MIDI listening (USB + BLE) and the MIDI clock here — bound to the + // Activity's WHOLE lifetime (onCreate..onDestroy), not onStart/onStop — so a + // connected controller keeps driving the app while the screen is off. The + // audio engine already runs a continuous output stream via the started + // PlaybackService, which keeps the process alive to receive those events in + // the background; closing the ports on onStop was the only reason input died. midi.start() app.midiClock.start() } @@ -93,11 +96,19 @@ class MainActivity : ComponentActivity() { override fun onStop() { // Autosave the project whenever we leave the foreground, so a later - // system-kill (or crash) resumes from here on next launch. + // system-kill (or crash) resumes from here on next launch. MIDI is + // deliberately NOT stopped here (see onCreate / onDestroy) so controllers + // keep working with the screen off or the app backgrounded. app.projectStore.save(app.project) + super.onStop() + } + + override fun onDestroy() { + // Release MIDI only when the Activity is actually torn down (task removed or + // finishing), not merely backgrounded / screen-off. midi.stop() app.midiClock.stop() - super.onStop() + super.onDestroy() } // ---- Hardware input forwarding ----