Os usuários geralmente querem se comunicar usando emojis, adesivos e outros tipos de conteúdo. Nas versões anteriores do Android, os teclados de software, também conhecidos como editores de métodos de entrada ou IMEs: podiam enviar apenas emojis Unicode para apps. Para conteúdo avançado, os apps criados APIs específicas do app que não podiam ser usadas em outros apps ou que usavam soluções alternativas, como enviar imagens com um compartilhamento simples ou a área de transferência.
A partir do Android 7.1 (nível 25 da API), o SDK do Android inclui a API Commit API Content, que fornece uma maneira universal para os IMEs enviarem imagens e outros conteúdo avançado diretamente para um editor de texto em um aplicativo. A API também está disponível em Biblioteca de Suporte v13 a partir da revisão 25.0.0. Recomendamos o uso do Suporte Biblioteca, porque contém métodos auxiliares que simplificam a implementação.
Com essa API, é possível criar aplicativos de mensagens que aceitam conteúdo avançado de qualquer teclado, bem como teclados que podem enviar conteúdo avançado para qualquer aplicativo. A página Google Teclado e aplicativos como o Mensagens de 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 exige 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 ele aceita 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
ao editor. A chamadacommitContent()
é análoga à chamadacommitText()
, mas para conteúdo avançado.InputContentInfo
contém um URI que identifica o conteúdo de uma plataforma de nuvem.
Esse processo é mostrado na Figura 2:
Adicionar suporte a imagens nos apps
Para aceitar conteúdo avançado de IMEs, um app precisa informar a eles quais tipos de conteúdo ele
aceita e especifica um método de retorno de chamada que é executado quando o conteúdo é recebido.
O exemplo a seguir demonstra como criar um EditText
que aceite PNG.
imagens:
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 mais explicações:
Este exemplo usa a Biblioteca de Suporte, portanto há algumas referências a
android.support.v13.view.inputmethod
em vez deandroid.view.inputmethod
Este exemplo cria um
EditText
e substitui oonCreateInputConnection(EditorInfo)
para modificar o métodoInputConnection
OInputConnection
é o canal de comunicação entre um IME e o app que está recebendo entrada.A chamada
super.onCreateInputConnection()
preserva o comportamento integrado (envio e recebimento de texto) e fornece uma referência aoInputConnection
.setContentMimeTypes()
adiciona uma lista de tipos MIME compatíveis aoEditorInfo
Ligaçãosuper.onCreateInputConnection()
antes desetContentMimeTypes()
.callback
é executado sempre que o IME confirma conteúdo. MétodoonCommitContent()
tem uma referência aInputContentInfoCompat
, que contém um URI de conteúdo.- Solicitar e liberar permissões se o app estiver sendo executado no nível 25 da API
ou superior, e a
INPUT_CONTENT_GRANT_READ_URI_PERMISSION
é definido pelo IME. Caso contrário, você já tem acesso ao conteúdo URI porque é concedido pelo IME ou porque o provedor de conteúdo que não restrinja o acesso. Para mais informações, consulte Adicionar suporte a imagens ao IMEs (editores de método de entrada, na sigla em inglês).
- Solicitar e liberar permissões se o app estiver sendo executado no nível 25 da API
ou superior, e a
createWrapper()
encapsula oInputConnection
, oEditorInfo
modificado e o callback em um novoInputConnection
e o retorna.
Veja 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 eles deixam oEditorInfo.contentMimeTypes
definido. paranull
.Os editores vão ignorar o conteúdo se o tipo MIME especificado em
InputContentInfo
. não corresponde a nenhum dos tipos aceitos.O conteúdo avançado não afeta nem é afetado pela posição do texto. cursor. Os editores podem ignorar a posição do cursor ao trabalhar com o conteúdo.
Na guia
OnCommitContentListener.onCommitContent()
, é 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, conteúdo é confirmado imediatamente. Se você quiser permitir que os usuários editem ou excluam implemente a lógica você mesmo.
Para testar o app, confira se o dispositivo ou emulador tem um teclado que pode 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 precisarão implementar a API Commit Content. API, conforme mostrado no exemplo a seguir:
- Substituir
onStartInput()
ouonStartInputView()
e leia a lista de tipos de conteúdo compatíveis com o destino editor. 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 no app quando o usuário selecionar uma imagem. Evitar chamadas
commitContent()
quando há algum texto sendo composto, porque pode fazer com que o editor perca o foco. O snippet de código a seguir mostra como para fazer commit de 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, você provavelmente precisará 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údos
de provedores de conteúdo, como
MediaStore
Para informações sobre
criar provedores de conteúdo, consulte a documentação
provedor e file
do provedor.
Se você estiver criando seu próprio provedor de conteúdo, recomendamos não exportá-lo.
definindo
android:exported
para
false
. Em vez disso, ative a concessão de permissões no provedor configurando
android:grantUriPermission
para 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 flag comoINPUT_CONTENT_GRANT_READ_URI_PERMISSION
. Em seguida, o objetoInputContentInfo
que o app recebe pode solicitar e liberar permissões temporárias de leitura 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 seu próprio mecanismo que e satisfaça seus próprios 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.