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

Release/v3.6.0 #255

Merged
merged 25 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
7af3df9
Enable Hermes for iOS
wvanhaevre Jan 9, 2024
fde65a3
Bump follow-redirects from 1.15.3 to 1.15.4 in /example
dependabot[bot] Jan 11, 2024
a6d64fb
Merge pull request #249 from THEOplayer/dependabot/npm_and_yarn/examp…
tvanlaerhoven Jan 29, 2024
352c8ce
Add keepScreenOn toggle
tvanlaerhoven Jan 29, 2024
15c760b
Bridge keepScreenOn for android
tvanlaerhoven Jan 29, 2024
3431eb8
Add changelog entry
tvanlaerhoven Jan 29, 2024
f38e1f4
Drop the need for wake_lock permission
tvanlaerhoven Jan 29, 2024
2a8a786
Update docs
tvanlaerhoven Jan 29, 2024
2536473
Add keepScreenOn web stub
tvanlaerhoven Jan 30, 2024
d7bcbf8
Merge pull request #250 from THEOplayer/feature/toggle_wake_lock
tvanlaerhoven Jan 30, 2024
49d39ec
Update changelog
tvanlaerhoven Jan 30, 2024
396d5ca
3.5.0
tvanlaerhoven Jan 30, 2024
c761e41
Merge pull request #252 from THEOplayer/release/v3.5.0
tvanlaerhoven Jan 30, 2024
7539deb
Remove deprecated DispatchDispatch protocol
wvanhaevre Jan 31, 2024
24607e1
Don't trigger the native fullscreen flow on iOS
wvanhaevre Jan 31, 2024
093fe63
Add missing changelog line
wvanhaevre Feb 2, 2024
372aa02
Start foreground service faster with an initial playback state
tvanlaerhoven Jan 31, 2024
85def4c
Fix warning
tvanlaerhoven Jan 31, 2024
a9e7141
Remove deprecated playerSuite value
tvanlaerhoven Jan 31, 2024
d8dd00b
Remove trivial warnings
tvanlaerhoven Jan 31, 2024
6d5b75d
Use a placeholder icon before fetching large notification icon
tvanlaerhoven Feb 1, 2024
88002f9
Add changelog entry
tvanlaerhoven Feb 1, 2024
59d5f64
Merge pull request #253 from THEOplayer/bugfix/android_foregroundserv…
tvanlaerhoven Feb 2, 2024
d33e912
Update changelog
tvanlaerhoven Feb 2, 2024
3453a1c
3.6.0
tvanlaerhoven Feb 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.1.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [3.6.0] - 24-02-02

### Fixed

- Fixed a build issue on the iOS bridge caused by the deprecated DispatchDispatch protocol.
- Fixed an issue on Android where the `MediaPlaybackService` would sometimes crash with a `ForegroundServiceDidNotStartInTimeException` exception.

### Added

- Added the ability to override both small and large notification icons in Android with `ic_notification_small` and `ic_notification_large` resources respectively.

## [3.5.0] - 24-01-30

### Added

- Added the ability to toggle `keepScreenOn` on Android. By default, screen timeout is disabled while the player is visible.

## [3.4.2] - 23-12-22

### Fixed
Expand Down
6 changes: 0 additions & 6 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@
-->
<uses-permission android:name="android.permission.INTERNET" />

<!--
Allows using PowerManager WakeLocks to keep processor from sleeping or screen from dimming.
Protection level: normal
-->
<uses-permission android:name="android.permission.WAKE_LOCK" />

<!--
Allows a regular application to use Service.startForeground.
Protection level: normal
Expand Down
2 changes: 1 addition & 1 deletion android/src/main/java/com/theoplayer/PlayerEventEmitter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,7 @@ class PlayerEventEmitter internal constructor(
)
payload.putMap(EVENT_PROP_VERSION, WritableNativeMap().apply {
putString(EVENT_PROP_VERSION, THEOplayerGlobal.getVersion())
putString(EVENT_PROP_SUITE_VERSION, THEOplayerGlobal.getPlayerSuiteVersion())
putString(EVENT_PROP_SUITE_VERSION, "")
})

