├── README.md └── androidCamera2Sample ├── .classpath ├── .gitignore ├── .project ├── AndroidManifest.xml ├── ic_launcher-web.png ├── proguard-project.txt ├── project.properties ├── res ├── drawable-mdpi │ └── ic_launcher.png ├── layout │ └── activity_main.xml ├── menu │ └── main.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml ├── values-w820dp │ └── dimens.xml └── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml └── src └── org └── kotemaru └── android └── camera2sample ├── AutoFitTextureView.java ├── Camera2StateMachine.java ├── Camera2Util.java └── MainActivity.java /README.md: -------------------------------------------------------------------------------- 1 | # androidCamera2Sample 2 | Android Camera2 API sample code. 3 | 4 | See http://blog.kotemaru.org/2015/05/23/android-camera2-sample.html 5 | 6 | -------------------------------------------------------------------------------- /androidCamera2Sample/.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /androidCamera2Sample/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | /gen/ 3 | -------------------------------------------------------------------------------- /androidCamera2Sample/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | androidCamera2Sample 4 | 5 | 6 | 7 | 8 | 9 | com.android.ide.eclipse.adt.ResourceManagerBuilder 10 | 11 | 12 | 13 | 14 | com.android.ide.eclipse.adt.PreCompilerBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.jdt.core.javabuilder 20 | 21 | 22 | 23 | 24 | com.android.ide.eclipse.adt.ApkBuilder 25 | 26 | 27 | 28 | 29 | 30 | com.android.ide.eclipse.adt.AndroidNature 31 | org.eclipse.jdt.core.javanature 32 | 33 | 34 | -------------------------------------------------------------------------------- /androidCamera2Sample/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 12 | 17 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /androidCamera2Sample/ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotemaru/androidCamera2Sample/98a707accdc5126c67d7f19c5fba1061ef3df8cb/androidCamera2Sample/ic_launcher-web.png -------------------------------------------------------------------------------- /androidCamera2Sample/proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /androidCamera2Sample/project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-22 15 | -------------------------------------------------------------------------------- /androidCamera2Sample/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kotemaru/androidCamera2Sample/98a707accdc5126c67d7f19c5fba1061ef3df8cb/androidCamera2Sample/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /androidCamera2Sample/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 12 | 13 | 18 | 19 | 25 | 26 | 27 | 33 | 34 | -------------------------------------------------------------------------------- /androidCamera2Sample/res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /androidCamera2Sample/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /androidCamera2Sample/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /androidCamera2Sample/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 64dp 9 | 10 | 11 | -------------------------------------------------------------------------------- /androidCamera2Sample/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /androidCamera2Sample/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | androidCamera2Sample 5 | Hello world! 6 | Settings 7 | 8 | 9 | -------------------------------------------------------------------------------- /androidCamera2Sample/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /androidCamera2Sample/src/org/kotemaru/android/camera2sample/AutoFitTextureView.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2014 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.kotemaru.android.camera2sample; 18 | 19 | import android.content.Context; 20 | import android.util.AttributeSet; 21 | import android.view.TextureView; 22 | 23 | /** 24 | * A {@link TextureView} that can be adjusted to a specified aspect ratio. 25 | */ 26 | public class AutoFitTextureView extends TextureView { 27 | 28 | private int mRatioWidth = 0; 29 | private int mRatioHeight = 0; 30 | 31 | public AutoFitTextureView(Context context) { 32 | this(context, null); 33 | } 34 | 35 | public AutoFitTextureView(Context context, AttributeSet attrs) { 36 | this(context, attrs, 0); 37 | } 38 | 39 | public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) { 40 | super(context, attrs, defStyle); 41 | } 42 | 43 | /** 44 | * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio 45 | * calculated from the parameters. Note that the actual sizes of parameters don't matter, that 46 | * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result. 47 | * 48 | * @param width Relative horizontal size 49 | * @param height Relative vertical size 50 | */ 51 | public void setAspectRatio(int width, int height) { 52 | if (width < 0 || height < 0) { 53 | throw new IllegalArgumentException("Size cannot be negative."); 54 | } 55 | mRatioWidth = width; 56 | mRatioHeight = height; 57 | requestLayout(); 58 | } 59 | 60 | @Override 61 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { 62 | super.onMeasure(widthMeasureSpec, heightMeasureSpec); 63 | int width = MeasureSpec.getSize(widthMeasureSpec); 64 | int height = MeasureSpec.getSize(heightMeasureSpec); 65 | if (0 == mRatioWidth || 0 == mRatioHeight) { 66 | setMeasuredDimension(width, height); 67 | } else { 68 | if (width < height * mRatioWidth / mRatioHeight) { 69 | setMeasuredDimension(width, width * mRatioHeight / mRatioWidth); 70 | } else { 71 | setMeasuredDimension(height * mRatioWidth / mRatioHeight, height); 72 | } 73 | } 74 | } 75 | 76 | //----------------------------------------------------------- 77 | // added by kotemaru.org 78 | public void setPreviewSize(int width, int height) { 79 | setAspectRatio(width, height); 80 | } 81 | public int getPreviewWidth() { 82 | return mRatioWidth; 83 | } 84 | public int getPreviewHeight() { 85 | return mRatioHeight; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /androidCamera2Sample/src/org/kotemaru/android/camera2sample/Camera2StateMachine.java: -------------------------------------------------------------------------------- 1 | // Copyright 2015 kotemaru.org. (http://www.apache.org/licenses/LICENSE-2.0) 2 | package org.kotemaru.android.camera2sample; 3 | 4 | import java.util.Arrays; 5 | import java.util.List; 6 | 7 | import android.app.Activity; 8 | import android.content.Context; 9 | import android.graphics.ImageFormat; 10 | import android.graphics.SurfaceTexture; 11 | import android.hardware.camera2.CameraAccessException; 12 | import android.hardware.camera2.CameraCaptureSession; 13 | import android.hardware.camera2.CameraCharacteristics; 14 | import android.hardware.camera2.CameraDevice; 15 | import android.hardware.camera2.CameraManager; 16 | import android.hardware.camera2.CameraMetadata; 17 | import android.hardware.camera2.CaptureRequest; 18 | import android.hardware.camera2.CaptureResult; 19 | import android.hardware.camera2.TotalCaptureResult; 20 | import android.hardware.camera2.params.StreamConfigurationMap; 21 | import android.media.ImageReader; 22 | import android.os.Handler; 23 | import android.util.Log; 24 | import android.util.Size; 25 | import android.view.Surface; 26 | import android.view.TextureView; 27 | 28 | public class Camera2StateMachine { 29 | private static final String TAG = Camera2StateMachine.class.getSimpleName(); 30 | private CameraManager mCameraManager; 31 | 32 | private CameraDevice mCameraDevice; 33 | private CameraCaptureSession mCaptureSession; 34 | private ImageReader mImageReader; 35 | private CaptureRequest.Builder mPreviewRequestBuilder; 36 | 37 | private AutoFitTextureView mTextureView; 38 | private Handler mHandler = null; // default current thread. 39 | private State mState = null; 40 | private ImageReader.OnImageAvailableListener mTakePictureListener; 41 | 42 | public void open(Activity activity, AutoFitTextureView textureView) { 43 | if (mState != null) throw new IllegalStateException("Alrady started state=" + mState); 44 | mTextureView = textureView; 45 | mCameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); 46 | nextState(mInitSurfaceState); 47 | } 48 | public boolean takePicture(ImageReader.OnImageAvailableListener listener) { 49 | if (mState != mPreviewState) return false; 50 | mTakePictureListener = listener; 51 | nextState(mAutoFocusState); 52 | return true; 53 | } 54 | public void close() { 55 | nextState(mAbortState); 56 | } 57 | 58 | // ---------------------------------------------------------------------------------------- 59 | // The following private 60 | private void shutdown() { 61 | if (null != mCaptureSession) { 62 | mCaptureSession.close(); 63 | mCaptureSession = null; 64 | } 65 | if (null != mCameraDevice) { 66 | mCameraDevice.close(); 67 | mCameraDevice = null; 68 | } 69 | if (null != mImageReader) { 70 | mImageReader.close(); 71 | mImageReader = null; 72 | } 73 | } 74 | 75 | private void nextState(State nextState) { 76 | Log.d(TAG, "state: " + mState + "->" + nextState); 77 | try { 78 | if (mState != null) mState.finish(); 79 | mState = nextState; 80 | if (mState != null) mState.enter(); 81 | } catch (CameraAccessException e) { 82 | Log.e(TAG, "next(" + nextState + ")", e); 83 | shutdown(); 84 | } 85 | } 86 | 87 | private abstract class State { 88 | private String mName; 89 | 90 | public State(String name) { 91 | mName = name; 92 | } 93 | //@formatter:off 94 | public String toString() {return mName;} 95 | public void enter() throws CameraAccessException {} 96 | public void onSurfaceTextureAvailable(int width, int height){} 97 | public void onCameraOpened(CameraDevice cameraDevice){} 98 | public void onSessionConfigured(CameraCaptureSession cameraCaptureSession) {} 99 | public void onCaptureResult(CaptureResult result, boolean isCompleted) throws CameraAccessException {} 100 | public void finish() throws CameraAccessException {} 101 | //@formatter:on 102 | } 103 | 104 | // =================================================================================== 105 | // State Definition 106 | private final State mInitSurfaceState = new State("InitSurface") { 107 | public void enter() throws CameraAccessException { 108 | if (mTextureView.isAvailable()) { 109 | nextState(mOpenCameraState); 110 | } else { 111 | mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); 112 | } 113 | } 114 | public void onSurfaceTextureAvailable(int width, int height) { 115 | nextState(mOpenCameraState); 116 | } 117 | 118 | private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() { 119 | @Override 120 | public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) { 121 | if (mState != null) mState.onSurfaceTextureAvailable(width, height); 122 | } 123 | @Override 124 | public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) { 125 | // TODO: ratation changed. 126 | } 127 | @Override 128 | public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) { 129 | return true; 130 | } 131 | @Override 132 | public void onSurfaceTextureUpdated(SurfaceTexture texture) { 133 | } 134 | }; 135 | }; 136 | // ----------------------------------------------------------------------------------- 137 | private final State mOpenCameraState = new State("OpenCamera") { 138 | public void enter() throws CameraAccessException { 139 | // configureTransform(width, height); 140 | String cameraId = Camera2Util.getCameraId(mCameraManager, CameraCharacteristics.LENS_FACING_BACK); 141 | CameraCharacteristics characteristics = mCameraManager.getCameraCharacteristics(cameraId); 142 | StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); 143 | 144 | mImageReader = Camera2Util.getMaxSizeImageReader(map, ImageFormat.JPEG); 145 | Size previewSize = Camera2Util.getBestPreviewSize(map, mImageReader); 146 | mTextureView.setPreviewSize(previewSize.getHeight(), previewSize.getWidth()); 147 | 148 | mCameraManager.openCamera(cameraId, mStateCallback, mHandler); 149 | Log.d(TAG, "openCamera:" + cameraId); 150 | } 151 | public void onCameraOpened(CameraDevice cameraDevice) { 152 | mCameraDevice = cameraDevice; 153 | nextState(mCreateSessionState); 154 | } 155 | 156 | private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() { 157 | @Override 158 | public void onOpened(CameraDevice cameraDevice) { 159 | if (mState != null) mState.onCameraOpened(cameraDevice); 160 | } 161 | @Override 162 | public void onDisconnected(CameraDevice cameraDevice) { 163 | nextState(mAbortState); 164 | } 165 | @Override 166 | public void onError(CameraDevice cameraDevice, int error) { 167 | Log.e(TAG, "CameraDevice:onError:" + error); 168 | nextState(mAbortState); 169 | } 170 | }; 171 | }; 172 | // ----------------------------------------------------------------------------------- 173 | private final State mCreateSessionState = new State("CreateSession") { 174 | public void enter() throws CameraAccessException { 175 | mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); 176 | SurfaceTexture texture = mTextureView.getSurfaceTexture(); 177 | texture.setDefaultBufferSize(mTextureView.getPreviewWidth(), mTextureView.getPreviewHeight()); 178 | Surface surface = new Surface(texture); 179 | mPreviewRequestBuilder.addTarget(surface); 180 | List outputs = Arrays.asList(surface, mImageReader.getSurface()); 181 | mCameraDevice.createCaptureSession(outputs, mSessionCallback, mHandler); 182 | } 183 | public void onSessionConfigured(CameraCaptureSession cameraCaptureSession) { 184 | mCaptureSession = cameraCaptureSession; 185 | nextState(mPreviewState); 186 | } 187 | 188 | private final CameraCaptureSession.StateCallback mSessionCallback = new CameraCaptureSession.StateCallback() { 189 | @Override 190 | public void onConfigured(CameraCaptureSession cameraCaptureSession) { 191 | if (mState != null) mState.onSessionConfigured(cameraCaptureSession); 192 | } 193 | @Override 194 | public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) { 195 | nextState(mAbortState); 196 | } 197 | }; 198 | }; 199 | // ----------------------------------------------------------------------------------- 200 | private final State mPreviewState = new State("Preview") { 201 | public void enter() throws CameraAccessException { 202 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); 203 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 204 | mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mHandler); 205 | } 206 | }; 207 | private final CameraCaptureSession.CaptureCallback mCaptureCallback = new CameraCaptureSession.CaptureCallback() { 208 | @Override 209 | public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) { 210 | onCaptureResult(partialResult, false); 211 | } 212 | @Override 213 | public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { 214 | onCaptureResult(result, true); 215 | } 216 | private void onCaptureResult(CaptureResult result, boolean isCompleted) { 217 | try { 218 | if (mState != null) mState.onCaptureResult(result, isCompleted); 219 | } catch (CameraAccessException e) { 220 | Log.e(TAG, "handle():", e); 221 | nextState(mAbortState); 222 | } 223 | } 224 | }; 225 | // ----------------------------------------------------------------------------------- 226 | private final State mAutoFocusState = new State("AutoFocus") { 227 | public void enter() throws CameraAccessException { 228 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_START); 229 | mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mHandler); 230 | } 231 | public void onCaptureResult(CaptureResult result, boolean isCompleted) throws CameraAccessException { 232 | Integer afState = result.get(CaptureResult.CONTROL_AF_STATE); 233 | boolean isAfReady = afState == null 234 | || afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED 235 | || afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED; 236 | if (isAfReady) { 237 | nextState(mAutoExposureState); 238 | } 239 | } 240 | }; 241 | // ----------------------------------------------------------------------------------- 242 | private final State mAutoExposureState = new State("AutoExposure") { 243 | public void enter() throws CameraAccessException { 244 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, 245 | CameraMetadata.CONTROL_AE_PRECAPTURE_TRIGGER_START); 246 | mCaptureSession.setRepeatingRequest(mPreviewRequestBuilder.build(), mCaptureCallback, mHandler); 247 | } 248 | public void onCaptureResult(CaptureResult result, boolean isCompleted) throws CameraAccessException { 249 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE); 250 | boolean isAeReady = aeState == null 251 | || aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED 252 | || aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED; 253 | if (isAeReady) { 254 | nextState(mTakePictureState); 255 | } 256 | } 257 | }; 258 | // ----------------------------------------------------------------------------------- 259 | private final State mTakePictureState = new State("TakePicture") { 260 | public void enter() throws CameraAccessException { 261 | final CaptureRequest.Builder captureBuilder = 262 | mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); 263 | captureBuilder.addTarget(mImageReader.getSurface()); 264 | captureBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); 265 | captureBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 266 | captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, 90); // portraito 267 | mImageReader.setOnImageAvailableListener(mTakePictureListener, mHandler); 268 | 269 | mCaptureSession.stopRepeating(); 270 | mCaptureSession.capture(captureBuilder.build(), mCaptureCallback, mHandler); 271 | } 272 | public void onCaptureResult(CaptureResult result, boolean isCompleted) throws CameraAccessException { 273 | if (isCompleted) { 274 | nextState(mPreviewState); 275 | } 276 | } 277 | public void finish() throws CameraAccessException { 278 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CameraMetadata.CONTROL_AF_TRIGGER_CANCEL); 279 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH); 280 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback, mHandler); 281 | mTakePictureListener = null; 282 | } 283 | }; 284 | // ----------------------------------------------------------------------------------- 285 | private final State mAbortState = new State("Abort") { 286 | public void enter() throws CameraAccessException { 287 | shutdown(); 288 | nextState(null); 289 | } 290 | }; 291 | } 292 | -------------------------------------------------------------------------------- /androidCamera2Sample/src/org/kotemaru/android/camera2sample/Camera2Util.java: -------------------------------------------------------------------------------- 1 | package org.kotemaru.android.camera2sample; 2 | 3 | import android.graphics.SurfaceTexture; 4 | import android.hardware.camera2.CameraAccessException; 5 | import android.hardware.camera2.CameraCharacteristics; 6 | import android.hardware.camera2.CameraManager; 7 | import android.hardware.camera2.params.StreamConfigurationMap; 8 | import android.media.ImageReader; 9 | import android.util.Size; 10 | 11 | public class Camera2Util { 12 | public static String getCameraId(CameraManager cameraManager, int facing) throws CameraAccessException { 13 | for (String cameraId : cameraManager.getCameraIdList()) { 14 | CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId); 15 | if (characteristics.get(CameraCharacteristics.LENS_FACING) == facing) { 16 | return cameraId; 17 | } 18 | } 19 | return null; 20 | } 21 | 22 | public static ImageReader getMaxSizeImageReader(StreamConfigurationMap map, int imageFormat) throws CameraAccessException { 23 | Size[] sizes = map.getOutputSizes(imageFormat); 24 | Size maxSize = sizes[0]; 25 | for (Size size:sizes) { 26 | if (size.getWidth() > maxSize.getWidth()) { 27 | maxSize = size; 28 | } 29 | } 30 | ImageReader imageReader = ImageReader.newInstance( 31 | //maxSize.getWidth(), maxSize.getHeight(), // for landscape. 32 | maxSize.getHeight(), maxSize.getWidth(), // for portrait. 33 | imageFormat, /*maxImages*/1); 34 | return imageReader; 35 | } 36 | 37 | public static Size getBestPreviewSize(StreamConfigurationMap map, ImageReader imageSize) throws CameraAccessException { 38 | //float imageAspect = (float) imageSize.getWidth() / imageSize.getHeight(); // for landscape. 39 | float imageAspect = (float) imageSize.getHeight() / imageSize.getWidth(); // for portrait 40 | float minDiff = 1000000000000F; 41 | Size[] previewSizes = map.getOutputSizes(SurfaceTexture.class); 42 | Size previewSize = previewSizes[0]; 43 | for (Size size : previewSizes) { 44 | float previewAspect = (float) size.getWidth() / size.getHeight(); 45 | float diff = Math.abs(imageAspect - previewAspect); 46 | if (diff < minDiff) { 47 | previewSize = size; 48 | minDiff = diff; 49 | } 50 | if (diff == 0.0F) break; 51 | } 52 | return previewSize; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /androidCamera2Sample/src/org/kotemaru/android/camera2sample/MainActivity.java: -------------------------------------------------------------------------------- 1 | package org.kotemaru.android.camera2sample; 2 | 3 | import java.nio.ByteBuffer; 4 | 5 | import android.app.Activity; 6 | import android.graphics.Bitmap; 7 | import android.graphics.BitmapFactory; 8 | import android.media.Image; 9 | import android.media.ImageReader; 10 | import android.os.Bundle; 11 | import android.view.KeyEvent; 12 | import android.view.View; 13 | import android.widget.ImageView; 14 | 15 | public class MainActivity extends Activity { 16 | private AutoFitTextureView mTextureView; 17 | private ImageView mImageView; 18 | private Camera2StateMachine mCamera2; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_main); 24 | 25 | mTextureView = (AutoFitTextureView) findViewById(R.id.TextureView); 26 | mImageView = (ImageView) findViewById(R.id.ImageView); 27 | mCamera2 = new Camera2StateMachine(); 28 | } 29 | 30 | @Override 31 | protected void onResume() { 32 | super.onResume(); 33 | mCamera2.open(this, mTextureView); 34 | } 35 | @Override 36 | protected void onPause() { 37 | mCamera2.close(); 38 | super.onPause(); 39 | } 40 | @Override 41 | public boolean onKeyDown(int keyCode, KeyEvent event) { 42 | if (keyCode == KeyEvent.KEYCODE_BACK && mImageView.getVisibility() == View.VISIBLE) { 43 | mTextureView.setVisibility(View.VISIBLE); 44 | mImageView.setVisibility(View.INVISIBLE); 45 | return false; 46 | } 47 | return super.onKeyDown(keyCode, event); 48 | } 49 | public void onClickShutter(View view) { 50 | mCamera2.takePicture(new ImageReader.OnImageAvailableListener() { 51 | @Override 52 | public void onImageAvailable(ImageReader reader) { 53 | // 撮れた画像をImageViewに貼り付けて表示。 54 | final Image image = reader.acquireLatestImage(); 55 | ByteBuffer buffer = image.getPlanes()[0].getBuffer(); 56 | byte[] bytes = new byte[buffer.remaining()]; 57 | buffer.get(bytes); 58 | Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length); 59 | image.close(); 60 | 61 | mImageView.setImageBitmap(bitmap); 62 | mImageView.setVisibility(View.VISIBLE); 63 | mTextureView.setVisibility(View.INVISIBLE); 64 | } 65 | }); 66 | } 67 | 68 | } 69 | --------------------------------------------------------------------------------