Ajouter des vidéos en mode Picture-in-picture (PIP)

À partir d'Android 8.0 (niveau d'API 26), Android autorise le lancement des activités dans mode Picture-in-picture (PIP). Le PIP est un type spécial de mode multifenêtre, utilisé pour la lecture des vidéos. Elle permet à l'utilisateur de regarder une vidéo dans une petite fenêtre épinglée dans un coin de l'écran pendant que vous naviguez entre les applications ou que vous parcourez du contenu sur l'écran principal.

Il exploite les API multifenêtres disponibles dans Android 7.0 pour fournir la une vidéo en superposition épinglée. Pour ajouter le PIP à votre application, vous devez enregistrer votre activités compatibles avec le mode PIP, passez en mode PIP si nécessaire, et Assurez-vous que les éléments de l'interface utilisateur sont masqués et que la lecture de la vidéo se poursuit lorsque l'activité est en mode PIP.

La fenêtre PIP apparaît dans la couche supérieure de l'écran, dans un coin choisi par le système.

Le mode PIP est également pris en charge sur les appareils équipés de l'OS Android TV et exécutants Android 14 (niveau d'API 34) ou version ultérieure Bien qu'il existe de nombreuses similitudes, il existe des considérations supplémentaires lors de l'utilisation PIP sur votre téléviseur

Comment les utilisateurs peuvent-ils interagir avec la fenêtre PIP ?

Les utilisateurs peuvent faire glisser la fenêtre PIP vers un autre emplacement. À partir d'Android 12, les utilisateurs peut également:

  • Appuyez une fois sur la fenêtre pour afficher un bouton du bouton "Paramètres" et des actions personnalisées fournies par votre application (par exemple, lecture de contrôle).

  • Appuyez deux fois sur la fenêtre pour passer de la taille PIP actuelle à la taille maximale ou une taille PIP minimale (par exemple, appuyer deux fois sur une fenêtre agrandie) la minimise, et l'inverse est également vrai.

  • Pour masquer la fenêtre, faites-la glisser vers le bord gauche ou droit. Pour désencombrer appuyez sur la partie visible de la fenêtre placée dans la cachette ou faites-la glisser hors de la fenêtre.

  • Redimensionnez la fenêtre PIP pour zoomer.

Votre application contrôle le moment où l'activité en cours passe en mode PIP. Voici quelques exemples exemples:

  • Une activité peut passer en mode PIP lorsque l'utilisateur appuie sur le bouton d'accueil ou balaie l'écran jusqu'à la maison. C'est ainsi que Google Maps continue d'afficher les itinéraires l'utilisateur exécute une autre activité en même temps.

  • Votre application peut passer une vidéo en mode PIP lorsque l'utilisateur revient en arrière la vidéo pour parcourir d'autres contenus.

  • Votre application peut passer une vidéo en mode PIP pendant qu'un utilisateur regarde la fin d'une épisode de contenu. L'écran principal affiche des promotions ou des résumés sur le prochain épisode de la série.

  • Votre application peut permettre aux utilisateurs de mettre en file d'attente du contenu supplémentaire lorsqu'ils regardent une vidéo. La vidéo continue d'être lue en mode PIP affiche une activité de sélection de contenu.

Déclarer la compatibilité avec le mode PIP

Par défaut, le système ne prend pas automatiquement en charge le mode PIP pour les applications. Si vous voulez prend en charge le PIP dans votre application, enregistrez votre activité vidéo dans votre fichier manifeste en en définissant android:supportsPictureInPicture sur true. Indiquez également que votre l'activité gère les modifications de configuration de mise en page être redémarré lorsque la mise en page est modifiée lors des transitions en mode PIP.

<activity android:name="VideoActivity"
    android:supportsPictureInPicture="true"
    android:configChanges=
        "screenSize|smallestScreenSize|screenLayout|orientation"
    ...

Basculer votre activité en mode PIP

