Как настроить приложение для режима "Картинка в картинке"

В теге activity файла AndroidManifest.xml выполните следующие действия:

  1. Добавьте supportsPictureInPicture и задайте для него значение true, чтобы указать, что в приложении будет использоваться режим "Картинка в картинке" (PiP).
  2. Добавьте configChanges и задайте для него значение orientation|screenLayout|screenSize|smallestScreenSize, чтобы указать, что ваше действие обрабатывает изменения конфигурации макета. В этом случае при переходе в режим "Картинка в картинке" и обратно ваше приложение не будет перезапускаться.
<activity
    android:name=".SnippetsActivity"
    android:exported="true"
    android:supportsPictureInPicture="true"
    android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
    android:theme="@style/Theme.Snippets">

В коде Compose выполните следующие действия:

  1. Добавьте это расширение на сайт Context. В этом руководстве вы будете использовать это расширение несколько раз, чтобы получить доступ к действию.
    internal fun Context.findActivity(): ComponentActivity {
        var context = this
        while (context is ContextWrapper) {
            if (context is ComponentActivity) return context
            context = context.baseContext
        }
        throw IllegalStateException("Picture in picture should be called in the context of an Activity")
    }

Добавление режима "Картинка в картинке" при выходе из приложения для версий Android ниже 12

Чтобы добавить режим "Картинка в картинке" для версий Android ниже 12, используйте addOnUserLeaveHintProvider. Чтобы добавить режим "Картинка в картинке" в приложение для Android 11 или более ранней версии, выполните следующие действия:

  1. Добавьте версию, чтобы код был доступен только в версиях O–R.
  2. Используйте DisposableEffect с ключом Context.
  3. Внутри DisposableEffect определите поведение при активации onUserLeaveHintProvider с помощью лямбда-выражения. В лямбда-выражении вызовите метод enterPictureInPictureMode() для объекта findActivity() и передайте ему объект PictureInPictureParams.Builder().build().
  4. Добавьте addOnUserLeaveHintListener, используя findActivity(), и передайте в лямбда-функцию.
  5. В onDispose добавьте removeOnUserLeaveHintListener, используя findActivity() и передав лямбда-выражение.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
    Build.VERSION.SDK_INT < Build.VERSION_CODES.S
) {
    val context = LocalContext.current
    DisposableEffect(context) {
        val onUserLeaveBehavior = Runnable {
            context.findActivity()
                .enterPictureInPictureMode(PictureInPictureParams.Builder().build())
        }
        context.findActivity().addOnUserLeaveHintListener(
            onUserLeaveBehavior
        )
        onDispose {
            context.findActivity().removeOnUserLeaveHintListener(
                onUserLeaveBehavior
            )
        }
    }
} else {
    Log.i("PiP info", "API does not support PiP")
}

Добавление режима "Картинка в картинке" при выходе из приложения для устройств с Android 12 и более поздних версий

В Android 12 и более поздних версиях PictureInPictureParams.Builder добавляется с помощью модификатора, который передается видеопроигрывателю приложения.

  1. Создайте карту modifier и вызовите для нее функцию onGloballyPositioned. Координаты макета будут использоваться на следующем шаге.
  2. Создайте переменную для PictureInPictureParams.Builder().
  3. Добавьте оператор if, чтобы проверить, является ли SDK версией S или более поздней. Если да, добавьте в конструктор setAutoEnterEnabled и задайте для него значение true, чтобы при проведении пальцем включался режим "Картинка в картинке". Это обеспечивает более плавную анимацию, чем при переходе через enterPictureInPictureMode.
  4. Позвоните на номер setPictureInPictureParams(), используя findActivity(). Позвоните по номеру build() на устройстве builder и передайте его.

val pipModifier = modifier.onGloballyPositioned { layoutCoordinates ->
    val builder = PictureInPictureParams.Builder()

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        builder.setAutoEnterEnabled(true)
    }
    context.findActivity().setPictureInPictureParams(builder.build())
}
VideoPlayer(pipModifier)

Используйте setAspectRatio, чтобы задать соотношение сторон окна PiP.

Чтобы задать соотношение сторон окна "Картинка в картинке", выберите определенное соотношение сторон или используйте ширину и высоту видео в проигрывателе. Если вы используете проигрыватель media3, убедитесь, что он не имеет значения null и что размер видео не равен VideoSize.UNKNOWN, прежде чем задавать соотношение сторон.

val context = LocalContext.current

val pipModifier = modifier.onGloballyPositioned { layoutCoordinates ->
    val builder = PictureInPictureParams.Builder()
    if (shouldEnterPipMode && player != null && player.videoSize != VideoSize.UNKNOWN) {
        val sourceRect = layoutCoordinates.boundsInWindow().toAndroidRectF().toRect()
        builder.setSourceRectHint(sourceRect)
        builder.setAspectRatio(
            Rational(player.videoSize.width, player.videoSize.height)
        )
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        builder.setAutoEnterEnabled(shouldEnterPipMode)
    }
    context.findActivity().setPictureInPictureParams(builder.build())
}

VideoPlayer(pipModifier)

Если вы используете собственный проигрыватель, задайте соотношение сторон, указав высоту и ширину проигрывателя с помощью синтаксиса, подходящего для вашего проигрывателя. Если во время инициализации размер проигрывателя изменится и выйдет за допустимые границы соотношения сторон, приложение будет закрыто. Возможно, вам потребуется добавить проверки, чтобы определить, когда можно рассчитать соотношение сторон, как это делается для проигрывателя Media3.