App ShortcutsはいいからまずはImage Keyboardをサポートしたほうがいい


煽り気味のタイトルですみません

App Shortcutsとは?

ホームに特定の機能をショートカットとして置くことができます。
https://developer.android.com/guide/topics/ui/shortcuts.html

Android 7.1から使えるようになった機能です

Image Keyboard Supportとは?

キーボードから画像を入力することができます。
https://developer.android.com/guide/topics/text/image-keyboard.html

Android 7.1から使えるようになった機能……ではないです!

The API is also available in v13 Support Library as of revision 25.0.0.

サポートライブラリを使えばAndroid 3.2から使えます!

画像が入力できるキーボードなんて使っている人いるの?

実はNexusなどに標準で入っているキーボードがGboardという名前になったとき、GIFアニメが入力できるようになりました。
https://play.google.com/store/apps/details?id=com.google.android.inputmethod.latin
http://jp.techcrunch.com/2016/12/18/20161216google-brings-its-upgraded-keyboard-app-gboard-to-android/

かなり分かりにくいですが、以下のような手順で入力できます。

どうやって対応する?

従来のintentによる画像選択が実装されているようなアプリでは、かなり簡単に実装することができます。

サポートライブラリ

まずは、サポートライブラリの導入。

build.gradle
dependencies {
    // ...
    compile 'com.android.support:support-v13:25.1.0'
}

あんまり使わない(?)v13のサポートライブラリです。25以降を入れる必要があります。

ImageKeyboardSupportEditTextの作成

ドキュメントではEditTextnewしていますが、専用のクラスを作ってしまった方が、xmlにも書けて楽でしょう。

RxJavaとラムダ式を使うと以下のような感じでしょうか?

ImageKeyboardSupportEditText.java
class ImageKeyboardSupportEditText extends EditText {
    private BehaviorSubject<Uri> uri = BehaviorSubject.create();

    // コンストラクタは省略

    @Override
    public InputConnection onCreateInputConnection(EditorInfo editorInfo) {
        final InputConnection ic = super.onCreateInputConnection(editorInfo);
        EditorInfoCompat.setContentMimeTypes(editorInfo, new String[]{"image/gif"});
        return InputConnectionCompat.createWrapper(ic, editorInfo, (inputContentInfo, flags, opts) -> {
            if (BuildCompat.isAtLeastNMR1() && (flags & InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION) != 0) {
                try {
                    inputContentInfo.requestPermission();
                } catch (Exception e) {
                    return false;
                }
            }
            uri.onNext(inputContentInfo.getContentUri());
            inputContentInfo.releasePermission();
            return true;
        });
    }

    public Observable<Uri> getUri() {
        return uri.asObservable();
    }
}

ほとんどドキュメントの通りですが、GboardはGIFだけっぽいので、image/gifにしています。

後はfindViewByIdするなどして、コールバックを設定します。

MainActivity.java
ImageKeyboardSupportEditText imageKeyboardSupportEditText = (ImageKeyboardSupportEditText) findViewById(R.id.image_keyboard_support_edit_text);
imageKeyboardSupportEditText.getUri().subscribe(uri -> {
    // 画像のuriを受けた後の処理
});

URIから画像に

通常なら、以下のような感じになると思いますが、

imageKeyboardSupportEditText.getUri().subscribe(uri -> {
    InputStream inputStream = getContentResolver().openInputStream(uri);
    Bitmap bitmap = BitmapFactory.decodeStream(inputStream, null, null);
    // bitmapを使う
});

Glideを使えばGIFアニメーションも簡単にできてしまいます。

final GlideDrawableImageViewTarget target = new GlideDrawableImageViewTarget(imageView);
imageKeyboardSupportEditText.getUri().subscribe(uri -> {
    Glide.with(this).load(uri).into(target);
});

すでにACTION_GET_CONTENTACTION_IMAGE_CAPTUREによって画像を取得し、サーバに送信する処理などを実装しているのであれば、以下のような感じでもできると思います。

imageKeyboardSupportEditText.getUri().subscribe(uri -> {
    onActivityResult(REQUEST_CODE, RESULT_OK, new Intent().setData(uri));
});

まとめ

最初は「文字列内に画像が入るの?」と思いましたが、通常の画像選択と同じuriなので、意外と簡単に導入できました。
LINEスタンプの代わりになるようなものとして発展していけば面白いなと思います。
ただ、画像の著作権がどのようになっているのかはちょっと気になりました
気が向いたらIMEの方も作ってみたいと思います

何か間違いがあれば教えていただけると幸いです