Shivam Dhuria I’m an Android Developer. I spend my days experimenting with Kotlin, Swift, and React. I build apps that delight and inform and am proficient in i18n, i10n, and accessibility.

Implementing Picture-in-Picture mode on Android

4 min read 1347

Android Logo Over a Background of Picture Frames

Implementing Picture-in-Picture (PiP) mode in your mobile apps is extremely beneficial for your users, especially when your app displays data or content of high priority. For example, your app can display navigation directions, sports updates, or run a video call in the PiP window even when the user navigates away from the app.

In this tutorial, we will learn to implement Picture-in-Picture mode to enhance our users’ experience.

What is Picture-in-Picture mode?

PiP mode allows users to open multiple applications simultaneously leveraging Android’s multi-window APIs. If a user is running an app and presses the home button, the app doesn’t fully close and can continue running in PiP mode, hovering on the screen while the user interacts with other applications.

Map in PiP Mode

Setting up our Android app

PiP mode is only supported on devices starting from Android 8.0 (API level 26) and above. Go to your app’s build.gradle file and set the minSdk version to 26, like so:

defaultConfig {
    applicationId "com.example.pip"
    minSdk 26
    targetSdk 30
    ...
}

Next, decide what screen in your app requires PiP mode. It is not imperative that all screens in your application require PiP mode, as Android lets you set PiP mode for only specific screens of the app.

To enable PiP mode for any activity, go to the AndroidManifest.xml file and make the following changes for that activity:

<activity
    android:name=".MainActivity"
    android:exported="true"
    //Add the following line
    android:supportsPictureInPicture="true">
</activity>

For brevity in this tutorial, the main screen in our app plays a simple animation loop. We want it to be displayed in PiP mode while the user interacts with other apps.

Currently, if the user presses the home button, our app disappears. Let’s now incorporate PiP mode for our app.

Implementing PiP mode on Android

We want to trigger PiP mode in our Android app for two scenarios:

We made a custom demo for .
No really. Click here to check it out.

  • When the user presses the Home button
  • When the user presses the Enter PiP Mode button in the app

To implement PiP mode, go to the MainActivity file and make the following changes:

override fun onCreate(savedInstanceState: Bundle?) {
    //listener for button click
    button.setOnClickListener {
        enterPipMode()
    }
}
  //This method is triggered when 
  //Home button is pressed.
override fun onUserLeaveHint() {
    enterPipMode()
}

private fun enterPipMode() {
    val params = PictureInPictureParams.Builder().build();
    enterPictureInPictureMode(params)
}

After making the above changes in our code block, we can transition into PiP mode correctly.

Changing the aspect ratio of the PiP window

Depending upon your application, you can also customize the aspect ratio of the PiP window. If your application screen shows important content in a landscape view, such as a video, you might want to show the PiP window with a 16:9 aspect ratio.

This will help crop out unnecessary information from the PiP window so that only the important content you want to be displayed occupies the entire width and height of the PiP window.

We can also modify the aspect ratio of the PiP window by using the setAspectRatio() method. The aspect ratio can be set to the PictureInPictureParams, as shown below.

private fun enterPipMode() {
    val aspectRatio = Rational(16, 9)
    val params = PictureInPictureParams
        .Builder()
        .setAspectRatio(aspectRatio)
        .build()
    enterPictureInPictureMode(params)
}

The above code sets the aspect ratio to 16:9, so our app should now look like this in PiP mode:

PiP in 16:9

To make the PiP widow square, you can set the aspect ratio to 1:1 by making the following changes:

val aspectRatio = Rational(1, 1)
val params = PictureInPictureParams
    .Builder()
    .setAspectRatio(aspectRatio)
    .build()
enterPictureInPictureMode(params)

PiP as a Square Window

Now it’s a square!

Adjusting window size in PiP mode

Now that we’ve learned how to implement PiP mode and adjust the window’s aspect ratio, we need to consider the app’s PiP window size.

In PiP mode, notice that the window size is much smaller than a normal activity screen. This means that the user might not be able to interact with or even see smaller details on the screen.

It is a good idea to only show details in the app that are crucial in PiP mode and hide all unimportant details. It’s also critical to restore the views when the user switches to normal full-screen activity.

Let’s check out an example. Below, our Android app contains a ton of unimportant details that are not usable or applicable in PiP mode, such as the Android icon, the button, and excess text.

We need to hide this text when the user enters PiP mode, but reveal it when the user views the screen in fullscreen.

Text in Full Screen

To hide and restore these views, go to the MainActivity file and add the following code:

override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
    if (isInPictureInPictureMode) {
        //hide all unimportant views
        image.visibility = GONE
        button.visibility = GONE
        heading.visibility = GONE
        description.visibility = GONE
    } else {
        //show all unimportant views
        image.visibility = VISIBLE
        button.visibility = VISIBLE
        heading.visibility = VISIBLE
        description.visibility = VISIBLE
    }
}

As you can see, now only the important aspects of our app are shown in PiP mode. When a user clicks on our app, it expands to full-screen and reveals the text.

Setting custom actions in Android’s PiP mode

PiP mode does provide a way for the user to interact with the app. 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

You can add a list of remote actions to be taken in the PiP window. For this example, we will add an information button in the PiP window, which, when clicked, opens a web browser.

To add this action, make the following changes to the MainActivity file.

private fun enterPipMode() {
    val actions: ArrayList<RemoteAction> = ArrayList()
    val remoteAction = RemoteAction(
        Icon.createWithResource([email protected], 
          android.R.drawable.ic_menu_info_details),
          "Info","Info Details",
        PendingIntent.getActivity([email protected], 0, 
        Intent(Intent.ACTION_VIEW, Uri.parse("http://www.google.com")), 0)
    )
    //Add the above action to the List
    actions.add(remoteAction)
    val aspectRatio = Rational(16, 9)
    val params = PictureInPictureParams
        .Builder()
        .setAspectRatio(aspectRatio)
    //Set the list of actions to the params
        .setActions(actions)
        .build()
    enterPictureInPictureMode(params)
}

Now, when the info button in the window is pressed, a custom action opens the web browser. With this code, you can add several varied actions for the use cases in your app.

🗒️ Note: If an app has a video playing, then play, pause, next, and previous controls will appear by default.

Best practices when implementing PiP mode

To make sure that there are no multiple instances of the same activity running, we need to set the launch mode of the PiP activities to singleTask in the AndroidManifest file.

android:launchMode="singleTask"

Once we do, the same instance of the activity will be maintained whether in full-screen mode or in PiP mode.

We also need to ensure that the activity does not lose any data when the configuration of an activity is changed. To do this, add this code to the AndroidManifest file:

android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"

Now the AndroidManifest file should look like this:

<activity
    android:name=".MainActivity"
    android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
    android:exported="true"
    android:launchMode="singleTask"
    android:supportsPictureInPicture="true">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

Conclusion

In this tutorial, we have successfully implemented PiP mode within an Android application, including how to add PiP to an Android activity, set the PiP window’s aspect ratio and size, and detect a transition from an activity to PiP and vice versa.

PiP mode should only be used when your app needs to display critical information to the user, as it can become obtrusive otherwise. Check out the final code for our app on GitHub.

: Full visibility into your web apps

LogRocket is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

.
Shivam Dhuria I’m an Android Developer. I spend my days experimenting with Kotlin, Swift, and React. I build apps that delight and inform and am proficient in i18n, i10n, and accessibility.

Leave a Reply