In the previous article of the series we explained how to make a custom call notification on Android? This time we’ll talk about the picture-in picture mode.  

In recent years, smartphones have become increasingly close to computers in terms of functionality, and many are already replacing the PC as their primary tool for work. The advantage of personal computers was multi-window capability, which remained unavailable on smartphones. But with the release of Android 7.0, this began to change and multi-window support appeared.

It’s hard to overestimate the convenience of a small floating window with the video of the interlocutor when the call is minimized — you can continue the dialogue and simultaneously take notes or clarify some information. Android has two options for implementing this functionality: support for the application in a floating window and a picture-in-picture mode. Ideally, an application should support both approaches, but the floating window is more difficult to develop and imposes certain restrictions on the overall application design, so let’s consider picture-in-picture (PiP) on Android as a relatively simple way to bring multi-window support into your application.

Switching to PIP mode

Picture-in-picture mode is supported on most devices with Android 8 and above. Accordingly, if you support system versions lower than this, all PIP mode-related calls should be wrapped in the system version check:

 
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
// Something related to PiP   
}
 

The entire `Activity` is converted to PIP, and first you need to declare PIP support and that “Activity” handles configuration changes in `AndroidManifest.xml`:

 
 activity
…
android:configChanges="screenSize|smallestScreenSize|screenLayout|
orientation"
android:supportsPictureInPicture="true" /
 

Before using picture-in-picture it is necessary to make sure that the user’s device supports this mode, to do this we turn to the `PackageManager`.

 
 val isPipSupported = context.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
 

After that, in its simplest form, the transition to picture-in-picture mode is done literally with one line:

 
 this.enterPictureInPictureMode()
 

But to go to it, you need to know when it is convenient for the user. You can make a separate button and jump when you click on it. The most common approach is automatic switch when the user minimizes the application during a call, such as using the Home or Recent button

Starting with Android 12, this behavior can be implemented by setting PictureInPictureParams with the setAutoEnterEnabled flag on the Activity:

 
 val pipParams = PictureInPictureParams.Builder()
.setAutoEnterEnabled(true)
.build()
setPictureInPictureParams(pipParams)
 

On devices with Android 11 or lower, an activity must explicitly call enterPictureInPictureMode() in `Activity.onUserLeaveHint`:

 
 override fun onUserLeaveHint() {
...
if (isPipSupported && imaginaryCallManager.isInCall)

this.enterPictureInPictureMode()
}
 

Interface adaptation

Great, now our call screen automatically goes into picture-in-picture on Android! But there are often “end call” or “change camera” buttons, and they will not work in this mode. It’s better to hide them when transitioning.

To track the transition to / from PIP mode, `Activity` and `Fragment` have a method `onPictureInPictureModeChanged`. Let’s redefine it and hide unnecessary interface elements

 
 override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration?
) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
setIsUiVisible(isInPictureInPictureMode)
}
 

The PIP window is quite small, so it makes sense to hide everything except the interlocutor’s video, including the local user’s video — it will beThe PIP window is quite small, so it makes sense to hide everything except the interlocutor’s video, including the local user’s video — it will be too small to see anything there anyway.

PiP on Android

Customization

The PIP window can be further customized by passing `PictureInPictureParams` in a call to `enterPictureInPictureMode`. There are not many customization options, but the option to add buttons to the bottom of the window deserves special attention. This is a nice way to keep the screen interactive despite the fact that the regular buttons stop working when the user activates the PIP mode.

The maximum number of buttons you can add depends on many factors, but you can always add at least three. All buttons over the limit simply won’t be shown, so it’s better to place the especially important ones at the beginning. You can find out the exact limit in the current configuration through the method `Activity`:

 
 this.maxNumPictureInPictureActions
 

Let’s add an End call button to our PIP window. To start with, just like with notifications, we need a `PendingIntent`, which will be responsible for telling our application that the button has been pressed. If this is the first time you’ve heard of `PendingIntent’—you can learn more about them in our last article.

After that, we can start creating the actual button description, namely `RemoteAction`.

 
 val endCallPendingIntent = getPendingIntent()
val endCallAction = RemoteAction(
// An icon for a button. The color will be ignored and changed to a system color 
Icon.createWithResource(this, R.drawable.ic_baseline_call_end_24),
// Text of the button that won't be shown  
"End call",
// ContentDescription для screen readers
"End call button",
// Our PendingIntent  that'll be launched upon pressing the button  
endCallPendingIntent
)
 

Our “action” is ready, now we need to add it to the PIP parameters and, subsequently, to the mode transition call.

Let’s start by creating a Builder for our customization parameters:

 
val pipParams = PictureInPictureParams.Builder()
.setActions(listOf(endCallAction))
.build()
this.enterPictureInPictureMode(pipParams)
 
Picture-in-picture customization in an Android app

Starting with Android 8, you can define the area of the screen that will be displayed when Activity switches to PIP. You can do this with setSourceRectHint method:

In addition to the buttons and the visible area of the screen, through the parameters you can set the aspect ratio of the PIP features on Android or the animation of switching to this mode.

Conclusion  

We have considered a fairly simple but very handy variant of using the multi-window feature to improve the user experience, learned how to add buttons to the PIP window on Android and adapt our interface when switching to and from this mode.
In the next article we’ll cover audio output switching for your Android calling apps on WebRTC.

  • Development