5 Easy Steps to Implement PiP mode in Android

Implementing PiP mode in Android in 5 simple steps

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

Just a sample of picture in picture
Photo by Jakob Owens on Unsplash

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:

PiP mode in Android
Source: https://developer.android.com

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

  1. Before your app uses PiP, check to be sure it is available by calling hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
  2. 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.
    The setSeamlessResizeEnabled flag is set to true by default for backward compatibility. Leave this set to true for video content, and change it to false for non-video content.
  3. 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

Leave a comment