Supporto per la tastiera delle immagini

Gli utenti spesso vogliono comunicare utilizzando emoji, adesivi e altri tipi di contenuti multimediali contenuti. Nelle versioni precedenti di Android, le tastiere software, note anche come editor dei metodi di input oppure IME: potrebbe inviare solo emoji Unicode alle app. Per i contenuti avanzati, le app API specifiche per le app che non è stato possibile usare in altre app o soluzioni alternative come invio di immagini tramite una semplice azione di condivisione o negli appunti.

Un'immagine che mostra una tastiera che supporta la ricerca immagini
. Figura 1. Esempio del supporto della tastiera di immagini.

A partire da Android 7.1 (livello API 25), l'SDK per Android include il campo API Content, che fornisce agli IME un metodo universale per inviare immagini e altri contenuto multimediale direttamente in un editor di testo in un'app. L'API è disponibile anche in la v13 Support Library a partire dalla revisione 25.0.0. È consigliabile utilizzare il Centro assistenza Libreria perché contiene metodi helper che semplificano l'implementazione.

Con questa API, puoi creare app di messaggistica che accettano contenuti avanzati da qualsiasi e tastiere che consentono di inviare contenuti multimediali a qualsiasi app. Il Google Tastiera e app come Messaggi di Google Supportano la Commit Content API in Android 7.1, come mostrato nella figura 1.

Questo documento mostra come implementare l'API Commit Content sia negli IME che app.

Come funziona

L'inserimento di immagini con la tastiera richiede la partecipazione dell'IME e dell'app. La nella sequenza seguente viene descritto ogni passaggio del processo di inserimento dell'immagine:

  1. Quando l'utente tocca una EditText, l'editor invia un elenco dei tipi di contenuti MIME accettati in EditorInfo.contentMimeTypes.

  2. L'IME legge l'elenco dei tipi supportati e visualizza i contenuti nel software tastiera accettata dall'editor.

  3. Quando l'utente seleziona un'immagine, l'IME chiama commitContent() e invia un'email InputContentInfo all'editore. La chiamata commitContent() è analoga alla commitText(), ma per contenuti avanzati. InputContentInfo contiene un URI che identifica i contenuti presenti in un contenuti del cloud privato.

Questo processo è illustrato nella figura 2:

Un'immagine che mostra la sequenza da applicazione a IME e tornare ad applicazione
. Figura 2. Dal flusso dall'applicazione all'IME al flusso dell'applicazione.

Aggiungi il supporto delle immagini alle app

Per accettare contenuti avanzati dagli IME, un'app deve indicare agli IME di che tipi di contenuti accetta e specifica un metodo di callback da eseguire alla ricezione di contenuti. L'esempio seguente mostra come creare un elemento EditText che accetta PNG immagini:

Kotlin

var editText: EditText = object : EditText(this) {
    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection {
        var ic = super.onCreateInputConnection(outAttrs)
        EditorInfoCompat.setContentMimeTypes(outAttrs, arrayOf("image/png"))
        val mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this)
        if (mimeTypes != null) {
            EditorInfoCompat.setContentMimeTypes(outAttrs, mimeTypes)
            ic = InputConnectionCompat.createWrapper(this, ic, outAttrs)
        }
        return ic
    }
}

Java

EditText editText = new EditText(this) {
    @Override
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
        InputConnection ic = super.onCreateInputConnection(outAttrs);
        EditorInfoCompat.setContentMimeTypes(outAttrs, new String[]{"image/png"});
        String[] mimeTypes = ViewCompat.getOnReceiveContentMimeTypes(this);
        if (mimeTypes != null) {
            EditorInfoCompat.setContentMimeTypes(outAttrs, mimeTypes);
            ic = InputConnectionCompat.createWrapper(this, ic, outAttrs);
        }
        return ic;
    }
};

Di seguito sono riportate ulteriori spiegazioni:

Di seguito sono riportate alcune pratiche consigliate:

  • Gli editor che non supportano i contenuti avanzati non chiamano setContentMimeTypes() e lascia impostato EditorInfo.contentMimeTypes a null.

  • Gli editor ignorano i contenuti se il tipo MIME specificato in InputContentInfo non corrisponde a nessuno dei tipi accettati.

  • I contenuti avanzati non incidono sulla posizione del testo né sulla posizione del testo il cursore del mouse. Gli editor possono ignorare la posizione del cursore quando lavorano con i contenuti.

  • Nella sezione OnCommitContentListener.onCommitContent(), puoi restituire true in modo asincrono, prima di caricare i contenuti.

  • A differenza del testo, che può essere modificato nell'IME prima del commit, il commit dei contenuti è immediato. Se vuoi consentire agli utenti di modificare o eliminare di implementare direttamente la logica.

Per testare la tua app, assicurati che il dispositivo o l'emulatore abbia una tastiera in grado di inviare contenuti avanzati. Puoi usare la tastiera Google su Android 7.1 o versioni successive.

