Recevoir du contenu enrichi

Figure 1. L'API unifiée fournit un emplacement unique pour gérer le contenu entrant, quel que soit le mécanisme d'UI spécifique, comme le collage à partir du menu "Appuyer de manière prolongée" ou l'utilisation du glisser-déposer.

Les utilisateurs apprécient les images, les vidéos et autres contenus expressifs, mais il n'est pas toujours facile de les insérer et de les déplacer dans les applications. Pour simplifier la réception de contenu enrichi par les applications, Android 12 (niveau d'API 31) introduit une API unifiée qui permet à votre application d'accepter du contenu provenant de n'importe quelle source : presse-papiers, clavier ou glisser-déposer.

Vous pouvez associer une interface, telle que OnReceiveContentListener, à des composants d'UI et obtenir un rappel lorsque du contenu est inséré par le biais d'un mécanisme quelconque. Le rappel devient le seul endroit où votre code peut gérer la réception de tous les contenus, du texte brut et stylisé au balisage, en passant par les images, les vidéos, les fichiers audio et autres.

Pour assurer la rétrocompatibilité avec les versions précédentes d'Android, cette API est également disponible dans AndroidX, à partir de Core 1.7 et Appcompat 1.4, que nous vous recommandons d'utiliser lorsque vous implémentez cette fonctionnalité.

Présentation

Avec les autres API existantes, chaque mécanisme d'UI (comme le menu "Appuyer de manière prolongée" ou le glisser-déposer) possède sa propre API correspondante. Cela signifie que vous devez intégrer chaque API séparément, en ajoutant un code similaire pour chaque mécanisme qui insère du contenu :

Image montrant les différentes actions et l'API correspondante à implémenter
Figure 2 : Auparavant, les applications implémentaient une API différente pour chaque mécanisme d'UI permettant d'insérer du contenu.

L'API OnReceiveContentListener consolide ces différents chemins de code sous la forme d'une seule API à implémenter. Vous pouvez ainsi vous concentrer sur la logique propre à votre application et laisser la plate-forme gérer le reste :

Image montrant l'API unifiée simplifiée
Figure 3 : L'API unifiée vous permet d'implémenter une seule API compatible avec tous les mécanismes d'UI.

Cette approche signifie également que lorsque de nouvelles façons d'insérer du contenu sont ajoutées à la plate-forme, vous n'avez pas besoin d'apporter de modifications supplémentaires au code pour activer la prise en charge dans votre application. Si votre application doit implémenter une personnalisation complète pour un cas d'utilisation particulier, vous pouvez toujours utiliser les API existantes, qui continuent de fonctionner de la même manière.

Implémentation

L'API est une interface d'écouteur avec une seule méthode, OnReceiveContentListener. Pour prendre en charge les anciennes versions de la plate-forme Android, nous vous recommandons d'utiliser l'interface OnReceiveContentListener correspondante dans la bibliothèque AndroidX Core.

Pour utiliser l'API, implémentez le listener en spécifiant les types de contenus que votre application peut gérer :

Kotlin

object MyReceiver : OnReceiveContentListener {
    val MIME_TYPES = arrayOf("image/*", "video/*")
    
    // ...
    
    override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
        TODO("Not yet implemented")
    }
}

Java

public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
     // ...
}

Après avoir spécifié tous les types MIME de contenu compatibles avec votre application, implémentez le reste de l'écouteur :

Kotlin

class MyReceiver : OnReceiveContentListener {
    override fun onReceiveContent(view: View, contentInfo: ContentInfoCompat): ContentInfoCompat {
        val split = contentInfo.partition { item: ClipData.Item -> item.uri != null }
        val uriContent = split.first
        val remaining = split.second
        if (uriContent != null) {
            // App-specific logic to handle the URI(s) in uriContent.
        }
        // Return anything that your app didn't handle. This preserves the
        // default platform behavior for text and anything else that you aren't
        // implementing custom handling for.
        return remaining
    }

    companion object {
        val MIME_TYPES = arrayOf("image/*", "video/*")
    }
}

