Target Version : 27
参考サイト
•なるべく最小のコードでCamera2のプレビューをしてみたい。
•プレビューだけでいいので、フォーカスやズーム、フラッシュ等いらない。
•撮影もしない。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jp.kd2.simplecamera1">
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera.level.full" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">
<activity
android:name=".MainActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
※ android:theme=@style/Theme.AppCompat.Light.NoActionBar を指定しないと、タイトルバーの分だけアスペクト比が崩れる。※ android:screenOrientation="portrait" を追加しないと、画面が回転しない。
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">
<TextureView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/preview"/>
</android.support.constraint.ConstraintLayout>
MainActivity.kt
package jp.kd2.simplecamera1
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
import android.support.v4.content.ContextCompat;
import android.util.Log;
import android.util.Size;
import android.view.Surface;
import android.view.TextureView;
class MainActivity : AppCompatActivity() {
// ? -> Nullable Type
private var mTextureView: TextureView? = null
private val TAG = MainActivity::class.java.simpleName
// Activity初期化
// 立ち上げ時と、タテ→ヨコ、ヨコ→タテの変換時にも呼ばれる。
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
mTextureView = findViewById(R.id.preview);
}
// 描画時
override fun onResume() {
super.onResume()
// TextureViewが利用可能になったらカメラを開く
if (mTextureView!!.isAvailable()) {
// call now
val width = mTextureView!!.getWidth()
val height = mTextureView!!.getHeight()
openCamera(width, height)
} else {
// 動画等を描画する際にコールバックする関数を登録する。
mTextureView!!.setSurfaceTextureListener(mSurfaceTextureListener)
}
}
// 停止時
public override fun onPause() {
super.onPause()
closeCamera()
}
/******************** カメラ制御 ********************/
private var mCameraDevice: CameraDevice? = null
private var mSize: Size? = null
// カメラの状態によるコールバックメソッド
private val mStateCallback = object : CameraDevice.StateCallback() {
// カメラに接続された時
override fun onOpened(cameraDevice: CameraDevice) {
mCameraDevice = cameraDevice
createCameraPreviewSession()
}
// カメラが切断させたとき
override fun onDisconnected(cameraDevice: CameraDevice) {
mCameraDevice = null
}
// エラー
override fun onError(cameraDevice: CameraDevice, i: Int) {
mCameraDevice = null
}
}
// カメラに接続する。
private fun openCamera(width: Int, height: Int) {
// パーミッションのチェック
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
// パーミッションを求める。
requestCameraPermission()
return
}
val cameraManager = getSystemService(Context.CAMERA_SERVICE) as CameraManager
try {
val cameraId = cameraManager.cameraIdList[0]
val characteristics = cameraManager.getCameraCharacteristics(cameraId)
val map = characteristics.get(
CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
mSize = map!!.getOutputSizes(SurfaceTexture::class.java)[0]
cameraManager.openCamera(cameraId, mStateCallback, null)
} catch (t: Throwable) {
Log.d(TAG, t.message)
}
}
// カメラを切断する。
private fun closeCamera() {
try {
if (null != mCameraDevice)
mCameraDevice!!.close()
} catch (t: Throwable) {
Log.d(TAG, t.message)
}
}
/******************** プレビュー制御 ********************/
private var mCaptureRequestbuilder: CaptureRequest.Builder? = null
// 描画領域のイベントリスナ
private val mSurfaceTextureListener = object : TextureView.SurfaceTextureListener {
override fun onSurfaceTextureAvailable(texture: SurfaceTexture, width: Int, height: Int) {
openCamera(width, height)
}
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) {}
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture): Boolean {
return true
}
override fun onSurfaceTextureUpdated(texture: SurfaceTexture) {}
}
// 描画領域のコールバックメソッド
private val mCaptureStateCallback = object : CameraCaptureSession.StateCallback() {
override fun onConfigured(cameraCaptureSession: CameraCaptureSession) {
try {
cameraCaptureSession.setRepeatingRequest(mCaptureRequestbuilder!!.build(), null, null)
} catch (t: Throwable) {
Log.d(TAG, t.message)
}
}
override fun onConfigureFailed(cameraCaptureSession: CameraCaptureSession) {}
}
// プレビューセッションの開始
private fun createCameraPreviewSession() {
val texture = mTextureView!!.getSurfaceTexture()
texture.setDefaultBufferSize(mSize!!.getWidth(), mSize!!.getHeight())
val surface = Surface(texture)
try {
mCaptureRequestbuilder = mCameraDevice!!.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
mCaptureRequestbuilder!!.addTarget(surface)
mCameraDevice!!.createCaptureSession(listOf(surface), mCaptureStateCallback, null)
} catch (t: Throwable) {
Log.d(TAG, t.message)
}
}
/******************** パーミッション制御 ********************/
private val REQUEST_CAMERA_PERMISSION = 1
// ユーザにパーミッションの許可を求める。
private fun requestCameraPermission() {
requestPermissions(arrayOf(Manifest.permission.CAMERA), REQUEST_CAMERA_PERMISSION)
}
// パーミッションの結果を取得後のコールバックメソッド
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>,
grantResults: IntArray) {
if (requestCode == REQUEST_CAMERA_PERMISSION) {
if (grantResults.size != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
// パーミッションが許可されなかった場合。
this.finish()
}
} else {
// 許可ダイアログの承認結果を受け取る。
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
}