Implementing Picture in Picture Mode
Overview
Android supports Picture-in-picture (PiP) mode starting from android 8.0 (API level 26). Picture-in-picture (PiP) is a special case of the multi-window UI which lets the user watch a video in a small window pinned to a corner of the screen while navigating between apps or browsing content on the main screen. To add PiP to your app, you need to register your activities that support PiP, switch your activity to PiP mode as required, and make sure UI elements are hidden and video playback continues when the activity is in PiP mode. The PiP window appears in the topmost layer of the screen, in a corner chosen by the system.
How users can interact with the picture-in-picture (PiP) window
It is possible to drag the PiP window to another location. Starting in Android 12, users can also:
- Single-tap the window to display a full-screen toggle, a close button, a settings button, and custom actions provided by your app (for example, play controls).
- Double-tap the window to toggle between the current PiP size and maximum PiP size.
- Resize the PiP window using pinch-to-zoom.
Your app controls when the current activity enters PiP mode. Here are some examples:
- An activity can enter PiP mode when the user taps the home button.
- Your app can move a video into PiP mode when the user navigates back from the video to browse other content.
Declare picture-in-picture support
Register your video activity in your manifest by setting android:supportsPictureInPicture
to true
. Also, specify that your activity handles layout configuration changes so that your activity doesn't relaunch when layout changes occur during PiP mode transitions.
<activity
android:name=".PlayerActivity"
android:configChanges="keyboardHidden|orientation|screenSize|smallestScreenSize|screenLayout"
android:supportsPictureInPicture="true">
Picture in picture implementation
The react native SDK provides two ways to implement a player. One with native controls and one with user-implemented custom controls. So, there are two methods to implement picture-in-picture mode.
Picture-in-picture (PiP) for player with native controls
After declaring the picture in picture support in the manifest file, pass setPictureInPictureSupport: true
in embed info along with the otp and playbackinfo to VdoPlayerView
component.
import {VdoPlayerView} from 'vdocipher-rn-bridge';
const embedInfo = {
otp: 'some-otp',
playbackInfo: 'some-playbackInfo',
setPictureInPictureSupport: true,
};
// in JSX
<VdoPlayerView style={{height: 200, width: '100%'}} embedInfo={embedInfo} />;
To use PIP mode support for native controls, the pip should also be enabled from player configuration from dashboard as well.
Picture-in-picture (PiP) for player with custom controls
To enter picture-in-picture mode for custom controls, an activity must call enterPictureInPictureMode(). For example, the following code switches an activity to PiP mode when a the user clicks the home or recent button:
import android.app.PictureInPictureParams;
import android.os.Bundle;
import android.os.Build;
import androidx.annotation.RequiresApi;
import androidx.fragment.app.Fragment;
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
//switch to PiP mode if the user presses the home or recent button,
Fragment vdoPlayerFragment = getSupportFragmentManager().findFragmentByTag("VdoPlayerUIFragmentRN");
if (vdoPlayerFragment != null && vdoPlayerFragment.isVisible()) {
enterPictureInPictureMode(new PictureInPictureParams.Builder().build());
}
}
The check for vdoPlayerFragment needs to be added if you do not wish to enter pip mode for any other screen.
After performing above steps, pass setPictureInPictureSupport: true
in embed info along with the otp and playbackinfo to VdoPlayerView
component.
import {VdoPlayerView} from 'vdocipher-rn-bridge';
const embedInfo = {
otp: 'some-otp',
playbackInfo: 'some-playbackInfo',
setPictureInPictureSupport: true,
};
// in JSX
<VdoPlayerView
style={{height: 200, width: '100%'}}
embedInfo={embedInfo}
showNativeControls={false}
/>;
Handle UI during picture-in-picture for custom controls
Use onPictureInPictureModeChanged
event based prop to handle UI during pip mode.
Refer example below to show/hide custom controls based on isInPictureInPictureMode
flag
import {VdoPlayerView} from 'vdocipher-rn-bridge';
const embedInfo = {
otp: 'some-otp',
playbackInfo: 'some-playbackInfo',
setPictureInPictureSupport: true,
};
// in JSX
var isInPictureInPictureMode = this.state.isInPictureInPictureMode;
<VdoPlayerView
style={{height: 200, width: '100%'}}
embedInfo={embedInfo}
showNativeControls={false}
onPictureInPictureModeChanged={this._onPictureInPictureModeChanged}
/>;
{
!isInPictureInPictureMode && (
<View style={styles.controls.container}>
<TouchableWithoutFeedback onPress={this._onPlayButtonTouch}>
<Icon name={showPlayIcon ? 'play' : 'pause'} size={30} color="#FFF" />
</TouchableWithoutFeedback>
<Text style={styles.controls.position}>
{digitalTime(Math.floor(this.state.position))}
</Text>
{this._renderSeekbar()}
<Text style={styles.controls.duration}>
{digitalTime(Math.floor(this.state.duration))}
</Text>
<TouchableWithoutFeedback onPress={this._toggleFullscreen}>
<MatIcon
name={isFullscreen ? 'fullscreen-exit' : 'fullscreen'}
style={styles.controls.fullscreen}
size={30}
color="#FFF"
/>
</TouchableWithoutFeedback>
</View>
);
}
_onPictureInPictureModeChanged = (pictureInPictureModeInfo) => {
this.setState({
isInPictureInPictureMode:
pictureInPictureModeInfo.nativeEvent.isInPictureInPictureMode,
});
};