LoginSignup
9
5

More than 5 years have passed since last update.

Image Keyboardをいらすとやで作ってみた

Posted at

作ったもの

device-2017-01-09-204311.gif

手っ取り早く試したい場合はapkをどうぞ。

Image Keyboard

前回はこんな記事を書きました。

App ShortcutsはいいからまずはImage Keyboardをサポートしたほうがいい
http://qiita.com/oxsoft/items/47337bfa137e2b03b66c

サポートライブラリを使うことで、キーボードから画像を入力することができるようになりました。
今回はこれを、みんな大好きいらすとやで作ってみました :muscle:

キーボードの作成

Serviceの作成

キーボードを作るので、InputMethodServiceを継承したクラスを作成します。

MainService.java
public class MainService extends InputMethodService {
    @Override
    public View onCreateInputView() {
        View inputView = getLayoutInflater().inflate(R.layout.view_keyboard, null);
        // inputViewの設定
        return inputView;
    }

    @Override
    public void onStartInputView(EditorInfo editorInfo, boolean restarting) {
        // 入力欄に応じた処理
    }
}

xmlの作成

キーボードの情報をシステムに伝えるために、res/xmlにmethod.xmlを作成します。

method.xml
<?xml version="1.0" encoding="utf-8"?>
<input-method xmlns:android="http://schemas.android.com/apk/res/android">
    <subtype
        android:imeSubtypeLocale="jp_JP"
        android:imeSubtypeMode="keyboard"
        android:label="@string/label" />
</input-method>

AndroidManifestの修正

作成したServiceとxmlをAndroidManifestで宣言します。

AndroidManifest.xml
<manifest ...>
    <application ...>
        ...
        <service
            android:name=".MainService"
            android:label="@string/app_name"
            android:permission="android.permission.BIND_INPUT_METHOD">
            <meta-data
                android:name="android.view.im"
                android:resource="@xml/method" />
            <intent-filter>
                <action android:name="android.view.InputMethod" />
            </intent-filter>
        </service>
    </application>
</manifest>

ここまでは、今までのキーボード作成と同じですね。

Image Keyboardをサポートしているかチェック

入力欄がImage Keyboardをサポートしていなければ何もできないので、onStartInputView内でチェックします。
基本的にはAdding Image Support to IMEsに書いてある通りですが、今回扱う画像はpngなので、そこだけ修正します。

MainService.java
@Override
public void onStartInputView(EditorInfo editorInfo, boolean restarting) {
    String[] mimeTypes = EditorInfoCompat.getContentMimeTypes(editorInfo);

    boolean pngSupported = false;
    for (String mimeType : mimeTypes) {
        if (ClipDescription.compareMimeTypes(mimeType, "image/png")) {
            pngSupported = true;
        }
    }

    // サポートしていない場合はその旨を表示
    unsupported.setVisibility(pngSupported ? View.GONE : View.VISIBLE);
}

画像を送信

これもAdding Image Support to IMEsに書いてある通りですが、gifをpngにしました。
ただ今回は、web上にある画像を使っているので、付加情報としてlinkUriを付けるようにしました。(Gboardもそうなっていたので)

MainService.java
private void commitPngImage(Uri contentUri, String imageDescription, Uri linkUri) {
    InputContentInfoCompat inputContentInfo = new InputContentInfoCompat(contentUri, new ClipDescription(imageDescription, new String[]{"image/png"}), linkUri);
    InputConnection inputConnection = getCurrentInputConnection();
    EditorInfo editorInfo = getCurrentInputEditorInfo();
    int flags = 0;
    if (android.os.Build.VERSION.SDK_INT >= 25) {
        flags |= InputConnectionCompat.INPUT_CONTENT_GRANT_READ_URI_PERMISSION;
    }
    InputConnectionCompat.commitContent(inputConnection, editorInfo, inputContentInfo, flags, null);
}

画像の取得

今回はいらすとやを題材にしているので、クロールして画像をアプリ内にキャッシュします。okhttp3を使うと以下のような感じです。詳しくはGitHubの方を参照してください。

Request request = new Request.Builder().url("画像のURL").build();
Response response = new OkHttpClient().newCall(request).execute();
InputStream input = response.body().byteStream();
OutputStream output = openFileOutput("画像のファイル名", MODE_PRIVATE);
byte[] buffer = new byte[65536];
int bytesRead;
while ((bytesRead = input.read(buffer)) != -1) {
    output.write(buffer, 0, bytesRead);
}
response.body().close();

ContentProviderの設定

ContentProviderを用意することで、アプリ内のデータを外部に提供することができます。FileProviderを使うことで、独自クラスを作成することなく、簡単に実装できます。

file_pathsの用意

xml/file_paths.xmlを以下のように作成します。

file_paths.xml
<?xml version="1.0" encoding="utf-8"?>
<paths>
    <files-path
        name="images"
        path="/" />
</paths>

今回はルートディレクトリにしていますが、ディレクトリを分けた方がいいかもしれません。

AndroidManifestの修正

FileProviderのauthoritiesを設定し、先ほどのxmlを指定します。

AndroidManifest.xml
<manifest ...>
    <application ...>
        ...
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.oxsoft.irasutoya.content"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/file_paths" />
        </provider>
    </application>
</manifest>

uriの取得

以上の設定をすることで、以下のように画像のuriを取得することができます。authoritiesをAndroidManifestに書いたものと一致させる必要があります。

File file = getFileStreamPath("画像のファイル名");
Uri uri = FileProvider.getUriForFile(this, "com.oxsoft.irasutoya.content", file);

このuriを、上で作成したcommitPngImageに渡せば、画像が入力できるというわけです。

まとめ

意外と簡単に画像入力を実装できることが分かりました。とはいえまだまだ画像入力に対応しているアプリが少ないですね :sweat_smile:

また、日本語入力を独自に実装することが難しかったため、Gboardにあるような検索機能をつけることができませんでした :sweat_smile:

何か間違いがあれば指摘していただけると幸いです :bow:

9
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
5