// Notify the player is ready
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ open class DefaultEventDispatcher: EventDispatcher<Event<*>> {

fun dispatchEvent(event: Event<*>) {
_listeners[event.type]?.forEach { listener ->
(listener as EventListener<Event<*>>).handleEvent(event)
@Suppress("UNCHECKED_CAST")
(listener as EventListener<Event<*>>).handleEvent(event)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class CastEventAdapter(private val castApi: Cast, private val emitter: Emitter)

private fun serializeError(error: CastError): WritableMap {
val errorPayload = Arguments.createMap()
@Suppress("SENSELESS_NULL_IN_WHEN")
errorPayload.putString(
EVENT_PROP_ERROR_CODE,
when (error.errorCode) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,12 @@ class ContentProtectionModule(private val context: ReactApplicationContext) :
}

@ReactMethod
@Suppress("UNUSED_PARAMETER")
fun addListener(eventName: String?) {
}

@ReactMethod
@Suppress("UNUSED_PARAMETER")
fun removeListeners(count: Int?) {
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.support.v4.media.session.MediaSessionCompat
Expand Down Expand Up @@ -195,3 +196,13 @@ fun fetchImageFromUri(uri: Uri?, block: (Bitmap?) -> Unit) {
)
}
}

fun loadPlaceHolderIcon(context: Context, res: Int = R.drawable.ic_notification_large): Bitmap? {
return try {
BitmapFactory.decodeResource(context.resources, res)
} catch(e: Exception) {
// Make sure we never crash on trying to decode a possibly overridden icon resource.
Log.w(TAG, "Failed to decode placeHolderIcon: ${e.message}")
null
}
}
50 changes: 31 additions & 19 deletions android/src/main/java/com/theoplayer/media/MediaPlaybackService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.theoplayer.media
import android.app.*
import android.content.Intent
import android.content.pm.ServiceInfo
import android.graphics.Bitmap
import android.os.Binder
import android.os.Build
import android.os.Bundle
Expand Down Expand Up @@ -96,6 +97,8 @@ class MediaPlaybackService : MediaBrowserServiceCompat() {
Log.w(TAG, "Failed to start foreground service: ${e.message}")
}

// Quickly post a notification and already call startForeground. This has to happen within 5s
// after creating the service to avoid a ForegroundServiceDidNotStartInTimeException
updateNotification(PlaybackStateCompat.STATE_PLAYING)
}

Expand Down Expand Up @@ -222,6 +225,7 @@ class MediaPlaybackService : MediaBrowserServiceCompat() {
}
}

@Suppress("UNUSED_PARAMETER")
private fun allowBrowsing(clientPackageName: String, clientUid: Int): Boolean {
// Only allow browsing from the same package
return TextUtils.equals(clientPackageName, packageName)
Expand Down Expand Up @@ -264,26 +268,13 @@ class MediaPlaybackService : MediaBrowserServiceCompat() {
// When a service runs in the foreground, it must display a notification, ideally
// with one or more transport controls. The notification should also include useful
// information from the session's metadata.
// Fetch large icon asynchronously

// Get the foreground service started in time before fetching an icon.
startForegroundWithPlaybackState(playbackState, loadPlaceHolderIcon(this))

// Fetch the correct large icon asynchronously.
fetchImageFromUri(mediaSession.controller.metadata?.description?.iconUri) { largeIcon ->
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(
NOTIFICATION_ID,
notificationBuilder.build(playbackState, largeIcon, enableMediaControls),
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
)
} else {
startForeground(
NOTIFICATION_ID,
notificationBuilder.build(playbackState, largeIcon, enableMediaControls)
)
}
} catch (e: IllegalStateException) {
// Make sure that app does not crash in case anything goes wrong with starting the service.
// https://issuetracker.google.com/issues/229000935
Log.w(TAG, "Failed to start foreground service: ${e.message}")
}
startForegroundWithPlaybackState(playbackState, largeIcon)
}
}
PlaybackStateCompat.STATE_STOPPED -> {
Expand All @@ -303,4 +294,25 @@ class MediaPlaybackService : MediaBrowserServiceCompat() {
}
}
}

private fun startForegroundWithPlaybackState(@PlaybackStateCompat.State playbackState: Int, largeIcon: Bitmap? = null) {
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(
NOTIFICATION_ID,
notificationBuilder.build(playbackState, largeIcon, enableMediaControls),
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
)
} else {
startForeground(
NOTIFICATION_ID,
notificationBuilder.build(playbackState, largeIcon, enableMediaControls)
)
}
} catch (e: IllegalStateException) {
// Make sure that app does not crash in case anything goes wrong with starting the service.
// https://issuetracker.google.com/issues/229000935
Log.w(TAG, "Failed to start foreground service: ${e.message}")
}
}
}
7 changes: 7 additions & 0 deletions android/src/main/java/com/theoplayer/player/PlayerModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,13 @@ class PlayerModule(context: ReactApplicationContext) : ReactContextBaseJavaModul
}
}

@ReactMethod
fun setKeepScreenOn(tag: Int, value: Boolean) {
viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? ->
view?.playerContext?.playerView?.keepScreenOn = value
}
}

