Ricevi contenuti avanzati

Figura 1. L'API unificata offre un'unica posizione contenuti in entrata a prescindere dal meccanismo specifico dell'interfaccia utente, ad esempio incollando dal tocco e tieni premuto il menu o trascina.

Gli utenti amano immagini, video e altri contenuti espressivi, ma inserendo e spostare questi contenuti nelle app non è sempre facile. Per semplificare la gestione delle ricevere contenuti avanzati, Android 12 (livello API 31) introduce un'API unificata che consente alla tua app di accettare contenuti da qualsiasi origine: appunti, tastiera o trascinamento.

Puoi collegare un'interfaccia, ad esempio OnReceiveContentListener, ai componenti dell'interfaccia utente e ricevere un callback quando il contenuto viene inserito tramite meccanismo di attenzione. Il callback diventa l'unica posizione da gestire per il codice ricevere tutti i contenuti, da testo normale e con stili a markup, immagini, video file audio e altri ancora.

Per la compatibilità con le versioni precedenti di Android, questa API è disponibile anche in AndroidX, a partire da Core 1.7 e AppCompat 1.4, che ti consigliamo di utilizzare per implementare questa funzionalità.

Panoramica

Con le altre API esistenti, ogni meccanismo dell'interfaccia utente, ad esempio il menu Tocca e tieni premuto o il trascinamento, ha la propria API corrispondente. Ciò significa che devi si integrano con ogni API separatamente, aggiungendo codice simile per ogni meccanismo che inserisce contenuto:

Un'immagine che mostra le diverse azioni e l'API relativa da implementare
Figura 2. In precedenza, le app implementavano un'API diversa per ogni meccanismo di UI per l'inserimento di contenuti.

L'API OnReceiveContentListener consolida questi diversi percorsi di codice in creando un'unica API da implementare, così potrai concentrarti sulla logica specifica dell'app e lasciare che sia la piattaforma a occuparsi del resto:

Un'immagine che mostra l'API unificata semplificata
Figura 3. L'API unificata ti consente di implementare una singola API che supporta tutti i meccanismi dell'interfaccia utente.

Questo approccio implica anche che, quando vengono aggiunti nuovi modi di inserire contenuti piattaforma, non devi apportare ulteriori modifiche al codice per abilitare il supporto all'interno dell'app. E se la tua app deve implementare la personalizzazione completa per caso d'uso specifico, puoi comunque usare le API esistenti, che continuano allo stesso modo.

Implementazione

L'API è un'interfaccia di listener con un unico metodo, OnReceiveContentListener. Per supportare le versioni precedenti della piattaforma Android, ti consigliamo di utilizzare l'interfaccia corrispondente OnReceiveContentListener nella libreria AndroidX Core.

Per utilizzare l'API, implementa l'ascoltatore specificando i tipi di contenuti che la tua app può gestire:

KotlinJava
object MyReceiver : OnReceiveContentListener {
    val MIME_TYPES = arrayOf("image/*", "video/*")
    
    // ...
    
    override fun onReceiveContent(view: View, payload: ContentInfoCompat): ContentInfoCompat? {
        TODO("Not yet implemented")
    }
}
public class MyReceiver implements OnReceiveContentListener {
     public static final String[] MIME_TYPES = new String[] {"image/*", "video/*"};
     // ...
}

Dopo aver specificato tutti i tipi MIME di contenuti supportati dall'app, implementa il resto di chi ascolta:

KotlinJava
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/*")
    }
}
 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;
     }
 }

Se la tua app supporta già la condivisione con intent, puoi riutilizzare i tuoi logica specifica dell'app per la gestione degli URI dei contenuti. Restituire i dati rimanenti per delegare la gestione di questi dati alla piattaforma.

Dopo aver implementato l'ascoltatore, impostalo sugli elementi dell'interfaccia utente appropriati nella tua app:

KotlinJava
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())
    }
}
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());
     }
}

Autorizzazioni URI

Le autorizzazioni di lettura vengono concesse e rilasciate automaticamente dalla piattaforma per qualsiasi URI contenuti nel payload passato a OnReceiveContentListener.

Di solito, la tua app elabora gli URI dei contenuti in un servizio o in un'attività. Per l'elaborazione a lunga esecuzione, WorkManager. Quando implementi questa funzionalità, estendi le autorizzazioni al servizio o all'attività di destinazione passando i contenuti utilizzando Intent.setClipData e impostando il flag FLAG_GRANT_READ_URI_PERMISSION.

In alternativa, puoi utilizzare un thread in background nel contesto corrente per elaborare i contenuti. In questo caso, devi mantenere un riferimento Oggetto payload ricevuto dal listener per garantire che le autorizzazioni non vengano revocati prematuramente dalla piattaforma.

Elementi View personalizzati

Se la tua app utilizza una sottoclasse View personalizzata, assicurati che la classe OnReceiveContentListener non viene bypassato.

Se la tua classe View sostituisce la onCreateInputConnection usa l'API Jetpack InputConnectionCompat.createWrapper per configurare InputConnection.

Se la classe View sostituisce il metodo onTextContextMenuItem, delega a super quando la voce di menu è R.id.paste o R.id.pasteAsPlainText.

Confronto con l'API Keyboard Image

Puoi considerare l'API OnReceiveContentListener come la versione successiva dell'API di immagini della tastiera esistente. Questo ha unificato supporta la funzionalità dell'API Keyboard Image, nonché alcune funzionalità aggiuntive. La compatibilità con i dispositivi e le funzionalità varia a seconda che tu utilizzi la libreria Jetpack o le API native dell'SDK Android.

Tabella 1. Funzionalità e livelli API supportati per Jetpack.
Azione o funzionalità Supportato dall'API di immagini della tastiera Supportato dall'API unificata
Inserisci dalla tastiera Sì (livello API 13 e versioni successive) Sì (livello API 13 e versioni successive)
Inserire utilizzando l'opzione Incolla dal menu Tocca e tieni premuto No
Inserire gli elementi utilizzando il trascinamento No Sì (livello API 24 e successivi)
Tabella 2. Funzionalità supportate e livelli API per gli annunci nativi API.
Azione o funzionalità Supportato dall'API di immagini della tastiera Supportato dall'API unificata
Inserisci dalla tastiera Sì (livello API 25 e successivi) Sì (Android 12 e versioni successive)
Inserisci usando incolla dal tocco e tieni premuto il menu No
Inserisci utilizzando la funzionalità di trascinamento No