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 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/SampleProject/app/src/main/java/org/techbooster/sample/camera2application/MainActivity.java:
--------------------------------------------------------------------------------
1 | package org.techbooster.sample.camera2application;
2 |
3 | import android.Manifest;
4 | import android.app.Activity;
5 | import android.app.AlertDialog;
6 | import android.content.Context;
7 | import android.content.DialogInterface;
8 | import android.content.pm.PackageManager;
9 | import android.content.res.Configuration;
10 | import android.graphics.ImageFormat;
11 | import android.graphics.Matrix;
12 | import android.graphics.RectF;
13 | import android.graphics.SurfaceTexture;
14 | import android.hardware.camera2.CameraAccessException;
15 | import android.hardware.camera2.CameraCharacteristics;
16 | import android.hardware.camera2.CameraManager;
17 | import android.hardware.camera2.params.StreamConfigurationMap;
18 | import android.media.ImageReader;
19 | import android.os.Bundle;
20 | import android.os.Handler;
21 | import android.util.Log;
22 | import android.util.Size;
23 | import android.view.Surface;
24 | import android.view.TextureView;
25 | import android.view.View;
26 |
27 | import java.io.File;
28 | import java.util.ArrayList;
29 | import java.util.Arrays;
30 | import java.util.Collections;
31 | import java.util.Comparator;
32 | import java.util.List;
33 |
34 | public class MainActivity extends Activity implements CameraInterface {
35 |
36 | private static final String TAG = "Camera2App";
37 |
38 | private int REQUEST_CODE_CAMERA_PERMISSION = 0x01;
39 |
40 | private Size mPreviewSize;
41 | private AutoFitTextureView mTextureView;
42 |
43 | private ImageReader mImageReader;
44 | private BackgroundThreadHelper mThread;
45 | private BasicCamera mCamera;
46 |
47 | @Override
48 | protected void onCreate(Bundle savedInstanceState) {
49 | super.onCreate(savedInstanceState);
50 | setContentView(R.layout.activity_main);
51 | mTextureView = (AutoFitTextureView) findViewById(R.id.texture);
52 | mThread = new BackgroundThreadHelper();
53 |
54 | // Camera2 APIを別クラスへ切り出し(サンプルなので!ロジックが混ざらないように)
55 | mCamera = new BasicCamera();
56 | mCamera.setInterface(this);
57 | findViewById(R.id.picture).setOnClickListener(new View.OnClickListener() {
58 | @Override
59 | public void onClick(View v) {
60 | mCamera.takePicture();
61 | }
62 | });
63 | }
64 |
65 | @Override
66 | public void onResume() {
67 | super.onResume();
68 | mThread.start();
69 |
70 | if (mTextureView.isAvailable()) {
71 | // Preview用のTextureViewの準備ができている
72 | openCamera(mTextureView.getWidth(), mTextureView.getHeight());
73 | } else {
74 | // 準備完了通知を受け取るためにリスナーを登録する
75 | mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
76 | }
77 | }
78 |
79 | @Override
80 | public void onPause() {
81 | closeCamera();
82 | mThread.stop();
83 | super.onPause();
84 | }
85 |
86 | private String setUpCameraOutputs(int width, int height) {
87 | CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
88 | try {
89 | for (String cameraId : manager.getCameraIdList()) {
90 | CameraCharacteristics characteristics
91 | = manager.getCameraCharacteristics(cameraId);
92 |
93 | // フロントカメラを利用しない
94 | Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
95 | if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
96 | continue;
97 | }
98 | // ストリーム制御をサポートしていない場合、セットアップを中断する
99 | StreamConfigurationMap map = characteristics.get(
100 | CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
101 | if (map == null) {
102 | continue;
103 | }
104 |
105 | // 最大サイズでキャプチャする
106 | Size largest = Collections.max(
107 | Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
108 | new CompareSizesByArea());
109 |
110 | setUpPreview(map.getOutputSizes(SurfaceTexture.class),
111 | width, height, largest);
112 | configurePreviewTransform(width, height);
113 |
114 | mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
115 | ImageFormat.JPEG, /*maxImages*/2);
116 | mImageReader.setOnImageAvailableListener(
117 | new ImageReader.OnImageAvailableListener() {
118 |
119 | @Override
120 | public void onImageAvailable(ImageReader reader) {
121 | File file = new File(getExternalFilesDir(null), "pic.jpg");
122 | mThread.getHandler().post(new ImageStore(reader.acquireNextImage(), file));
123 | }
124 |
125 | }, mThread.getHandler());
126 |
127 | return cameraId;
128 | }
129 | } catch (CameraAccessException e) {
130 | e.printStackTrace();
131 | } catch (NullPointerException e) {
132 | // Camera2 API未サポート
133 | Log.e(TAG, "Camera Error:not support Camera2API");
134 | }
135 |
136 | return null;
137 | }
138 |
139 | private void openCamera(int width, int height) {
140 | if (checkSelfPermission(Manifest.permission.CAMERA)
141 | != PackageManager.PERMISSION_GRANTED) {
142 | requestCameraPermission();
143 | return;
144 | }
145 |
146 | String cameraId = setUpCameraOutputs(width, height);
147 | CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
148 | try {
149 | if (!mCamera.isLocked()) {
150 | throw new RuntimeException("Time out waiting to lock camera opening.");
151 | }
152 | manager.openCamera(cameraId, mCamera.stateCallback, mThread.getHandler());
153 | } catch (CameraAccessException e) {
154 | e.printStackTrace();
155 | } catch (InterruptedException e) {
156 | throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
157 | }
158 | }
159 |
160 | private void closeCamera() {
161 | mCamera.close();
162 | if (null != mImageReader) {
163 | mImageReader.close();
164 | mImageReader = null;
165 | }
166 | }
167 |
168 | //Texture Listener
169 | private final TextureView.SurfaceTextureListener mSurfaceTextureListener
170 | = new TextureView.SurfaceTextureListener() {
171 |
172 | @Override
173 | public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) {
174 | // SurfaceTextureの準備が完了した
175 | openCamera(width, height);
176 | }
177 |
178 | @Override
179 | public void onSurfaceTextureSizeChanged(SurfaceTexture texture, int width, int height) {
180 | // Viewのサイズに変更があったためPreviewサイズを計算し直す
181 | configurePreviewTransform(width, height);
182 | }
183 |
184 | @Override
185 | public boolean onSurfaceTextureDestroyed(SurfaceTexture texture) {
186 | return true;
187 | }
188 |
189 | @Override
190 | public void onSurfaceTextureUpdated(SurfaceTexture texture) {
191 | }
192 | };
193 |
194 | private void setUpPreview(Size[] choices, int width, int height, Size aspectRatio) {
195 | // カメラ性能を超えたサイズを指定するとキャプチャデータにゴミがまじるため、注意
196 |
197 | // 表示するSurfaceより、高い解像度のプレビューサイズを抽出する
198 | List bigEnough = new ArrayList<>();
199 | int w = aspectRatio.getWidth();
200 | int h = aspectRatio.getHeight();
201 | for (Size option : choices) {
202 | if (option.getHeight() == option.getWidth() * h / w &&
203 | option.getWidth() >= width && option.getHeight() >= height) {
204 | bigEnough.add(option);
205 | }
206 | }
207 |
208 | // プレビューを表示するSurfaceに最も近い(小さな)解像度を選択する
209 | if (bigEnough.size() > 0) {
210 | mPreviewSize = Collections.min(bigEnough, new CompareSizesByArea());
211 | } else {
212 | Log.e(TAG, "Couldn't find any suitable preview size");
213 | mPreviewSize = choices[0];
214 | }
215 |
216 | // プレビューが歪まないようにアスペクト比を調整する
217 | int orientation = getResources().getConfiguration().orientation;
218 | if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
219 | mTextureView.setAspectRatio(
220 | mPreviewSize.getWidth(), mPreviewSize.getHeight());
221 | } else {
222 | mTextureView.setAspectRatio(
223 | mPreviewSize.getHeight(), mPreviewSize.getWidth());
224 | }
225 | }
226 |
227 | private void configurePreviewTransform(int viewWidth, int viewHeight) {
228 | if (null == mTextureView || null == mPreviewSize) {
229 | return;
230 | }
231 | int rotation = getWindowManager().getDefaultDisplay().getRotation();
232 | Matrix matrix = new Matrix();
233 | RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
234 | RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
235 | float centerX = viewRect.centerX();
236 | float centerY = viewRect.centerY();
237 | if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
238 | bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
239 | matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
240 | float scale = Math.max(
241 | (float) viewHeight / mPreviewSize.getHeight(),
242 | (float) viewWidth / mPreviewSize.getWidth());
243 | matrix.postScale(scale, scale, centerX, centerY);
244 | matrix.postRotate(90 * (rotation - 2), centerX, centerY);
245 | } else if (Surface.ROTATION_180 == rotation) {
246 | matrix.postRotate(180, centerX, centerY);
247 | }
248 | mTextureView.setTransform(matrix);
249 | }
250 |
251 | // パーミッションの処理シーケンスはまだおかしい
252 | // Parmission handling for Android 6.0
253 | private void requestCameraPermission() {
254 | if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
255 | // 権限チェックした結果、持っていない場合はダイアログを出す
256 | new AlertDialog.Builder(this)
257 | .setMessage("Request Permission")
258 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
259 | @Override
260 | public void onClick(DialogInterface dialog, int which) {
261 | requestPermissions(new String[]{Manifest.permission.CAMERA},
262 | REQUEST_CODE_CAMERA_PERMISSION);
263 | }
264 | })
265 | .setNegativeButton(android.R.string.cancel,
266 | new DialogInterface.OnClickListener() {
267 | @Override
268 | public void onClick(DialogInterface dialog, int which) {
269 | finish();
270 | }
271 | })
272 | .create();
273 | return;
274 | }
275 |
276 | // 権限を取得する
277 | requestPermissions(new String[]{Manifest.permission.CAMERA},
278 | REQUEST_CODE_CAMERA_PERMISSION);
279 | return;
280 | }
281 |
282 | @Override
283 | public void onRequestPermissionsResult(int requestCode,
284 | String permissions[], int[] grantResults) {
285 | if (requestCode == REQUEST_CODE_CAMERA_PERMISSION) {
286 | if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
287 | new AlertDialog.Builder(this)
288 | .setMessage("Need Camera Permission")
289 | .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
290 | @Override
291 | public void onClick(DialogInterface dialogInterface, int i) {
292 | finish();
293 | }
294 | })
295 | .create();
296 | }
297 | return;
298 | }
299 |
300 | super.onRequestPermissionsResult(requestCode, permissions, grantResults);
301 | }
302 |
303 | @Override
304 | public SurfaceTexture getSurfaceTextureFromTextureView() {
305 | return mTextureView.getSurfaceTexture();
306 | }
307 |
308 | @Override
309 | public Size getPreviewSize() {
310 | return mPreviewSize;
311 | }
312 |
313 | @Override
314 | public Handler getBackgroundHandler() {
315 | return mThread.getHandler();
316 | }
317 |
318 | @Override
319 | public Surface getImageRenderSurface() {
320 | return mImageReader.getSurface();
321 | }
322 |
323 | @Override
324 | public int getRotation() {
325 | return getWindowManager().getDefaultDisplay().getRotation();
326 | }
327 |
328 | /**
329 | * Compares two {@code Size}s based on their areas.
330 | */
331 | static class CompareSizesByArea implements Comparator {
332 |
333 | @Override
334 | public int compare(Size lhs, Size rhs) {
335 | // We cast here to ensure the multiplications won't overflow
336 | return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
337 | (long) rhs.getWidth() * rhs.getHeight());
338 | }
339 | }
340 |
341 | }
342 |
343 |
--------------------------------------------------------------------------------
/SampleProject/app/src/main/java/org/techbooster/sample/camera2application/BasicCamera.java:
--------------------------------------------------------------------------------
1 | package org.techbooster.sample.camera2application;
2 |
3 | import android.graphics.SurfaceTexture;
4 | import android.hardware.camera2.CameraAccessException;
5 | import android.hardware.camera2.CameraCaptureSession;
6 | import android.hardware.camera2.CameraDevice;
7 | import android.hardware.camera2.CameraMetadata;
8 | import android.hardware.camera2.CaptureRequest;
9 | import android.hardware.camera2.CaptureResult;
10 | import android.hardware.camera2.TotalCaptureResult;
11 | import android.util.Log;
12 | import android.util.Size;
13 | import android.util.SparseIntArray;
14 | import android.view.Surface;
15 |
16 | import java.util.Arrays;
17 | import java.util.concurrent.Semaphore;
18 | import java.util.concurrent.TimeUnit;
19 |
20 | /**
21 | * Created by mhidaka on 2015/11/09.
22 | */
23 | public class BasicCamera {
24 |
25 | private static final String TAG = "BasicCamera";
26 |
27 | private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
28 |
29 | static {
30 | ORIENTATIONS.append(Surface.ROTATION_0, 90);
31 | ORIENTATIONS.append(Surface.ROTATION_90, 0);
32 | ORIENTATIONS.append(Surface.ROTATION_180, 270);
33 | ORIENTATIONS.append(Surface.ROTATION_270, 180);
34 | }
35 |
36 | private static final int STATE_PREVIEW = 0x00;
37 | private static final int STATE_WAITING_LOCK = 0x01;
38 | private static final int STATE_WAITING_PRECAPTURE = 0x02;
39 | private static final int STATE_WAITING_NON_PRECAPTURE = 0x03;
40 | private static final int STATE_PICTURE_TAKEN = 0x04;
41 | private int mState = STATE_PREVIEW;
42 |
43 | private Semaphore mCameraOpenCloseLock = new Semaphore(1);
44 | private CameraDevice mCameraDevice;
45 | private CaptureRequest.Builder mPreviewRequestBuilder;
46 | private CaptureRequest mPreviewRequest;
47 | private CameraCaptureSession mCaptureSession = null;
48 |
49 | private CameraInterface mInterface;
50 |
51 | public void setInterface(CameraInterface param) {
52 | mInterface = param;
53 | }
54 |
55 | public final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
56 |
57 | @Override
58 | public void onOpened(CameraDevice cameraDevice) {
59 | // カメラが利用可能状態になった
60 | mCameraOpenCloseLock.release();
61 | mCameraDevice = cameraDevice;
62 | createCameraPreviewSession();
63 | }
64 |
65 | @Override
66 | public void onDisconnected(CameraDevice cameraDevice) {
67 | mCameraOpenCloseLock.release();
68 | cameraDevice.close();
69 | mCameraDevice = null;
70 | }
71 |
72 | @Override
73 | public void onError(CameraDevice cameraDevice, int error) {
74 | mCameraOpenCloseLock.release();
75 | cameraDevice.close();
76 | mCameraDevice = null;
77 | Log.e(TAG, "Camera StateCallback onError: Please Reboot Android OS");
78 | }
79 |
80 | };
81 |
82 | public boolean isLocked() throws InterruptedException {
83 | return mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS);
84 | }
85 |
86 | public void close() {
87 | try {
88 | mCameraOpenCloseLock.acquire();
89 | if (null != mCaptureSession) {
90 | mCaptureSession.close();
91 | mCaptureSession = null;
92 | }
93 | if (null != mCameraDevice) {
94 | mCameraDevice.close();
95 | mCameraDevice = null;
96 | }
97 | } catch (InterruptedException e) {
98 | throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
99 | } finally {
100 | mCameraOpenCloseLock.release();
101 | }
102 | }
103 |
104 | private void createCameraPreviewSession() {
105 | try {
106 | SurfaceTexture texture = mInterface.getSurfaceTextureFromTextureView();
107 | assert texture != null;
108 |
109 | // カメラ利用開始時にプレビューの設定を行う
110 | Size preview = mInterface.getPreviewSize();
111 | texture.setDefaultBufferSize(preview.getWidth(), preview.getHeight());
112 |
113 | // 画面への表示用のSurfaceを作成する
114 | Surface surface = new Surface(texture);
115 | mPreviewRequestBuilder
116 | = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
117 | mPreviewRequestBuilder.addTarget(surface);
118 |
119 | // プレビュー画面のため、キャプチャセッションを作成する
120 | Surface imageRenderSurface = mInterface.getImageRenderSurface();
121 | mCameraDevice.createCaptureSession(Arrays.asList(surface, imageRenderSurface),
122 | new CameraCaptureSession.StateCallback() {
123 |
124 | @Override
125 | public void onConfigured(CameraCaptureSession cameraCaptureSession) {
126 | // The camera is already closed
127 | if (null == mCameraDevice) {
128 | return;
129 | }
130 |
131 | // プレビュー準備が完了したのでカメラのAF,AE制御を指定する
132 | mCaptureSession = cameraCaptureSession;
133 | try {
134 | // プレビューがぼやけては困るのでオートフォーカスを利用する
135 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
136 | CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
137 | // 露出、フラッシュは自動モードを仕様する
138 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
139 | CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
140 |
141 | // カメラプレビューを開始する(ここでは開始要求のみ)
142 | mPreviewRequest = mPreviewRequestBuilder.build();
143 | mCaptureSession.setRepeatingRequest(mPreviewRequest,
144 | mCaptureCallback, mInterface.getBackgroundHandler());
145 | } catch (CameraAccessException e) {
146 | e.printStackTrace();
147 | }
148 | }
149 |
150 | @Override
151 | public void onConfigureFailed(CameraCaptureSession cameraCaptureSession) {
152 | Log.e(TAG, "CameraCaptureSession onConfigureFailed");
153 | }
154 | }, null
155 | );
156 | } catch (CameraAccessException e) {
157 | e.printStackTrace();
158 | }
159 | }
160 |
161 | private CameraCaptureSession.CaptureCallback mCaptureCallback
162 | = new CameraCaptureSession.CaptureCallback() {
163 |
164 | @Override
165 | public void onCaptureProgressed(CameraCaptureSession session,
166 | CaptureRequest request,
167 | CaptureResult partialResult) {
168 | // キャプチャの進捗状況(随時呼び出される)
169 | process(partialResult);
170 | }
171 |
172 | @Override
173 | public void onCaptureCompleted(CameraCaptureSession session,
174 | CaptureRequest request,
175 | TotalCaptureResult result) {
176 | // キャプチャの完了(プレビューの場合、プレビュー状態が継続)
177 | process(result);
178 | }
179 |
180 |
181 | private void process(CaptureResult result) {
182 | switch (mState) {
183 | case STATE_PREVIEW: {
184 | // プレビュー中は何もしない
185 | break;
186 | }
187 | case STATE_WAITING_LOCK: {
188 | // 焦点が合った時に静止画を撮影する(AF)
189 | Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
190 | if (afState == null) {
191 | captureStillPicture();
192 | } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
193 | CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
194 | // CONTROL_AE_STATE がnullのデバイスがある
195 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
196 | if (aeState == null ||
197 | aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
198 | mState = STATE_PICTURE_TAKEN;
199 | captureStillPicture();
200 | } else {
201 | runPrecaptureSequence();
202 | }
203 | }
204 | break;
205 | }
206 | case STATE_WAITING_PRECAPTURE: {
207 | // キャプチャ準備中
208 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
209 | if (aeState == null || // CONTROL_AE_STATE がnullのデバイスがある
210 | aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
211 | aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
212 | mState = STATE_WAITING_NON_PRECAPTURE;
213 | }
214 | break;
215 | }
216 | case STATE_WAITING_NON_PRECAPTURE: {
217 | // CONTROL_AE_STATE がnullのデバイスがある
218 | Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
219 | if (aeState == null || aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
220 | mState = STATE_PICTURE_TAKEN;
221 | captureStillPicture();
222 | }
223 | break;
224 | }
225 | }
226 | }
227 |
228 | };
229 |
230 | private void captureStillPicture() {
231 | try {
232 | if (null == mCameraDevice) {
233 | return;
234 | }
235 | // 静止画の撮影を開始する
236 | final CaptureRequest.Builder captureBuilder =
237 | mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
238 | captureBuilder.addTarget(mInterface.getImageRenderSurface());
239 |
240 | // 静止画の撮影モードを指定(AF,AE)
241 | captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
242 | CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
243 | captureBuilder.set(CaptureRequest.CONTROL_AE_MODE,
244 | CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
245 |
246 | // 現在のカメラの向きを指定する(0~270度)
247 | int rotation = mInterface.getRotation();
248 | captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, ORIENTATIONS.get(rotation));
249 |
250 | CameraCaptureSession.CaptureCallback CaptureCallback
251 | = new CameraCaptureSession.CaptureCallback() {
252 |
253 | @Override
254 | public void onCaptureCompleted(CameraCaptureSession session,
255 | CaptureRequest request,
256 | TotalCaptureResult result) {
257 | // 静止画撮影が完了した時に呼ばれるコールバック
258 | Log.e(TAG, "onCaptureCompleted Picture Saved");
259 | // プレビュー用の設定に戻す
260 | unlockFocus();
261 | }
262 | };
263 |
264 | mCaptureSession.stopRepeating(); // プレビューを一旦停止する
265 | // 静止画を撮影する(captureBuilder)
266 | mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);
267 | } catch (CameraAccessException e) {
268 | e.printStackTrace();
269 | }
270 | }
271 |
272 | private void runPrecaptureSequence() {
273 | try {
274 | // 静止画の撮影準備:自動露光の準備を開始する
275 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
276 | CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
277 | // 準備完了をまつため、mCaptureCallbackへ進行状況を通知する
278 | mState = STATE_WAITING_PRECAPTURE;
279 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
280 | mInterface.getBackgroundHandler());
281 | } catch (CameraAccessException e) {
282 | e.printStackTrace();
283 | }
284 | }
285 |
286 | public void takePicture() {
287 | if (mCaptureSession != null) {
288 | lockFocus();
289 | }
290 | }
291 |
292 | private void lockFocus() {
293 | try {
294 | // 静止画を撮影するため、AFをロックする
295 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
296 | CameraMetadata.CONTROL_AF_TRIGGER_START);
297 | // captureを実行する。AFロック完了通知を受け取るため、mCaptureCallbackへ進行状況を通知する
298 | mState = STATE_WAITING_LOCK;
299 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
300 | mInterface.getBackgroundHandler());
301 | } catch (CameraAccessException e) {
302 | e.printStackTrace();
303 | }
304 | }
305 |
306 | private void unlockFocus() {
307 | try {
308 | // AFのロックを解除する(トリガーをキャンセルする)
309 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
310 | CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
311 | mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
312 | CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
313 | // AFトリガーのキャンセルを実行する
314 | mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
315 | mInterface.getBackgroundHandler());
316 | // プレビューを継続するためsetRepeatingRequestメソッドを実行する
317 | mState = STATE_PREVIEW;
318 | mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
319 | mInterface.getBackgroundHandler());
320 | } catch (CameraAccessException e) {
321 | e.printStackTrace();
322 | }
323 | }
324 | }
325 |
--------------------------------------------------------------------------------