@ReactMethod
fun setTextTrackStyle(tag: Int, style: ReadableMap?) {
viewResolver.resolveViewByTag(tag) { view: ReactTHEOplayerView? ->
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions example/ios/Podfile
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ target 'ReactNativeTHEOplayer' do
use_react_native!(
:path => config[:reactNativePath],
:flipper_configuration => flipper_config,
:hermes_enabled => true,
)

pod 'react-native-theoplayer', :path => '../..'
Expand Down
6 changes: 3 additions & 3 deletions example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions ios/THEOplayerRCTPlayerAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ class THEOplayerRCTPlayerAPI: NSObject, RCTBridgeModule {
if newPresentationMode == .fullscreen {
print(ERROR_MESSAGE_PLAYER_FULLSCREEN_UNSUPPORTED_FEATURE)
}
if let theView = self.bridge.uiManager.view(forReactTag: node) as? THEOplayerRCTView,
let player = theView.player {
else if let theView = self.bridge.uiManager.view(forReactTag: node) as? THEOplayerRCTView,
let player = theView.player {
if player.presentationMode != newPresentationMode {
if DEBUG_PLAYER_API { PrintUtils.printLog(logText: "[NATIVE] Changing TheoPlayer to \(presentationMode)") }
player.presentationMode = newPresentationMode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public class THEOplayerRCTBroadcastEventHandler: DefaultEventDispatcher {
}
}

public class DefaultEventDispatcher: NSObject, THEOplayerSDK.EventDispatcherProtocol, THEOplayerSDK.DispatchDispatch {
public class DefaultEventDispatcher: NSObject, THEOplayerSDK.EventDispatcherProtocol {
private var eventListeners = [String: [EventListenerWrapper]]()

public func addEventListener<E>(type: THEOplayerSDK.EventType<E>, listener: @escaping (_ : E) -> ()) -> THEOplayerSDK.EventListener {
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-native-theoplayer",
"version": "3.4.2",
"version": "3.6.0",
"description": "A THEOplayer video component for react-native.",
"main": "lib/commonjs/index",
"module": "lib/module/index",
Expand Down
9 changes: 9 additions & 0 deletions src/api/player/THEOplayer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@ export interface THEOplayer extends EventDispatcher<PlayerEventMap> {
*/
aspectRatio: AspectRatio;

/**
* Toggle the wake-lock on the player view. The screen will time out if disabled.
*
* @defaultValue `true`
* @remarks
* Only available on Android.
*/
keepScreenOn: boolean;

/**
* The active configuration for PiP.
*/
Expand Down
5 changes: 2 additions & 3 deletions src/internal/adapter/NativePlayerState.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import type { MediaTrack, PreloadType, PresentationMode, SourceDescription, TextTrack, TimeRange } from 'react-native-theoplayer';
import type { BackgroundAudioConfiguration } from '../../api/backgroundAudio/BackgroundAudioConfiguration';
import type { PiPConfiguration } from 'react-native-theoplayer';
import type { AspectRatio } from 'react-native-theoplayer';
import type { PiPConfiguration, AspectRatio, BackgroundAudioConfiguration } from 'react-native-theoplayer';

export interface NativePlayerState {
source: SourceDescription | undefined;
Expand All @@ -20,6 +18,7 @@ export interface NativePlayerState {
playbackRate: number;
preload: PreloadType;
aspectRatio: AspectRatio;
keepScreenOn: boolean;
audioTracks: MediaTrack[];
videoTracks: MediaTrack[];
textTracks: TextTrack[];
Expand Down
12 changes: 12 additions & 0 deletions src/internal/adapter/THEOplayerAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const defaultPlayerState: NativePlayerState = {
playbackRate: 1,
preload: 'none',
aspectRatio: AspectRatio.FIT,
keepScreenOn: true,
audioTracks: [],
videoTracks: [],
textTracks: [],
Expand Down Expand Up @@ -502,6 +503,17 @@ export class THEOplayerAdapter extends DefaultEventDispatcher<PlayerEventMap> im
NativeModules.PlayerModule.setAspectRatio(this._view.nativeHandle, ratio);
}

get keepScreenOn(): boolean {
return this._state.keepScreenOn;
}

set keepScreenOn(value: boolean) {
this._state.keepScreenOn = value;
if (Platform.OS === 'android') {
NativeModules.PlayerModule.setKeepScreenOn(this._view.nativeHandle, value);
}
}

pause(): void {
if (this.hasValidSource()) {
this._state.paused = true;
Expand Down
8 changes: 8 additions & 0 deletions src/internal/adapter/THEOplayerWebAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,14 @@ export class THEOplayerWebAdapter extends DefaultEventDispatcher<PlayerEventMap>
// unused
}

get keepScreenOn(): boolean {
return false;
}

set keepScreenOn(_screenOn: boolean) {
// unused
}

get duration(): number {
return this._player ? this._player.duration * 1e3 : NaN;
}
Expand Down
Loading