Os usuários geralmente querem se comunicar usando emojis, adesivos e outros tipos de conteúdo avançado. Nas versões anteriores do Android, os teclados de software, também conhecidos como editores de método de entrada (IMEs, na sigla em inglês), podiam enviar apenas emojis Unicode para apps. Para conteúdo avançado, os apps criam APIs específicas que não podem ser usadas em outros apps ou usam soluções alternativas, como enviar imagens com uma ação de compartilhamento simples ou a área de transferência.
![Uma imagem que mostra um teclado compatível com a pesquisa por imagens](https://developer.android.com/static/images/guide/topics/text/image-keyboard-sample.png?authuser=5&hl=pt)
No Android 7.1 (nível 25 da API) e versões mais recentes, o SDK do Android inclui a API Commit Content, que oferece uma maneira universal de IMEs enviarem imagens e outros conteúdo avançado diretamente para um editor de texto em um app. A API também está disponível na Biblioteca de Suporte v13 a partir da revisão 25.0.0. Recomendamos o uso da Biblioteca de Suporte porque ela contém métodos auxiliares que simplificam a implementação.
Com essa API, você pode criar apps de mensagens que aceitam conteúdo avançado de qualquer teclado e teclados que podem enviar conteúdo avançado para qualquer app. O Teclado do Google e apps como o Messages do Google oferecem suporte à API Commit Content no Android 7.1, como mostrado na Figura 1.
Este documento mostra como implementar a API Commit Content em IMEs e apps.
Como funciona
A inserção de imagem do teclado requer a participação do IME e do app. A sequência a seguir descreve cada etapa do processo de inserção de imagem:
Quando o usuário toca em uma
EditText
, o editor envia uma lista de tipos de conteúdo MIME que são aceitos emEditorInfo.contentMimeTypes
.O IME lê a lista de tipos compatíveis e exibe o conteúdo no teclado de software que o editor pode aceitar.
Quando o usuário seleciona uma imagem, o IME chama
commitContent()
e envia umaInputContentInfo
para o editor. A chamada decommitContent()
é análoga à chamada decommitText()
, mas para conteúdo avançado. OInputContentInfo
contém um URI que identifica o conteúdo em um provedor de conteúdo.
Esse processo está descrito na Figura 2:
![Uma imagem mostrando a sequência de Application para IME e de volta para Application](https://developer.android.com/static/images/guide/topics/text/image-keyboard-diagram.png?authuser=5&hl=pt)
Adicionar compatibilidade com imagens a apps
Para aceitar conteúdo avançado de IMEs, um app precisa informar a eles quais tipos de conteúdo
são aceitos e especificar um método de callback que seja executado quando o conteúdo for recebido.
O exemplo a seguir demonstra como criar um EditText
que aceite imagens 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; } };
Confira a seguir uma explicação mais detalhada:
Este exemplo usa a Biblioteca de Suporte, então há algumas referências a
android.support.v13.view.inputmethod
em vez deandroid.view.inputmethod
.Este exemplo cria um
EditText
e substitui o métodoonCreateInputConnection(EditorInfo)
para modificar oInputConnection
. OInputConnection
é o canal de comunicação entre um IME e o app que está recebendo a entrada.A chamada
super.onCreateInputConnection()
preserva o comportamento integrado, ou seja, o envio e recebimento de texto, e fornece uma referência aoInputConnection
.setContentMimeTypes()
adiciona uma lista de tipos MIME compatíveis aoEditorInfo
. Chamesuper.onCreateInputConnection()
antes desetContentMimeTypes()
.callback
é executado sempre que o IME confirma conteúdo. O métodoonCommitContent()
tem uma referência aInputContentInfoCompat
, que contém um URI de conteúdo.- Solicite e libere permissões se o app estiver sendo executado na API de nível 25
ou mais recente e a sinalização
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
for definida pelo IME. Caso contrário, você já tem acesso ao URI de conteúdo, porque ele foi concedido pelo IME ou porque o provedor de conteúdo não restringe o acesso. Para saber mais, consulte Adicionar suporte a imagens a IMEs.
- Solicite e libere permissões se o app estiver sendo executado na API de nível 25
ou mais recente e a sinalização
createWrapper()
encapsula oInputConnection
, oEditorInfo
modificado e o callback em um novoInputConnection
e o retorna.
Confira a seguir as práticas recomendadas:
Os editores que não são compatíveis com conteúdo avançado não chamam
setContentMimeTypes()
e deixam oEditorInfo.contentMimeTypes
definido comonull
.Os editores vão ignorar o conteúdo se o tipo MIME especificado em
InputContentInfo
não corresponder a nenhum dos tipos aceitos.O conteúdo avançado não afeta e não é afetado pela posição do cursor de texto. Os editores podem ignorar a posição do cursor ao trabalhar com o conteúdo.
No método
OnCommitContentListener.onCommitContent()
do editor, é possível retornartrue
de forma assíncrona, mesmo antes de carregar o conteúdo.Ao contrário do texto, que pode ser editado no IME antes de ser confirmado, o conteúdo avançado é confirmado imediatamente. Se você quiser permitir que os usuários editem ou excluam conteúdo, implemente a lógica por conta própria.
Para testar seu app, verifique se o dispositivo ou emulador tem um teclado que possa enviar conteúdo avançado. Você pode usar o Teclado do Google no Android 7.1 ou versões mais recentes.
Adicionar suporte a imagens a IMEs
Os IMEs que quiserem enviar conteúdo avançado para apps precisam implementar a API Commit Content, conforme mostrado no exemplo a seguir:
- Modifique
onStartInput()
ouonStartInputView()
e leia a lista de tipos de conteúdo com suporte no editor de destino. O snippet de código a seguir mostra como verificar se o editor de destino aceita imagens 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. } }
- Confirme o conteúdo do app quando o usuário selecionar uma imagem. Evite chamar
commitContent()
quando houver algum texto sendo escrito, porque isso pode fazer com que o editor perca o foco. O snippet de código a seguir mostra como confirmar uma imagem 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); }
Como autor de um IME, é provável que você precise implementar seu próprio provedor de conteúdo para
responder a solicitações de URI de conteúdo. A exceção é se o IME oferecer suporte a conteúdo
de provedores de conteúdo existentes, como
MediaStore
. Para informações sobre
como criar provedores de conteúdo, consulte a documentação do provedor de
conteúdo e do provedor
de arquivos.
Se você estiver criando seu próprio provedor de conteúdo, recomendamos que não o exporte
definindo
android:exported
como
false
. Em vez disso, ative a concessão de permissões no provedor, definindo
android:grantUriPermission
como true
. Depois disso, seu IME poderá conceder permissões para acessar o URI de conteúdo quando
o conteúdo for confirmado. Há duas maneiras de fazer isso:
No Android 7.1 (nível 25 da API) e versões mais recentes, ao chamar
commitContent()
, defina o parâmetro de sinalização comoINPUT_CONTENT_GRANT_READ_URI_PERMISSION
. Em seguida, o objetoInputContentInfo
que o app recebe pode solicitar e liberar permissões de leitura temporárias chamandorequestPermission()
ereleasePermission()
.No Android 7.0 (nível 24 da API) e versões anteriores,
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
é ignorado. Portanto, conceda manualmente permissão ao conteúdo. Uma maneira de fazer isso é comgrantUriPermission()
, mas você pode implementar um mecanismo próprio que atenda aos seus requisitos.
Para testar o IME, verifique se o dispositivo ou emulador tem um app que possa receber conteúdo avançado. Você pode usar o app Google Messenger no Android 7.1 ou versões mais recentes.