Java

 public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};

     @Override
     public ContentInfoCompat onReceiveContent(View view, ContentInfoCompat contentInfo) {
         Pair<ContentInfoCompat, ContentInfoCompat> split = contentInfo.partition(
                 item -> item.getUri() != null);
         ContentInfo uriContent = split.first;
         ContentInfo remaining = split.second;
         if (uriContent != null) {
             // App-specific logic to handle the URI(s) in uriContent.
         }
         // Return anything that your app didn't handle. This preserves the
         // default platform behavior for text and anything else that you aren't
         // implementing custom handling for.
         return remaining;
     }
 }

Si votre application est déjà compatible avec le partage avec intents, vous pouvez réutiliser votre logique spécifique à l'application pour gérer les URI de contenu. Renvoie toutes les données restantes pour déléguer la gestion de ces données à la plate-forme.

Après avoir implémenté l'écouteur, définissez-le sur les éléments d'UI appropriés de votre application :

Kotlin

class MyActivity : Activity() {
    public override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // ...
        val myInput = findViewById(R.id.my_input)
        ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, MyReceiver())
    }
}

Java

public class MyActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         // ...

         AppCompatEditText myInput = findViewById(R.id.my_input);
         ViewCompat.setOnReceiveContentListener(myInput, MyReceiver.MIME_TYPES, new MyReceiver());
     }
}

Autorisations URI

Les autorisations de lecture sont accordées et libérées automatiquement par la plate-forme pour tous les URI de contenu présents dans la charge utile transmise à OnReceiveContentListener.

Normalement, votre application traite les URI de contenu dans un service ou une activité. Pour les traitements de longue durée, utilisez WorkManager. Lorsque vous implémentez cette fonctionnalité, étendez les autorisations au service ou à l'activité cibles en transmettant le contenu à l'aide de Intent.setClipData et en définissant l'indicateur FLAG_GRANT_READ_URI_PERMISSION.

Vous pouvez également utiliser un thread d'arrière-plan dans le contexte actuel pour traiter le contenu. Dans ce cas, vous devez conserver une référence à l'objet payload reçu par l'écouteur pour vous assurer que les autorisations ne sont pas révoquées prématurément par la plate-forme.

Vues personnalisées

Si votre application utilise une sous-classe View personnalisée, veillez à ce que OnReceiveContentListener ne soit pas contourné.

Si votre classe View remplace la méthode onCreateInputConnection, utilisez l'API Jetpack InputConnectionCompat.createWrapper pour configurer InputConnection.

Si votre classe View remplace la méthode onTextContextMenuItem, déléguez à la super-classe lorsque l'élément de menu est R.id.paste ou R.id.pasteAsPlainText.

Comparaison avec l'API Keyboard Image

Vous pouvez considérer l'API OnReceiveContentListener comme la prochaine version de l'API Keyboard Image existante. Cette API unifiée est compatible avec les fonctionnalités de l'API Keyboard Image, ainsi qu'avec d'autres fonctionnalités. La compatibilité des appareils et des fonctionnalités varie selon que vous utilisez la bibliothèque Jetpack ou les API natives du SDK Android.

Tableau 1. Fonctionnalités et niveaux d'API compatibles pour Jetpack.
Action ou fonctionnalité Prise en charge par l'API Keyboard Image Prise en charge par l'API unifiée
Insérer depuis le clavier Oui (niveau d'API 13 et versions ultérieures) Oui (niveau d'API 13 et versions ultérieures)
Insérer du contenu à l'aide de l'option "Coller" du menu "Appuyer de manière prolongée" Non Oui
Insérer à l'aide du glisser-déposer Non Oui (niveau d'API 24 et supérieur)
Tableau 2. Fonctionnalités et niveaux d'API compatibles pour les API natives.
Action ou fonctionnalité Prise en charge par l'API Keyboard Image Prise en charge par l'API unifiée
Insérer depuis le clavier Oui (niveau d'API 25 et versions ultérieures) Oui (Android 12 et versions ultérieures)
Insérer du contenu à l'aide de l'option "Coller" du menu "Appuyer de manière prolongée" Non
Insérer à l'aide du glisser-déposer Non