À partir d'Android 12, vous pouvez passer votre activité en mode PIP en configurant définissez l'option setAutoEnterEnabled sur true. Avec ce paramètre, une activité passe automatiquement en mode PIP si nécessaire, sans avoir à appeler explicitement enterPictureInPictureMode() dans onUserLeaveHint. Il s'agit présente l'avantage d'offrir des transitions bien plus fluides. Pour en savoir plus, consultez la section les transitions vers le mode PIP depuis la navigation par gestes

Si vous ciblez Android 11 ou une version antérieure, une activité doit appeler enterPictureInPictureMode() pour passer en mode PIP. Par exemple, le code suivant remplace une activité par Mode PIP lorsque l'utilisateur clique sur un bouton dédié dans l'interface utilisateur de l'application:

Kotlin

override fun onActionClicked(action: Action) {
    if (action.id.toInt() == R.id.lb_control_picture_in_picture) {
        activity?.enterPictureInPictureMode()
        return
    }
}

Java

@Override
public void onActionClicked(Action action) {
    if (action.getId() == R.id.lb_control_picture_in_picture) {
        getActivity().enterPictureInPictureMode();
        return;
    }
    ...
}

Vous pouvez inclure une logique qui bascule une activité en mode PIP à la place. d'aller en arrière-plan. Par exemple, Google Maps passe en mode PIP si l'utilisateur appuie sur le bouton Accueil ou Récents pendant la navigation dans l'application. Vous pouvez interceptez ce cas en remplaçant onUserLeaveHint():

Kotlin

override fun onUserLeaveHint() {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode()
    }
}

Java

@Override
public void onUserLeaveHint () {
    if (iWantToBeInPipModeNow()) {
        enterPictureInPictureMode();
    }
}

Recommandation: offrir aux utilisateurs une expérience de transition PIP soignée

Android 12 a apporté d'importantes améliorations esthétiques aux transitions animées. entre les fenêtres en plein écran et en PIP. Nous vous recommandons vivement d'implémenter modifications applicables Ces modifications s'adaptent automatiquement les grands écrans, tels que les pliables et les tablettes, sans nécessiter d'efforts supplémentaires.

Si votre application n'inclut pas de mises à jour applicables, les transitions PIP sont toujours fonctionnelle, mais les animations sont moins soignées. Par exemple, la transition le mode plein écran au mode PIP peut entraîner la disparition de la fenêtre avant qu'elle ne réapparaisse une fois la transition terminée.

Ces modifications impliquent les éléments suivants.

  • Rendre les transitions vers le mode PIP plus fluides depuis la navigation par gestes
  • Définir un sourceRectHint approprié pour accéder au mode PIP et le quitter
  • Désactiver le redimensionnement fluide pour les contenus autres que vidéo

Reportez-vous à la section Android Exemple PictureInPicture en Kotlin comme référence pour une transition soignée.

Transitions vers le mode PIP plus fluides depuis la navigation par gestes

À partir d'Android 12, l'indicateur setAutoEnterEnabled fournit beaucoup Animation plus fluide pour passer au contenu vidéo en mode PIP à l'aide d'un geste navigation, par exemple lorsque vous balayez l'écran vers le haut pour accéder à l'accueil depuis le mode plein écran.

Pour effectuer cette modification, procédez comme suit et consultez cet exemple pour découvrir référence:

  1. Utiliser setAutoEnterEnabled pour construire PictureInPictureParams.Builder:

    Kotlin

    setPictureInPictureParams(PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build())
    

    Java

    setPictureInPictureParams(new PictureInPictureParams.Builder()
        .setAspectRatio(aspectRatio)
        .setSourceRectHint(sourceRectHint)
        .setAutoEnterEnabled(true)
        .build());
    
  2. Appelez setPictureInPictureParams avec les PictureInPictureParams d'avance. L'application n'attend pas que Rappel onUserLeaveHint (comme cela aurait été le cas avec Android 11).

    Par exemple, vous pouvez appeler setPictureInPictureParams au niveau de la première et les suivantes en cas de modification du format.

  3. Appelez setAutoEnterEnabled(false), mais uniquement lorsque cela est nécessaire. Par exemple : vous ne voudrez probablement pas passer en mode PIP si la lecture en cours est en pause state.

