がぶちゃんの日記

札幌からフルリモートCTO

インテントでカメラを呼び出す方法の補足(主に、Xperia 2.1問題対応)

基本:インテントでカメラを呼び出す方法

以下のインテントを使うと標準のカメラアプリを呼び出すことができます。

public void onBasicClick(View view) {
    Intent intent = new Intent();
    intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
    startActivityForResult(intent, 1);
}

ちなみに、MediaStore.ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE" に対応したカメラアプリ(Camera 360など)がインストールされていれば選択ダイアログが表示されます。


撮影された画像データは以下のように受け取ります。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 1) {
        Bitmap bitmap = (Bitmap) data.getExtras().get("data");
    }

ただ、こうして取得できる Bitmap はサイズが非常に小さいので使い物になりません。
さらに、data.getData() で取得できるUriオブジェクトは null です。

撮影された解像度の画像データを取得する方法

以下のように MediaStore.EXTRA_OUTPUT に Uri オブジェクトを指定します。Uri オブジェクトはコンテントプロバイダに予め insert して確保しておきます。

private Uri mImageUri; // インスタンス変数

public void onExtraClick(View view) {
    String filename = System.currentTimeMillis() + ".jpg";
    
    ContentValues values = new ContentValues();
    values.put(MediaStore.Images.Media.TITLE, filename);
    values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
    mImageUri = getContentResolver().insert(
            MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
    
    Intent intent = new Intent();
    intent.setAction(MediaStore.ACTION_IMAGE_CAPTURE);
    intent.putExtra(MediaStore.EXTRA_OUTPUT, mImageUri);
    startActivityForResult(intent, 2);
}

撮影後は、MediaStore.EXTRA_OUTPUT で指定した mImageUri に画像データが書き込まれているので、mImageUri を参照するだけです。ただし、撮影された解像度のままの画像データなので、撮影サイズによっては画像サイズが非常に大きい場合があることを想定しなければいけません。

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    if (requestCode == 2) {
        // ImageViewに表示するなら
        ImageView imageView = (ImageView) findViewById(R.id.main_image);
        imageView.setImageURI(mImageUri);
    }

ちなみに、この方法でも data.getData() で取得できるUriオブジェクトは null です。

さて、ここまでの説明は Android SDK開発のレシピ に書いたので、この辺にして、いよいよ本題。

Xperia 2.1 の場合

前置きが長くなりましたが Xperia 2.1 の場合は、上記の MediaStore.EXTRA_OUTPUT で指定した mImageUri に画像データが書き込まれません。
なので、上記のようにImageViewに表示しようとしても表示できません。

では、どうするか? Xperia 2.1 では、data.getData() で取得できる Uri オブジェクトに撮影された画像データが書き込まれます。
いままで、ずっとnullだったのに!

それぞれの値はこんな感じ

mImageUri:      content://media/external/images/media/355
data.getData(): content://media/external/images/media/356

自動的にコンテントプロバイダに insert してくれるみたいですね。ちきしょー、優しいぜ。
ということで、Xperia 2.1 の場合は、予め insert は、しなくていいです。むしろ、以下のようにゴミになるので insert しない方がいいです。

ここまで原因と事象が分かれば色々な対処ができると思いますが、Build.Model と(アップデートしてないXperiaにも対応するために) Build.VERSION を見て、Xperia 2.1 だったら、予め insert しない対処をするか、私は、端末依存をコードに持ち込むのが嫌だったのでdata.getData() が null ではなくて、mImageUri のデータが 0 バイトだったら、コピーする(書き込む)ようにしました。同じ事象の端末にも対応できることに期待して。

さて、銀河SやIS03など今後のAndroid端末は、どちらの挙動をするんでしょうか、今から楽しみです。(ドM)