本格的なカメラアプリであれば別ですが、オプション的にカメラで撮った画像を使いたい場合はIntentを使うことで「比較的」簡単にできます。
2021.1.1
ACTION_IMAGE_CAPTURE
Intentを使うやり方は端末内のカメラアプリ、デフォルトで入っていますから、それを呼び出して撮影と保存をやってもらおうというあなた任せの機能です。(楽)
android.os.FileUriExposedException というエラーになった場合は、API24からはUriをfile://xxx という使い方ができない理由によるものかもしれません。またExternal Storageを使う方法を後半で紹介しています。
- API 29
- AndroidXへの移行で変更がいくつかありました。
- API 30
- ユーザーがインストールした別のアプリに対してアプリがクエリまたは操作を行う場合に新しい <queries> 要素を使用します。
Android 11 でのパッケージへのアクセス - メディア インテントのアクションにはシステムのデフォルト カメラのみが応答
動作の変更点: Android 11 をターゲットとするアプリ
- ユーザーがインストールした別のアプリに対してアプリがクエリまたは操作を行う場合に新しい <queries> 要素を使用します。
シンプルなカメラ起動
これは、emulatorでの簡単なカメラテストです。emulatorの「Advanced Settings」からCameraのfront, backの設定をEmulatedにしておきます。
Intentで飛ばして間接的にカメラを起動させるのでAndroid6.0からのRuntime Permissionに引っかかりません。
またこの段階では撮った写真を保存するところまではやっていません。
<queries>
<queries>要素を使用することで、アプリはアクセス可能なその他のアプリのセットを定義できます。
カメラの静止画を撮りたいのでandroid.media.action.IMAGE_CAPTUREを設定します。
1 2 3 4 5 |
<queries> <intent> <action android:name="android.media.action.IMAGE_CAPTURE" /> </intent> </queries> |
MediaStore.ACTION_IMAGE_CAPTURE
をIntentで設定します。
1 2 3 |
Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); resultLauncher.launch(intent); |
Intentで飛ばしたので結果を受け取るためにregisterForActivityResultを使います。
1 2 3 4 5 6 7 8 9 10 |
ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { Intent data = result.getData(); if(data != null) { // ... } } }); |
上記内容をまとめると
MainActivity.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
//package your.package.name; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.appcompat.app.AppCompatActivity; import android.app.Activity; import android.graphics.Bitmap; import android.os.Bundle; import android.content.Intent; import android.provider.MediaStore; import android.util.Log; import android.widget.Button; import android.widget.ImageView; public class MainActivity extends AppCompatActivity { private ImageView imageView; ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { Intent data = result.getData(); if(data != null) { Bitmap bitmap; // cancelしたケースも含む if (data.getExtras() == null) { Log.d("debug", "cancel ?"); return; } else { bitmap = (Bitmap) data.getExtras().get("data"); if (bitmap != null) { // 画像サイズを計測 int bmpWidth = bitmap.getWidth(); int bmpHeight = bitmap.getHeight(); Log.d("debug", String.format("w= %d", bmpWidth)); Log.d("debug", String.format("h= %d", bmpHeight)); } } imageView.setImageBitmap(bitmap); } } }); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = findViewById(R.id.image_view); Button cameraButton = findViewById(R.id.camera_button); // lambda式 cameraButton.setOnClickListener( v -> { Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE); resultLauncher.launch(intent); }); } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/camera_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_margin="20dp" android:text="@string/button" app:layout_constraintVertical_bias="0.2" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/image_view" android:scaleType="fitCenter" android:layout_width="300dp" android:layout_height="300dp" android:contentDescription="@string/description" app:layout_constraintVertical_bias="0.7" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout> |
リソース
strings.xml
1 2 3 4 5 |
<resources> <string name="app_name">Your App Name</string> <string name="button">Button</string> <string name="description">camera picture</string> </resources> |
AndroidManifest.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package=... <queries> <intent> <action android:name="android.media.action.IMAGE_CAPTURE" /> </intent> </queries> <application ... </application> </manifest> |
これでアプリを起動してボタンをタップ
エミュレートされた画像が表示されます。中央のカメラアイコンのボタンで撮影
撮影して画像が固定され、
チェック「✔︎」をクリックすると画像が表示されます。
ただし、これはサムネイル程度のとても小さい画像です。ここでは拡大するようにしていますが、emulatorでは(90 x 160pix)しかありません、また端末によっては画像が回転しているケースもあります。
また、Webcam0はPCのカメラですが、これもサムネイルサイズです。
ここでは、カメラの撮影画像をそのままアプリで取りんでいますが、もっと大きい画像ではこのやり方はできません。