Définissez un sourceRectHint approprié pour accéder au mode PIP et le quitter.

À partir de l'introduction du PIP dans Android 8.0, setSourceRectHint indique la partie de l'activité qui est visible après la transition vers Picture-in-picture (les limites de la vue d'un lecteur vidéo, par exemple)

Avec Android 12, le système utilise sourceRectHint pour implémenter une interface lors de l'entrée et de la sortie du mode PIP.

Pour configurer correctement sourceRectHint afin d'activer et de quitter le mode PIP:

  1. Construire PictureInPictureParams en utilisant les limites appropriées comme sourceRectHint. Nous vous recommandons également de joindre un écouteur de changement de mise en page du lecteur vidéo:

    Kotlin

    val mOnLayoutChangeListener =
    OnLayoutChangeListener { v: View?, oldLeft: Int,
            oldTop: Int, oldRight: Int, oldBottom: Int, newLeft: Int, newTop:
            Int, newRight: Int, newBottom: Int ->
        val sourceRectHint = Rect()
        mYourVideoView.getGlobalVisibleRect(sourceRectHint)
        val builder = PictureInPictureParams.Builder()
            .setSourceRectHint(sourceRectHint)
        setPictureInPictureParams(builder.build())
    }
    
    mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener)
    

    Java

    private final View.OnLayoutChangeListener mOnLayoutChangeListener =
            (v, oldLeft, oldTop, oldRight, oldBottom, newLeft, newTop, newRight,
            newBottom) -> {
        final Rect sourceRectHint = new Rect();
        mYourVideoView.getGlobalVisibleRect(sourceRectHint);
        final PictureInPictureParams.Builder builder =
            new PictureInPictureParams.Builder()
                .setSourceRectHint(sourceRectHint);
        setPictureInPictureParams(builder.build());
    };
    
    mYourVideoView.addOnLayoutChangeListener(mOnLayoutChangeListener);
    
  2. Si nécessaire, mettez à jour sourceRectHint avant que le système ne démarre le quitter la transition. Lorsque le système est sur le point de quitter le mode PIP, l'activité la hiérarchie des vues est disposée dans sa configuration de destination (par exemple, plein écran). L'application peut associer un écouteur de changement de mise en page à sa vue racine. ou la vue cible (comme celle du lecteur vidéo) pour détecter l'événement et Mettez à jour sourceRectHint avant le début de l'animation.

    Kotlin

    // Listener is called immediately after the user exits PiP but before animating.
    playerView.addOnLayoutChangeListener { _, left, top, right, bottom,
                        oldLeft, oldTop, oldRight, oldBottom ->
        if (left != oldLeft
            || right != oldRight
            || top != oldTop
            || bottom != oldBottom) {
            // The playerView's bounds changed, update the source hint rect to
            // reflect its new bounds.
            val sourceRectHint = Rect()
            playerView.getGlobalVisibleRect(sourceRectHint)
            setPictureInPictureParams(
                PictureInPictureParams.Builder()
                    .setSourceRectHint(sourceRectHint)
                    .build()
            )
        }
    }
    
    

    Java

    // Listener is called right after the user exits PiP but before
    // animating.
    playerView.addOnLayoutChangeListener((v, left, top, right, bottom,
                        oldLeft, oldTop, oldRight, oldBottom) -> {
        if (left != oldLeft
            || right != oldRight
            || top != oldTop
            || bottom != oldBottom) {
            // The playerView's bounds changed, update the source hint rect to
            // reflect its new bounds.
            final Rect sourceRectHint = new Rect();
            playerView.getGlobalVisibleRect(sourceRectHint);
            setPictureInPictureParams(
                new PictureInPictureParams.Builder()
                    .setSourceRectHint(sourceRectHint)
                    .build());
        }
    });
    
    

