Androidアプリ＆Kotlinでハマった点の技術的原因と対応方法（２．Android*のカメラ機能に関する処理）

# ２．*Android*のカメラ機能に関する処理
カメラ撮影後のイメージ保存場所は、サードベンダーが提供するカメラアプリ毎に相違があるようで、暗黙的*Intent*パラメータの挙動、内容に注意する必要があります。
また、*Android*バージョン6.0以降になると権限チェック及び権限付与確認をアプリの初起動時にユーザへ求めることになります。

## ２．１ 画像選択時のギャラリー又はカメラ機能を選択する*Chooser*処理

### ＜背景＞
本アプリでは、*Android*端末内のギャラリーの画像もしくはカメラ撮影を実施した後、画面遷移後にイメージ画像を貼り付ける処理を行います。

### ＜課題＞
*Android*端末内のギャラリーの画像もしくはカメラ撮影の２つの機能（暗黙的*Intent*（ギャラリー機能）／暗黙的*Intent*（カメラ機能））の*Intent*登録において、画面選択ボタンをタッチすると暗黙的*Intent*（ギャラリー機能）のみで暗黙的*Intent*（カメラ機能）が表示されない。
一方で、直後にキャンセルして再度、画面選択ボタンをタッチすると暗黙的*Intent*（ギャラリー機能）が複数表示されます。

### ＜原因＞
*Android*端末内のギャラリーの画像もしくはカメラ撮影の２つの機能の*Intent*登録の順番に誤りがありました。

### ＜対応＞
２つの機能（暗黙的*Intent*（ギャラリー機能）／暗黙的*Intent*（カメラ機能））の*Intent*登録を下記の順とします。
①暗黙的*Intent*（カメラ機能）の作成
②暗黙的*Intent*（ギャラリー機能）の作成
③*Chooser*の作成

```Kotlin:暗黙的Intent（ギャラリー機能／カメラ機能）の登録順
// ..... 略
	private fun addPhoto(requestCode: Int) {
		getCameraIntent()
		createChooserIntent()
// ..... 略
	}
// ..... 略
```

```Kotlin:暗黙的Intent（カメラ機能）の作成
// ..... 略
	private fun getCameraIntent() {
		Intent(MediaStore.ACTION_IMAGE_CAPTURE)
// ..... 略
	}
// ..... 略
```

```Kotlin:暗黙的Intent（ギャラリー機能）＆Chooserの作成
// ..... 略
	private fun createChooserIntent(): Intent {
		Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
			addCategory(Intent.CATEGORY_OPENABLE)
			type = "image/*"
		}
		return Intent.createChooser(引数).apply {
			putExtra(Intent.EXTRA_INITIAL_INTENTS, 引数)
		}
	}
// ..... 略
```

## ２．２ *Chooser*のカメラ機能に他カメラアプリを除外する処理

### ＜背景＞
本アプリでは、画面選択ボタンをタッチしてギャラリーの画像もしくはサードベンダーが提供するカメラアプリを除外してカメラ撮影を実施した後、画面遷移後にイメージ画像を貼り付ける処理を行います。

### ＜課題＞
サードベンダーが提供するカメラアプリが撮影画像の保存場所が不明のため、影響度を考慮して*Chooser*から除外します。

### ＜原因＞
なし

### ＜対応＞
暗黙的*Intent*（カメラ機能）の作成後、内蔵カメラ機能のクラス名とマッチした場合に新たな暗黙的*Intent*（カメラ機能）を作成します。

```Kotlin:他カメラアプリ除外
// ..... 略
	Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
		val intentInfoList = context?.packageManager?.queryIntentActivities(this, 0) ?: return

		// 他カメラアプリの仕様が不明のため、内蔵カメラのみ対象
		for (intentInfo in intentInfoList) {
			val packageName = intentInfo.activityInfo.packageName
			val name = intentInfo.activityInfo.name
			if (name.contains(CAMERA_CLS_NAME)) { // CAMERA_CLS_NAME → "com.android.camera"
				Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
// ..... 略
				}
			}
		}
	}
// ..... 略
```

## ２．３ カメラ撮影時の*onActivityResult()*の*Intent*パラメータ処理

### ＜背景＞
本アプリでは、画面選択ボタンをタッチしてギャラリーの画像もしくはカメラ撮影を実施した後、画面遷移後にイメージ画像を貼り付ける処理を行います。

### ＜課題＞
画像選択ボタンをタッチしてギャラリーの画像もしくはカメラ撮影を実施した後、画面遷移先レイアウト上の*ImageView*にイメージ画像が表示されず、画面が真っ白になります。

### ＜原因＞
*IntentChooser*付きの暗黙的*Intent*（カメラ機能）を作成する場合、*putExtra(MediaStore.EXTRA_OUTPUT, cameraUri)* を除外しないと*onActivityResult()*の*Intent*パラメータが*null*になるため、*Intent*先でカメラ撮影の*Uri*を取得できません。
（公式ドキュメントの暗黙的*Intent*例を使用）

### ＜対応＞
*putExtra(MediaStore.EXTRA_OUTPUT, cameraUri)* を除外して暗黙的*Intent*（カメラ機能）を作成します。

```Kotlin:putExtra()除外
// ..... 略
	Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
		val intentInfoList = context?.packageManager?.queryIntentActivities(this, 0) ?: return

		// 他カメラアプリの仕様が不明のため、内蔵カメラのみ対象
		for (intentInfo in intentInfoList) {
			val packageName = intentInfo.activityInfo.packageName
			val name = intentInfo.activityInfo.name
			if (name.contains(CAMERA_CLS_NAME)) { // CAMERA_CLS_NAME → "com.android.camera"
				Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply {
// ..... 略
					// putExtra(MediaStore.EXTRA_OUTPUT, cameraUri) → 除外
				}
			}
		}
	}
// ..... 略
```
  
## リンク
[初めてのAndroidアプリ＆Kotlinでハマった点の技術的原因と対応方法](https://qiita.com/schenlybiz/items/24d97c10f62c55334f6a)
[１．Androidの画面遷移（フラグメント）処理](https://qiita.com/schenlybiz/items/2aa4d4d2420ea73bef50)
[３．Androidの画像に関する処理](https://qiita.com/schenlybiz/items/b72c2106d7eadf2c1582)