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 for this Activity
in AndroidManifest.xml
:
<activity
...
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 an automatic switch when the user minimizes the application during a call. To track this event, there is a handy method Activity.onUserLeaveHint
called whenever the user intentionally leaves Activity
-- whether via the Home or Recent button.
override fun onUserLeaveHint() {
...
if (isPipSupported && imaginaryCallManager.isInCall)
this.enterPictureInPictureMode()
}
Interface adaptation
Great, now our call screen automatically goes into PIP mode 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 be too small to see anything there anyway.
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 in 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(
Icon.createWithResource(this, R.drawable.ic_baseline_call_end_24),
"End call",
"End call 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)
In addition to the buttons, 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. If you want to know more about developing video calling Android apps, check out our WebRTC on Android guide. Let us know in the comments if you found this article useful 💙
Top comments (0)