Aggiungi il supporto delle immagini agli IME

Gli IME che desiderano inviare contenuti avanzati alle app devono implementare l'opzione Contenuti del commit come mostrato nell'esempio seguente:

  • Esegui override onStartInput() oppure onStartInputView() e leggere l'elenco dei tipi di contenuti supportati dalla destinazione editor. Il seguente snippet di codice mostra come verificare se il target l'editor di codice accetta immagini GIF.

Kotlin

override fun onStartInputView(editorInfo: EditorInfo, restarting: Boolean) {
    val mimeTypes: Array<String> = EditorInfoCompat.getContentMimeTypes(editorInfo)

    val gifSupported: Boolean = mimeTypes.any {
        ClipDescription.compareMimeTypes(it, "image/gif")
    }

    if (gifSupported) {
        // The target editor supports GIFs. Enable the corresponding content.
    } else {
        // The target editor doesn't support GIFs. Disable the corresponding
        // content.
    }
}

Java

@Override
public void onStartInputView(EditorInfo info, boolean restarting) {
    String[] mimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo);

    boolean gifSupported = false;
    for (String mimeType : mimeTypes) {
        if (ClipDescription.compareMimeTypes(mimeType, "image/gif")) {
            gifSupported = true;
        }
    }

    if (gifSupported) {
        // The target editor supports GIFs. Enable the corresponding content.
    } else {
        // The target editor doesn't support GIFs. Disable the corresponding
        // content.
    }
}
  • Esegui il commit dei contenuti nell'app quando l'utente seleziona un'immagine. Evita di chiamare commitContent() quando viene composto qualsiasi testo, perché potrebbe far perdere lo stato attivo all'editor. Il seguente snippet di codice mostra come per eseguire il commit di un'immagine GIF.

Kotlin

// Commits a GIF image.

// @param contentUri = Content URI of the GIF image to be sent.
// @param imageDescription = Description of the GIF image to be sent.

fun commitGifImage(contentUri: Uri, imageDescription: String) {
    val inputContentInfo = InputContentInfoCompat(
            contentUri,
            ClipDescription(imageDescription, arrayOf("image/gif")),
            null
    )
    val inputConnection = currentInputConnection
    val editorInfo = currentInputEditorInfo
    var flags = 0
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
        flags = flags or InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION
    }
    InputConnectionCompat.commitContent(inputConnection, editorInfo, inputContentInfo, flags, null)
}

Java

// Commits a GIF image.

// @param contentUri = Content URI of the GIF image to be sent.
// @param imageDescription = Description of the GIF image to be sent.

public static void commitGifImage(Uri contentUri, String imageDescription) {
    InputContentInfoCompat inputContentInfo = new InputContentInfoCompat(
            contentUri,
            new ClipDescription(imageDescription, new String[]{"image/gif"}),
            null
    );
    InputConnection inputConnection = getCurrentInputConnection();
    EditorInfo editorInfo = getCurrentInputEditorInfo();
    Int flags = 0;
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
        flags |= InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
    }
    InputConnectionCompat.commitContent(
            inputConnection, editorInfo, inputContentInfo, flags, null);
}

In qualità di autore di IME, molto probabilmente dovrai implementare un tuo fornitore di contenuti per rispondere alle richieste URI dei contenuti. Fa eccezione il caso in cui l'IME supporta contenuti di fornitori di contenuti esistenti, come MediaStore Per informazioni su dei fornitori di contenuti, consulta i contenuti provider e file del fornitore.

Se stai creando un tuo fornitore di contenuti, ti consigliamo di non esportarlo impostando Da android:exported a false. Abilita invece la concessione delle autorizzazioni nel provider impostando android:grantUriPermission a true. Successivamente, l'IME può concedere le autorizzazioni per accedere all'URI dei contenuti quando il commit dei contenuti. Esistono due metodi per effettuare questa operazione:

  • Su Android 7.1 (livello API 25) e versioni successive, durante la chiamata a commitContent(), imposta il parametro flag su INPUT_CONTENT_GRANT_READ_URI_PERMISSION Quindi, l'oggetto InputContentInfo ricevuto dall'app può richiedere e rilascia autorizzazioni di lettura temporanee chiamando requestPermission() e releasePermission().

  • Su Android 7.0 (livello API 24) e versioni precedenti, INPUT_CONTENT_GRANT_READ_URI_PERMISSION viene ignorato, quindi concedilo manualmente autorizzazione all'accesso ai contenuti. Un modo per farlo è grantUriPermission(), ma puoi implementare un tuo meccanismo che che soddisfi le tue esigenze.

Per testare l'IME, assicurati che il dispositivo o l'emulatore disponga di un'app in grado di ricevere contenuti avanzati. Puoi utilizzare l'app Google Messenger in Android 7.1 o versioni successive.