GIF compatible EditText

The snippet below is a custom view that enables keyboard like GBoard to enter GIFs and stickers.

When the user enters a GIF, you’ll get a content-uri that you can use to upload the GIF to your backend.

Assuming et_message is a GifEditText in your layout, you can use the snippet below like this:

et_message.keyBoardInputCallbackListener = object : KeyBoardInputCallbackListener {
        override fun onCommitContent(
            inputContentInfo: InputContentInfoCompat?,
            flags: Int,
            opts: Bundle?
        ) {
            inputContentInfo?.let { info ->
                val mime = info.description.getMimeType(0)
                val contentUri = info.contentUri
                // TODO upload the contentUri
                // TODO show a preview (pass contentUri into Glide)
            }
        }
    }

GifEditText.kt

package com.pixplicity.example

import android.content.Context
import android.os.Build
import android.os.Bundle
import android.util.AttributeSet
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputConnection
import androidx.appcompat.widget.AppCompatEditText
import androidx.core.view.inputmethod.EditorInfoCompat
import androidx.core.view.inputmethod.InputConnectionCompat
import androidx.core.view.inputmethod.InputContentInfoCompat
import com.pixplicity.example.R


interface KeyBoardInputCallbackListener {
    fun onCommitContent(
        inputContentInfo: InputContentInfoCompat?,
        flags: Int,
        opts: Bundle?
    )
}

class GifEditText : AppCompatEditText {

    var imgTypeString = arrayOf(
        "image/png",
        "image/gif",
        "image/jpeg",
        "image/webp"
    )

    var keyBoardInputCallbackListener: KeyBoardInputCallbackListener? = null

    constructor(context: Context) : this(context, null, 0)

    constructor(context: Context, attrs: AttributeSet) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyle: Int) : super(
        context,
        attrs,
        R.attr.editTextStyle
    )

    override fun onCreateInputConnection(outAttrs: EditorInfo): InputConnection? {
        val ic = super.onCreateInputConnection(outAttrs)
        EditorInfoCompat.setContentMimeTypes(
            outAttrs,
            imgTypeString
        )
        return InputConnectionCompat.createWrapper(ic, outAttrs, callback)
    }


    val callback: InputConnectionCompat.OnCommitContentListener =
        object : InputConnectionCompat.OnCommitContentListener {
            override fun onCommitContent(
                inputContentInfo: InputContentInfoCompat,
                flags: Int,
                opts: Bundle?
            ): Boolean {

                // read and display inputContentInfo asynchronously
                val f = flags and InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION
                if (Build.VERSION.SDK_INT >= 25 && f != 0) {
                    try {
                        inputContentInfo.requestPermission()
                    } catch (e: Exception) {
                        return false
                    }
                }
                var supported = false
                for (mimeType in imgTypeString) {
                    if (inputContentInfo.description.hasMimeType(mimeType)) {
                        supported = true
                        break
                    }
                }
                if (!supported) {
                    return false
                }
                keyBoardInputCallbackListener?.onCommitContent(inputContentInfo, flags, opts)
                return true
            }
        }
}