Désactiver le redimensionnement fluide pour les contenus autres que vidéo

Android 12 ajoute l'indicateur setSeamlessResizeEnabled, qui offre beaucoup animation en fondu enchaîné plus fluide lors du redimensionnement du contenu autre que vidéo dans la fenêtre PIP fenêtre. Auparavant, le redimensionnement d'un contenu autre que vidéo dans une fenêtre PIP pouvait créer des artefacts visuels troublants.

Pour désactiver le redimensionnement fluide pour les contenus autres que vidéo:

Kotlin

setPictureInPictureParams(PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(false)
    .build())

Java

setPictureInPictureParams(new PictureInPictureParams.Builder()
    .setSeamlessResizeEnabled(false)
    .build());

Gérer l'UI en mode PIP

Lorsque l'activité passe en mode PIP ou la quitte, le système appelle Activity.onPictureInPictureModeChanged() ou Fragment.onPictureInPictureModeChanged().

Vous devez ignorer ces rappels pour redessiner les éléments d'interface utilisateur de l'activité. Conserver n'oubliez pas qu'en mode PIP, votre activité s'affiche dans une petite fenêtre. Les utilisateurs ne peuvent pas interagissent avec les éléments d'interface utilisateur de votre application en mode PIP, et avec les détails les petits éléments d'interface utilisateur peuvent être difficiles à voir. Activités de lecture de vidéos avec une interface utilisateur minimale offre la meilleure expérience utilisateur.

Si votre application doit fournir des actions personnalisées pour le mode PIP, consultez la section Ajouter de commande sur cette page. Supprimez les autres éléments de l'interface utilisateur avant votre l'activité passe en mode PIP et la restaure lorsque votre activité passe en plein écran à nouveau:

Kotlin

override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean,
                                           newConfig: Configuration) {
    if (isInPictureInPictureMode) {
        // Hide the full-screen UI (controls, etc.) while in PiP mode.
    } else {
        // Restore the full-screen UI.
    }
}

Java

@Override
public void onPictureInPictureModeChanged (boolean isInPictureInPictureMode, Configuration newConfig) {
    if (isInPictureInPictureMode) {
        // Hide the full-screen UI (controls, etc.) while in PiP mode.
    } else {
        // Restore the full-screen UI.
        ...
    }
}

Ajouter des commandes

La fenêtre PIP peut afficher des commandes lorsque l'utilisateur ouvre le menu de la fenêtre (par en appuyant sur la fenêtre d'un appareil mobile ou en sélectionnant le menu sur le téléviseur. la télécommande).

Si une application comporte un support actif de la série TV, puis de lire les commandes Pause, Suivant et précédent s’affichent.

Vous pouvez également spécifier explicitement des actions personnalisées en créant PictureInPictureParams par PictureInPictureParams.Builder.setActions() avant de passer en mode PIP, et transmettez les paramètres lorsque vous passez en mode PIP à l'aide de enterPictureInPictureMode(android.app.PictureInPictureParams) ou setPictureInPictureParams(android.app.PictureInPictureParams). Soyez vigilant. Si vous essayez d'ajouter plus de getMaxNumPictureInPictureActions(), vous n'obtiendrez que le nombre maximum.

Poursuite de la lecture de la vidéo en mode PIP

Lorsque votre activité passe en mode PIP, le système la place dans le et appelle la méthode onPause(). Vidéo la lecture ne doit pas être mise en pause et doit se poursuivre si l'activité est suspendu pendant le passage en mode PIP.

Sur Android 7.0 ou version ultérieure, vous devez mettre en pause et reprendre la lecture d'une vidéo lorsque l'icône le système appelle l'API onStop() et onStart(). Ainsi, vous éviterez d'avoir à vérifier si votre application est en mode PIP dans onPause(). poursuivre explicitement la lecture.

