feat(sdk): lock-screen media controls via LightMediaSession - #100
Open
tthayer wants to merge 8 commits into
Open
feat(sdk): lock-screen media controls via LightMediaSession#100tthayer wants to merge 8 commits into
tthayer wants to merge 8 commits into
Conversation
Add a LightMediaSession primitive so a tool can publish its playback to Android's media framework — a MediaSession plus a mediaPlayback foreground service and a MediaStyle notification — which LightOS surfaces on the lock screen and which routes headset/Bluetooth transport keys back to the tool. - plugin: allow FOREGROUND_SERVICE + FOREGROUND_SERVICE_MEDIA_PLAYBACK - client: LightMediaSession API (attach/setControls/update/release) + LightMediaService foreground service + manifest <service> declaration - emulator: NowPlayingReader reads active sessions via MediaSessionManager (MEDIA_CONTENT_CONTROL as the platform-signed system app) and the lock screen renders track title + transport controls that drive the session Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When the selected media session stops or pauses, re-evaluate which active session to show so the lock screen tracks the currently-playing (or most recently active) tool rather than sticking to a stale one. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- plugin: disable the NotificationPermission check for tool modules. A tool's only path to posting a notification is the SDK's guarded LightMediaSession (the sandbox blocks direct NotificationManager access), so the check is a false positive that every tool would inherit just by linking the SDK. - client: guard LightMediaSession's notify() behind a POST_NOTIFICATIONS runtime check (best-effort; only shows for tools that opted in). - emulator: tools:ignore ProtectedPermissions on MEDIA_CONTENT_CONTROL, which the platform-signed system-app emulator legitimately holds. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
would be great for the lock screen controls to control generic playing content as well rather than just content routed thru lightmediasession. not sure if that's the behavior already! |
Contributor
Author
Contributor
Author
|
I think it really just depends on the media player attaching to a LightMediaSession. Whichever attached last is the one that gets controls presented. |
Resolves the MainActivity conflict: main restructured onCreate into a PrimaryUI composable behind EmulatorNavController plus a LightModalManager host, so the lock screen's now-playing wiring moves into PrimaryUI's Nav.LockScreen branch and navigates via EmulatorNavController. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
PR lightphone#119 landed LightAudioPlayer, which already tracks everything the lock screen needs. Rather than make tools mirror that state into the session by hand, add an attach(lightContext, player) overload that derives it: transport callbacks route into the player, and its flows are combined into the LightNowPlaying/LightPlaybackStatus pushed on every change. release() cancels the collector before tearing the session down. The player kept queue metadata only inside ExoPlayer, so expose it as nowPlaying/hasNext/hasPrevious StateFlows. Those also save any caller mapping currentMediaItemIndex back onto its own queue, which is what the audio-demo player screen does today. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… into feat/lock-screen-media-controls
tthayer
marked this pull request as ready for review
July 27, 2026 17:53
Contributor
Author
|
@dupontgu I'm happy to see the LightAudioPlayer feature added! This PR integrates that and wires in the now-playing behavior. |
… rework PR lightphone#119 rebuilt the client audio surface around LightAudio/LightAudioPlayer, but in doing so it dropped the MediaStore reader this branch had carried: tools lost LightAudioLibrary, the SealedLightContext.audioLibrary accessor, and useMediaVolumeKeys. Nothing replaced them, and the Gradle plugin blocks tools from reaching a ContentResolver themselves, so after lightphone#119 a tool had no sanctioned way to enumerate the on-device music library at all. Restores the three pieces verbatim from 751ac3e, with the LightActivity volume handling merged into the key overrides that have since grown a screen/server routing chain rather than added alongside them. onKeyMultiple is left alone, as it was before. Playback itself stays on lightphone#119's LightAudioPlayer — this only returns the read-side library API and the volume HUD. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

Addresses #99
Add a LightMediaSession primitive so a tool can publish its playback to Android's media framework — a MediaSession plus a mediaPlayback foreground service and a MediaStyle notification — which LightOS surfaces on the lock screen and which routes headset/Bluetooth transport keys back to the tool.
<service>declarationRebased onto the audio API from #119
#119 landed
LightAudioPlayer, which already tracks everything the lock screen needs. Rather than have tools mirror that state into the session by hand, this branch now integrates the two:LightMediaSession.attach(lightContext, player)— a tool that plays through the SDK's own player gets lock-screen and headset controls in one line. Transport callbacks route into the player, and its state flows are combined into theLightNowPlaying/LightPlaybackStatuspushed on every change.release()cancels the collector before tearing the session down. The manualattach/setControls/updatepath is unchanged for tools driving their own playback engine.LightAudioPlayer.nowPlaying/.hasNext/.hasPrevious— the player kept queue metadata only inside ExoPlayer, so the current item'sLightMediaMetadataand its queue neighbours are now exposed asStateFlows. Independent of the media session, these save any caller mappingcurrentMediaItemIndexback onto the list it passed tosetMediaQueue, which is what theaudio-demoplayer screen does today.Merge conflict with main was in the emulator's
MainActivity: main restructuredonCreateinto aPrimaryUIcomposable behindEmulatorNavControllerplus aLightModalManagerhost, so the now-playing wiring moved intoPrimaryUI'sNav.LockScreenbranch and navigates viaEmulatorNavController.Note that
audio-demois deliberately left alone — wiring it toLightMediaSessionwould make it hold a foreground service and keep playing after the tool is left, which #119 explicitly scoped out pending LightOS work. Happy to add a demo tool here (or flip audio-demo) if you'd rather see it exercised end to end.