Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Enable Lock-Screen Controls #539

Open
wants to merge 36 commits into
base: feature/enable-lock-screen-controls
Choose a base branch
from

Conversation

123mpozzi
Copy link
Contributor

@123mpozzi 123mpozzi commented Oct 18, 2024

Description

Implement the lock-screen controls in Android (via the MediaSession API) to make the system display the current media information on the lock-screen, and the control-center.

Additionally, this PR also introduces background-playback support

PR-planning

Overview pics

image image

Changes

Implement lock-screen controls

  • Use a MediaSession service to hold a strong reference to the player instance
  • Add serializers for LockScreenControlConfig
  • Update manifest permissions to allow running the background service

Implement Background playback

  • Slightly change the PlayerView lifecycle to prevent auto-pausing the background playback on app minimize
    • Fix playerEventRelay being null in some scenarios

2 new samples

Both of them allows you to have playback without the main app being opened

  • Lock-Screen Controls (media session)
    • No background playback, so it pauses the app on minimizing it
  • Background Playback
    • It does not pause the playback when minimizing the app
    • Has lock-screen controls enabled (since we need a notification, we favor lock-screen controls)

Note

Note: both samples will destroy the player instance (hence destroying the lock-screen widgets) when going back to the homepage. That is expected, a more advanced sample could be part of a follw-up (e.g. letting the widget live in the homescreen as well, until we open a sample with media session disabled).

Config Flags Design

  • LockScreenControlConfig.isEnabled decides whether the service starts or not
  • PlayerConfig.PlaybackConfig.isBackgroundPlaybackEnabled decides whether to detach the player from the view
    • LockScreenControlConfig.isEnabled has to be true for background playback to work, since it needs a notification

Testing

Please do some manual testing, with a physical device if possible 🙏

Important

A snapshot build of the Android SDK is necessary until Lock-Screen is completely released there.
Direct-message me for a quick patch file

Things to look for

Lock-Screen Controls (use the new "Lock-Screen Control" sample)

  • widget is created
    • in notification-centre
    • in lock-screen
  • minimizing the app stops the playback
    • when re-opening the app, the player data is synced (e.g. current playback time)

Background Playback feature (use the new "Background Playback" sample)

  • widget is created
    • in notification-centre
    • in lock-screen
  • minimizing the app does NOT stop the playback
    • when re-opening the app, the player data is synced (e.g. current playback time)
  • does not work without media session being enabled as well (via LockScreenControlConfig)

Activity lifecycle changes

  • basic samples have no background playback
    • by default
    • after running the new samples
  • basic samples playerview is not empty after running the new samples

Checklist

  • 🗒 CHANGELOG entry - entry added already in base PR

To implement lock-screen controls, a player instance must be
'kept alive', so that the player is not garbage-collected or
destroyed by the system when the view is destroyed.

There are 2 ways to do this:
- init the player on the service itself
  (like in the Android SDK sample)
- init the player as usual, and somehow pass it to the service,
  to store an additional reference

This first version implements the second option.

The app has 1 strong reference, and the service has 1 strong reference
to the player. So that whenever the app dies, the background playback
still goes on.

Current Issues:
- Whenever the app gets back, the player instance should get fetched back as well!
- Another limitation with this implementation is that we're calling `setupMediaSession`
  on `player.ts`'s `inizitalize()`. But when changing sources
  (e.g. playback view, click back, playback view), the source in the
  media session does not get overridden with the source from the new view.
Via native by using player module

Note: The actual media session module can just be a native one (like offline module)
as it is just called via native (player module)
This module will be Android-only.
The old player was not getting destroyed when a
new one is being put in charge of the media session
This has to be handled via the activity lifecycle.
Took `BackgroundPlaybackScreen` from Android SDK samples as the example

Also fix `playerEventRelay` being null in some conditions
@123mpozzi 123mpozzi self-assigned this Oct 18, 2024
@123mpozzi 123mpozzi changed the base branch from development to feature/enable-lock-screen-controls October 18, 2024 09:07
As modules represent something native that can be re-used from the
JS side, but this is not the case here
EVENT_CLASS_TO_REACT_NATIVE_NAME_MAPPING,
::emitEventFromPlayer,
)

Copy link
Contributor Author

@123mpozzi 123mpozzi Oct 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had to move playerEventRelay initialization here because it was null during the first invocations of onStop in the activity lifecycle.
This is due to the custom setPlayer we have, which also sets playerEventRelay

Limitation section will need an update once the lock-screen
implementation into Android SDK is finished
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that the Limitations section is not modified.
It will be update once the lock-screen feature is fully released on the Android SDK

@123mpozzi 123mpozzi marked this pull request as ready for review October 18, 2024 12:37
@123mpozzi 123mpozzi requested a review from a team as a code owner October 18, 2024 12:37
fun ReadableMap.toLockScreenControlConfig(): LockScreenControlConfig = LockScreenControlConfig().apply {
withBoolean("isEnabled") { isEnabled = it }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This config is a cross-platform wrapper, it does not exist in either native SDK.
It acts as a common name to reach the feature

123mpozzi and others added 12 commits October 24, 2024 10:27
…re/android-extend-mediasession-for-simple-bg-playback

# Conflicts:
#	android/src/main/java/com/bitmovin/player/reactnative/BackgroundPlaybackManager.kt
AS media session is only the widget API
As it is not related to background playback
As it is
- good user experience on iOS
- necessary on Android after certain OS version
And reduce scope where possible
As they're actually directly related to media session instead now
val enableMediaSession = playerConfigJson?.getMap("lockScreenControlConfig")
?.toLockScreenControlConfig()?.isEnabled ?: false
enableBackgroundPlayback = playerConfigJson?.getMap("playbackConfig")
?.getBoolean("isBackgroundPlaybackEnabled") ?: false
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs special mapping as it is a React-Native (and iOS as well) flag

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.

1 participant