Si vous n'avez pas défini l'option setAutoEnterEnabled sur true et que vous devez suspendez la lecture dans votre implémentation onPause(), recherchez le mode PIP en appelant isInPictureInPictureMode() et gérez la lecture de manière appropriée. Exemple :

Kotlin

override fun onPause() {
    super.onPause()
    // If called while in PiP mode, do not pause playback
    if (isInPictureInPictureMode) {
        // Continue playback
    } else {
        // Use existing playback logic for paused Activity behavior.
    }
}

Java

@Override
public void onPause() {
    // If called while in PiP mode, do not pause playback
    if (isInPictureInPictureMode()) {
        // Continue playback
        ...
    } else {
        // Use existing playback logic for paused Activity behavior.
        ...
    }
}

Lorsque votre activité passe du mode PIP au mode plein écran, le système reprend votre activité et appelle votre onResume().

Utiliser une activité de lecture unique pour le mode PIP

Dans votre application, un utilisateur peut sélectionner une nouvelle vidéo lorsqu'il recherche du contenu sur la l'écran principal, tandis qu'une activité de lecture vidéo est en mode PIP. Lire la nouvelle vidéo dans l'activité de lecture existante en mode plein écran, au lieu de lancer une nouvelle activité susceptible de désorienter l'utilisateur.

Pour garantir qu'une seule activité est utilisée pour les demandes de lecture vidéo et qu'elle bascule en mode PIP selon les besoins, définissez le android:launchMode de l'activité sur singleTask dans votre fichier manifeste:

<activity android:name="VideoActivity"
    ...
    android:supportsPictureInPicture="true"
    android:launchMode="singleTask"
    ...

Dans votre activité, ignorer onNewIntent() gérer la nouvelle vidéo et arrêter la lecture de la vidéo existante si nécessaire.

Bonnes pratiques

Il est possible que le mode PIP soit désactivé sur les appareils à faible RAM. Avant que votre application utilise le PIP, vérifiez qu'elle est disponible en appelant hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE).

Le mode PIP est destiné aux activités qui incluent des vidéos en plein écran. Lorsque vous changez de en mode PIP, évitez de montrer autre chose que du contenu vidéo. Suivre quand votre activité passe en mode PIP et masque les éléments d'interface utilisateur, comme décrit dans la section Gérer l'interface utilisateur pendant le PIP.

Par défaut, lorsqu'une activité est en mode PIP, elle n'est pas sélectionnée. À recevoir des événements d'entrée en mode PIP, utilisez MediaSession.setCallback(). Pour en savoir plus sur l'utilisation de setCallback(), consultez la section Afficher un En écoute carte.

Lorsque votre application est en mode PIP, la lecture vidéo dans la fenêtre PIP peut entraîner des problèmes de son des interférences avec une autre application, telle qu'une application de lecteur de musique ou de recherche vocale ; Pour éviter cela, demandez la priorité audio lorsque vous lancez la lecture de la vidéo et notifications de changement de focus audio, comme décrit dans la section Gérer l'audio Mise au point. Si vous recevez une notification de perte de la focalisation audio en mode PIP, mettre en pause ou arrêter la lecture vidéo.

Lorsque votre appli est sur le point de passer en mode PIP, notez que seule l'activité principale entre en mode Picture-in-picture. Dans certains cas, par exemple sur les appareils multifenêtres, l'activité ci-dessous s'affichera désormais et sera de nouveau visible en même temps l'activité PIP. Vous devez gérer cette situation en conséquence, y compris activité ci-dessous pour obtenir un rappel onResume() ou onPause(). Il est également il est possible que l'utilisateur interagisse avec l'activité. Par exemple, si vous avez une liste de vidéos et une activité vidéo en mode PIP, l'utilisateur peut sélectionner une nouvelle vidéo dans la liste, et l'activité PIP doit se mettre à jour. en conséquence.

Exemples de code supplémentaires

Pour télécharger une application exemple écrite en Kotlin, consultez la page Exemple Android PictureInPicture. (Kotlin)