android camera2 api bug fixes
Different types of hardware can stress an application in different ways like the nexus 5x so I took the opportunity to do some android camera2 api bug fixes
Get Code
The code is now on github you can get it from here
https://github.com/mobapptuts/recyclerview_image_gallery.git Tag camera2-write-swap-fix
or else run this command
git clone https://github.com/mobapptuts/recyclerview_image_gallery.git –branch camera2-write-swap-fix
Bug fixes
Create the image file after the camera has gained focus lock
There are a number of places this can be done, I’m going to put the image creation code in the camera capture request callback
CameraCaptureSession.CaptureCallback captureCallback = new CameraCaptureSession.CaptureCallback() { @Override public void onCaptureStarted(CameraCaptureSession session, CaptureRequest request, long timestamp, long frameNumber) { super.onCaptureStarted(session, request, timestamp, frameNumber); try { if(mRequestingAppUri != null) { mImageFile = new File(mRequestingAppUri.getPath()); } else { mImageFile = createImageFile(); } } catch (IOException e) { e.printStackTrace(); } }
Add the picture completed state
If we don’t add this state the camera will keep saving images to the same file
private static final int STATE__PICTURE_CAPTURED = 2;
Swap the recyclerview image adapter after the image has been saved
Create a handler for the UI thread which will facilitate communication with the UI thread once the image has been written to the file.
private final Handler mUiHandler = new Handler(Looper.getMainLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); swapImageAdapter(); } };
Pass the UI handler to the ImageSaver Constructor
private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { mBackgroundHandler.post(new ImageSaver(mActivity, reader.acquireNextImage(), mUiHandler)); } };
Call the UI handler once the image has been saved from the ImageSaver runnable
private static class ImageSaver implements Runnable { private final Image mImage; private final Activity mActivity; private final Handler mHandler; private ImageSaver(Activity activity, Image image, Handler handler) { mActivity = activity; mImage = image; mHandler = handler; } @Override public void run() { ByteBuffer byteBuffer = mImage.getPlanes()[0].getBuffer(); byte[] bytes = new byte[byteBuffer.remaining()]; byteBuffer.get(bytes); FileOutputStream fileOutputStream = null; try { fileOutputStream = new FileOutputStream(mImageFile); fileOutputStream.write(bytes); } catch (IOException e) { e.printStackTrace(); } finally { mImage.close(); if(fileOutputStream != null) { try { fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } if(mRequestingAppUri != null) { mRequestingAppUri = null; mActivity.setResult(RESULT_OK); mActivity.finish(); } Message message = mHandler.obtainMessage(); message.sendToTarget(); } } }
Cancel camera capture session repeating requests when the still capture session is ready to be captured
private void captureStillImage() { mCameraCaptureSession.stopRepeating(); mCameraCaptureSession.capture( captureStillBuilder.build(), captureCallback, null );
Once the focus is unlocked re-enable the camera capture session repeating request
private void unLockFocus() { try { mState = STATE_PREVIEW; mPreviewCaptureRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_CANCEL); mCameraCaptureSession.setRepeatingRequest(mPreviewCaptureRequestBuilder.build(), mSessionCaptureCallback, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } }