diff --git a/CHANGELOG.md b/CHANGELOG.md index d410045d..e9ea180b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ ## Changelog +### Version 5.1.1 +* Added support for full-screen functionality in Android Exoplayer [#1730](https://github.com/react-native-community/react-native-video/pull/1730) + ### Version 5.1.0-alpha1 * Fixed Exoplayer doesn't work with mute=true (Android). [#1696](https://github.com/react-native-community/react-native-video/pull/1696) * Added support for automaticallyWaitsToMinimizeStalling property (iOS) [#1723](https://github.com/react-native-community/react-native-video/pull/1723) diff --git a/README.md b/README.md index 2ce6995a..9248bebe 100644 --- a/README.md +++ b/README.md @@ -412,6 +412,8 @@ Note on iOS, controls are always shown when in fullscreen mode. For Android MediaPlayer, you will need to build your own controls or use a package like [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls) or [react-native-video-player](https://github.com/cornedor/react-native-video-player). +Note on Android ExoPlayer, native controls are available by default. If needed, you can also add your controls or use a package like [react-native-video-controls]. + Platforms: Android ExoPlayer, iOS, react-native-dom #### disableFocus @@ -462,7 +464,7 @@ Controls whether the player enters fullscreen on play. * **false (default)** - Don't display the video in fullscreen * **true** - Display the video in fullscreen -Platforms: iOS +Platforms: iOS, Android Exoplayer #### fullscreenAutorotate If a preferred [fullscreenOrientation](#fullscreenorientation) is set, causes the video to rotate to that orientation but permits rotation of the screen to orientation held by user. Defaults to TRUE. @@ -475,6 +477,8 @@ Platforms: iOS * **landscape** * **portrait** +Note on Android ExoPlayer, the full-screen mode by default goes into landscape mode. Exiting from the full-screen mode will display the video in Initial orientation. + Platforms: iOS #### headers diff --git a/Video.js b/Video.js index 3cb28bb2..08b71dca 100644 --- a/Video.js +++ b/Video.js @@ -1,6 +1,6 @@ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import {StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image, Platform, findNodeHandle} from 'react-native'; +import { StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image, Platform, UIManager, findNodeHandle, Dimensions } from 'react-native'; import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'; import TextTrackType from './TextTrackType'; import FilterType from './FilterType'; @@ -20,24 +20,51 @@ export default class Video extends Component { super(props); this.state = { - showPoster: !!props.poster + showPoster: !!props.poster, + androidFullScreen: false, + videoContainerLayout_x: 0, + videoContainerLayout_y: 0 }; + this.getDimension(); + } + + /** + * @description this is will set the width and height needs to be considered for full screen + */ + getDimension() { + if (Dimensions.get('window').width < Dimensions.get('window').height) { + this.width = Math.round(Dimensions.get('window').height); + this.height = Math.round(Dimensions.get('window').width); + } + else { + this.width = Math.round(Dimensions.get('window').width); + this.height = Math.round(Dimensions.get('window').height); + } + } + + componentDidMount() { + UIManager.measure(findNodeHandle(this._videoContainer), (x, y) => { + this.setState({ + videoContainerLayout_x: x, + videoContainerLayout_y: y + }) + }) } setNativeProps(nativeProps) { this._root.setNativeProps(nativeProps); } - + toTypeString(x) { switch (typeof x) { case "object": - return x instanceof Date - ? x.toISOString() + return x instanceof Date + ? x.toISOString() : JSON.stringify(x); // object, null case "undefined": return ""; default: // boolean, number, string - return x.toString(); + return x.toString(); } } @@ -53,7 +80,7 @@ export default class Video extends Component { seek = (time, tolerance = 100) => { if (isNaN(time)) throw new Error('Specified time is not a number'); - + if (Platform.OS === 'ios') { this.setNativeProps({ seek: { @@ -88,7 +115,7 @@ export default class Video extends Component { _hidePoster = () => { if (this.state.showPoster) { - this.setState({showPoster: false}); + this.setState({ showPoster: false }); } } @@ -124,7 +151,7 @@ export default class Video extends Component { if (this.props.onBandwidthUpdate) { this.props.onBandwidthUpdate(event.nativeEvent); } - }; + }; _onSeek = (event) => { if (this.props.onSeek) { @@ -145,6 +172,7 @@ export default class Video extends Component { }; _onFullscreenPlayerWillPresent = (event) => { + Platform.OS === 'android' && this.setState({ androidFullScreen: true }) if (this.props.onFullscreenPlayerWillPresent) { this.props.onFullscreenPlayerWillPresent(event.nativeEvent); } @@ -157,6 +185,7 @@ export default class Video extends Component { }; _onFullscreenPlayerWillDismiss = (event) => { + Platform.OS === 'android' && this.setState({ androidFullScreen: false }) if (this.props.onFullscreenPlayerWillDismiss) { this.props.onFullscreenPlayerWillDismiss(event.nativeEvent); } @@ -195,7 +224,7 @@ export default class Video extends Component { this.props.onPlaybackRateChange(event.nativeEvent); } }; - + _onExternalPlaybackChange = (event) => { if (this.props.onExternalPlaybackChange) { this.props.onExternalPlaybackChange(event.nativeEvent); @@ -215,7 +244,7 @@ export default class Video extends Component { }; _onRestoreUserInterfaceForPictureInPictureStop = (event) => { - if (this.props.onRestoreUserInterfaceForPictureInPictureStop) { + if (this.props.onRestoreUserInterfaceForPictureInPictureStop) { this.props.onRestoreUserInterfaceForPictureInPictureStop(); } }; @@ -248,7 +277,7 @@ export default class Video extends Component { if (uri && uri.match(/^\//)) { uri = `file://${uri}`; } - + if (!uri) { console.warn('Trying to load empty source.'); } @@ -313,8 +342,22 @@ export default class Video extends Component { resizeMode: this.props.posterResizeMode || 'contain', }; + //androidFullScreen property will only impact on android. It will be always false for iOS. + const videoStyle = this.state.androidFullScreen ? { + position: 'absolute', + top: 0, + left: 0, + width: this.width, + height: this.height, + backgroundColor: '#ffffff', + justifyContent: "center", + zIndex: 99999, + marginTop: -1 * (this.state.videoContainerLayout_y ? parseFloat(this.state.videoContainerLayout_y) : 0), //margin: 0 - is not working properly. So, updated all the margin individually with 0. + marginLeft: -1 * (this.state.videoContainerLayout_x ? parseFloat(this.state.videoContainerLayout_x) : 0) + } : {} + return ( - + this._videoContainer = videoContainer} style={[nativeProps.style, videoStyle]}> + + + + +