Implementing PiP mode in Android in 5 simple steps
Table of Contents
Picture-in-Picture(PiP) mode shrinks the Android app content into a small floating window so that the user can keep consuming the content of the app from the PiP window while using other apps on the device
Brief Overview
PiP leverages the multi-window APIs made available in Android 7.0 to provide the pinned video overlay window. The PiP window appears in the topmost layer of the screen, in a corner chosen by the system. Check the screenshot below:
Implementation
To add PiP support to the app, you need to set the minSdk version to API 26 in the build.gradle file. I have broken down the PiP implementation into 5 easy steps. Let us go through these below:
1. Enable PiP support for your Activity
Enable PiP support for your Activity by setting the attribute android:supportsPictureInPicture
to true
in the Manifest file. Also, specify that your activity handles layout configuration changes so that your activity doesn’t relaunch when PiP mode transitions happen.
<activity android:name="MainActivity" android:supportsPictureInPicture="true" android:configChanges= "screenSize|smallestScreenSize|screenLayout|orientation"/>
2. Set the PictureInPictureParams value in the Activity
PictureInPictureParams
is used to configure the various properties of the PiP window like aspect ratio, sourceRectHint
, custom actions, etc. We can then set these params to activity using setPictureInPictureParams
method
- Set the custom aspect ratio using
Rational
class. See code below - Use
setAutoEnterEnabled
to provide smoother transitions to PiP when the user swipes up to go to the home screen using gesture navigation.
Note: When setAutoEnterEnabled
is enabled, you don’t need to explicitly call enterPictureInPictureMode
in onUserLeaveHint
. Also, this method is available only on Android 12 and above
val aspectRatio = Rational(16, 9)// Rational(1, 1) for square window setPictureInPictureParams(new PictureInPictureParams.Builder() .setAspectRatio(aspectRatio) .setAutoEnterEnabled(true) .build());
3. Switch to PiP mode
Calling enterPictureInPictureMode(android.app.PictureInPictureParams)
method will switch your activity to PiP mode. This method can be called at the click of a button or any other type of user action.
If want your activity to switch to PiP mode instead of going into the background then you can override the method onUserLeaveHint()
that gets invoked when an activity is about to go into the background as the result of user choice.
override fun onUserLeaveHint() { if (shouldShowPip()) { enterPictureInPictureMode() } }
Note:
As I observed in my testing, onUserLeaveHint()
method seems to be a little buggy as it gets called even when the activity goes to a paused state due to some system dialog appearing on top of it
Android documentation says:
onUserLeaveHint()
is invoked only when the activity is about to go in the background as a result of the user’s action.
The key thing to notice here is that the method should only be called by the system when an Activity is about to go in the background due to some user action. But it gets called even if we fire some implicit intent or launch an app chooser. So some additional checks are required to ignore the invalid calls(if any) made to the onUserLeaveHint()
method
4. Handle UI during Picture-in-picture switch
When the activity enters or exits picture-in-picture mode, you may want to modify the UI of the app. To achieve this, we can override onPictureInPictureModeChanged(boolean, android.content.res.Configuration)
method of the Activity or Fragment. We can check the current state of the app, if it is in PiP or full screen, and make UI modifications
override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) { if (isInPictureInPictureMode) { // Hide elements which are not needed in PiP } else { // Restore the full-screen UI. } }
5. Add Custom Controls on the PiP window
PiP window can display custom controls that users can interact with. You can set a list of custom actions that are available for users while the app is in PiP mode using RemoteAction
A remote action is defined by the following properties:
— Icon
— Title
— Content description
— Pending Intent
Here’s a sample of how we can add build remote action:
val remoteAction = RemoteAction( Icon.createWithResource(context, R.drawable.icon), "Previous", "Previous Song", PendingIntent.getBroadcast(context, requestCode, Intent("com.myapp.customcotrol.action124"), PendingIntent.FLAG_IMMUTABLE))
You can change the controls dynamically as well based on the current state of the app. This means we can hide or add a control on the basis of the app’s business logic. To accomplish this, we can call setPictureInPictureParams
with a new set of remote actions
val actions: ArrayList<RemoteAction> = ArrayList() actions.add(remoteAction) val params = PictureInPictureParams.Builder() //Set the list of actions to the params .setActions(actions) .build() setPictureInPictureParams(params)
Handling Click on custom controls:
Android System will send the broadcast when the user clicks on the custom controls that we have added on the PiP window. This broadcast will have the same action that we added above in the RemoteAction
object.
So to get the callback when the user clicks on custom controls, you will have to register a BroadcastReceiver and check for the action that you have added in the RemoteAction
instance
Now we have covered all the aspects of implementing the PiP mode in the Android app. Also, check the best practices and important points listed below
Important Points to Note and Best Practices to Follow
- Before your app uses PiP, check to be sure it is available by calling
hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
- Android 12 adds the
setSeamlessResizeEnabled
flag, which provides a much smoother cross-fading animation when resizing non-video content in the PiP window. Previously, resizing non-video content in a PiP window could create jarring visual artifacts.
ThesetSeamlessResizeEnabled
flag is set totrue
by default for backward compatibility. Leave this set totrue
for video content, and change it tofalse
for non-video content. - Custom Controls on the PiP window are always displayed with a White color background. Using icons of different colors will have no effect
This was a brief summary of how to implement the PiP mode in Android and since you have reached the bottom of the page, do not forget to add a comment below
References:
https://developer.android.com/develop/ui/views/picture-in-picture