Gli utenti spesso desiderano comunicare tramite emoji, adesivi e altri tipi di contenuti avanzati. Nelle versioni precedenti di Android, le tastiere flessibili, anche note come Input Method Editor, o IME, potevano inviare solo emoji Unicode alle app. Per i contenuti avanzati, le app creavano API specifiche per le app che non potevano essere utilizzate in altre app o utilizzavano soluzioni alternative come l'invio di immagini tramite una semplice azione di condivisione o gli appunti.
A partire da Android 7.1 (livello API 25), l'SDK Android include l'API Commit Content, che consente agli IME di inviare immagini e altri contenuti avanzati direttamente a un editor di testo in un'app. L'API è disponibile anche nella libreria di supporto v13 a partire dalla revisione 25.0.0. Consigliamo di utilizzare la libreria di supporto perché contiene metodi helper che semplificano l'implementazione.
Con questa API puoi creare app di messaggistica che accettano contenuti avanzati da qualsiasi tastiera, nonché tastiere in grado di inviare contenuti avanzati a qualsiasi app. La tastiera Google e le app come Messaggi di Google supportano l'API Commit Content in Android 7.1, come mostrato nella figura 1.
Questo documento mostra come implementare l'API Commit Content sia negli IME sia nelle app.
Come funziona
L'inserimento dell'immagine della tastiera richiede la partecipazione dell'IME e dell'app. La sequenza seguente descrive ogni passaggio del processo di inserimento delle immagini:
Quando l'utente tocca
EditText
, l'editor invia un elenco dei tipi di contenuti MIME che accetta inEditorInfo.contentMimeTypes
.L'IME legge l'elenco dei tipi supportati e mostra i contenuti nella tastiera software accettati dall'editor.
Quando l'utente seleziona un'immagine, l'IME chiama
commitContent()
e invia unInputContentInfo
all'editor. La chiamatacommitContent()
è analoga alla chiamatacommitText()
, ma per i contenuti multimediali.InputContentInfo
contiene un URI che identifica i contenuti di un fornitore di contenuti.
Questo processo è illustrato nella Figura 2:
Aggiungere il supporto delle immagini alle app
Per accettare contenuti avanzati dagli IME, un'app deve indicare agli IME i tipi di contenuti accettati e specificare un metodo di callback da eseguire alla ricezione dei contenuti.
L'esempio seguente mostra come creare un elemento EditText
che accetta le immagini PNG:
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 viene fornita una spiegazione più dettagliata:
Questo esempio utilizza la libreria di supporto, quindi ci sono alcuni riferimenti a
android.support.v13.view.inputmethod
anziché aandroid.view.inputmethod
.Questo esempio crea un
EditText
e sostituisce il relativo metodoonCreateInputConnection(EditorInfo)
per modificareInputConnection
.InputConnection
è il canale di comunicazione tra un IME e l'app che riceve il suo input.La chiamata
super.onCreateInputConnection()
conserva il comportamento integrato (invio e ricezione di testo) e fornisce un riferimento aInputConnection
.setContentMimeTypes()
aggiunge un elenco di tipi MIME supportati aEditorInfo
. Chiamasuper.onCreateInputConnection()
prima del giornosetContentMimeTypes()
.callback
viene eseguito ogni volta che l'IME esegue il commit dei contenuti. Il metodoonCommitContent()
fa riferimento aInputContentInfoCompat
, che contiene un URI di contenuti.- Richiedi e rilascia le autorizzazioni se la tua app è in esecuzione al livello API 25 o successivo e il flag
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
è impostato dall'IME. In caso contrario, hai già accesso all'URI dei contenuti perché è concesso dall'IME o perché il fornitore di contenuti non limita l'accesso. Per ulteriori informazioni, consulta la sezione Aggiungere il supporto di immagini agli IME.
- Richiedi e rilascia le autorizzazioni se la tua app è in esecuzione al livello API 25 o successivo e il flag
createWrapper()
aggrega ilInputConnection
, ilEditorInfo
modificato e il callback in un nuovoInputConnection
e lo restituisce.
Di seguito sono riportate le pratiche consigliate:
Gli editor che non supportano i contenuti avanzati non chiamano
setContentMimeTypes()
e lasciano il campoEditorInfo.contentMimeTypes
impostato sunull
.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 cursore del testo e non ne influenzano la posizione. Gli editor possono ignorare la posizione del cursore quando lavorano con i contenuti.
Nel metodo
OnCommitContentListener.onCommitContent()
dell'editor, puoi restituiretrue
in modo asincrono, anche prima di caricare i contenuti.A differenza del testo, che può essere modificato nell'IME prima del commit, il commit dei contenuti avanzati viene eseguito immediatamente. Se vuoi consentire agli utenti di modificare o eliminare i contenuti, implementa autonomamente la logica.
Per testare la tua app, assicurati che il tuo dispositivo o emulatore abbia una tastiera in grado di inviare contenuti avanzati. Puoi utilizzare la tastiera Google in Android 7.1 o versioni successive.
Aggiungere il supporto delle immagini agli IME
Gli IME che vogliono inviare contenuti avanzati alle app devono implementare l'API Commit Content, come mostrato nell'esempio seguente:
- Esegui l'override di
onStartInput()
oonStartInputView()
e leggi l'elenco dei tipi di contenuti supportati dall'editor di destinazione. Il seguente snippet di codice mostra come verificare se l'editor di destinazione 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 componi testo, perché l'editor potrebbe perdere lo stato attivo. Il seguente snippet di codice mostra come 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 il tuo fornitore di contenuti per
rispondere alle richieste degli URI dei contenuti. Fa eccezione il caso in cui l'IME supporti contenuti di fornitori di contenuti esistenti come MediaStore
. Per informazioni sulla creazione di fornitori di contenuti, consulta la documentazione relativa al provider di contenuti e al provider di file.
Se stai creando un tuo fornitore di contenuti, ti consigliamo di non esportarlo
impostando
android:exported
su
false
. Abilita la concessione delle autorizzazioni nel provider impostando android:grantUriPermission
su true
. Successivamente, l'IME può concedere le autorizzazioni per accedere all'URI dei contenuti quando viene eseguito il commit dei contenuti. Esistono due metodi per effettuare questa operazione:
Su Android 7.1 (livello API 25) e versioni successive, quando chiami
commitContent()
, imposta il parametro flag suINPUT_CONTENT_GRANT_READ_URI_PERMISSION
. Quindi, l'oggettoInputContentInfo
ricevuto dall'app può richiedere e rilasciare autorizzazioni di lettura temporanee chiamandorequestPermission()
ereleasePermission()
.Su Android 7.0 (livello API 24) e versioni precedenti,
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
viene ignorato, quindi concedi manualmente l'autorizzazione ai contenuti. Un modo per farlo è utilizzaregrantUriPermission()
, ma puoi implementare un meccanismo che soddisfi i tuoi requisiti.
Per testare il tuo IME, assicurati che il tuo dispositivo o emulatore abbia un'app in grado di ricevere contenuti multimediali. Puoi utilizzare l'app Google Messenger in Android 7.1 o versioni successive.