diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java index 469ff557..6aa2c8d3 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Camera2Engine.java @@ -167,9 +167,10 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv @SuppressWarnings("UnusedReturnValue") @NonNull private CaptureRequest.Builder createRepeatingRequestBuilder(int template) throws CameraAccessException { + CaptureRequest.Builder oldBuilder = mRepeatingRequestBuilder; mRepeatingRequestBuilder = mCamera.createCaptureRequest(template); mRepeatingRequestBuilder.setTag(template); - applyAllParameters(mRepeatingRequestBuilder); + applyAllParameters(mRepeatingRequestBuilder, oldBuilder); return mRepeatingRequestBuilder; } @@ -653,7 +654,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv LOG.i("onTakePicture:", "doMetering is false. Performing."); try { CaptureRequest.Builder builder = mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); - applyAllParameters(builder); + applyAllParameters(builder, mRepeatingRequestBuilder); mPictureRecorder = new Full2PictureRecorder(stub, this, mSession, mRepeatingRequestCallback, @@ -797,7 +798,9 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv //region Parameters - private void applyAllParameters(@NonNull CaptureRequest.Builder builder) { + private void applyAllParameters(@NonNull CaptureRequest.Builder builder, + @Nullable CaptureRequest.Builder oldBuilder) { + LOG.i("applyAllParameters:", "called for tag", builder.build().getTag()); builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); applyDefaultFocus(builder); applyFlash(builder, Flash.OFF); @@ -806,6 +809,18 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv applyHdr(builder, Hdr.OFF); applyZoom(builder, 0F); applyExposureCorrection(builder, 0F); + + if (oldBuilder != null) { + // We might be in a metering operation, or the old builder might have some special + // metering parameters. Copy these special keys over to the new builder. + // These are the keys changed by MeteringParameters, or by us in applyFocusForMetering. + builder.set(CaptureRequest.CONTROL_AF_REGIONS, oldBuilder.get(CaptureRequest.CONTROL_AF_REGIONS)); + builder.set(CaptureRequest.CONTROL_AE_REGIONS, oldBuilder.get(CaptureRequest.CONTROL_AE_REGIONS)); + builder.set(CaptureRequest.CONTROL_AWB_REGIONS, oldBuilder.get(CaptureRequest.CONTROL_AWB_REGIONS)); + builder.set(CaptureRequest.CONTROL_AE_LOCK, oldBuilder.get(CaptureRequest.CONTROL_AE_LOCK)); + builder.set(CaptureRequest.CONTROL_AWB_LOCK, oldBuilder.get(CaptureRequest.CONTROL_AWB_LOCK)); + builder.set(CaptureRequest.CONTROL_AF_MODE, oldBuilder.get(CaptureRequest.CONTROL_AF_MODE)); + } } private void applyDefaultFocus(@NonNull CaptureRequest.Builder builder) { @@ -1184,6 +1199,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv // Reset the old meter if present. if (mMeter != null) { mMeter.resetMetering(); + mMeter = null; } // The meter will check the current configuration to see if AF/AE/AWB should run. @@ -1197,7 +1213,6 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv // Create the meter and start. mMeteringGesture = gesture; mMeter = new Meter(Camera2Engine.this, - mRepeatingRequestBuilder, mCameraCharacteristics, Camera2Engine.this); mMeter.startMetering(mLastRepeatingResult, point); @@ -1214,10 +1229,10 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv @Override public void onMeteringStarted(@Nullable PointF point) { LOG.w("onMeteringStarted - point:", point, "gesture:", mMeteringGesture); + applyRepeatingRequestBuilder(); if (point != null) { mCallback.dispatchOnFocusStart(mMeteringGesture, point); } - applyRepeatingRequestBuilder(); } /** @@ -1229,6 +1244,7 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv @Override public void onMeteringEnd(@Nullable PointF point, boolean success) { LOG.w("onMeteringEnd - point:", point, "gesture:", mMeteringGesture, "success:", success); + applyRepeatingRequestBuilder(); if (point != null) { mCallback.dispatchOnFocusEnd(mMeteringGesture, success, point); } else { @@ -1257,5 +1273,16 @@ public class Camera2Engine extends CameraEngine implements ImageReader.OnImageAv } } + /** + * Called by {@link Meter} to get the current capture request + * builder so it can apply changes on it. + * @return our builder + */ + @NonNull + @Override + public CaptureRequest.Builder getMeteringBuilder() { + return mRepeatingRequestBuilder; + } + //endregion } \ No newline at end of file diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Meter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Meter.java index bd43fefb..5fd78c8b 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Meter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/Meter.java @@ -70,6 +70,16 @@ public class Meter { * */ void onMeteringReset(@Nullable PointF point); + + /** + * Returns the currently used builder. This can change while a metering + * operation happens, so the meter will never cache this value. + * It is the engine responsibility to copy over values to the new builder + * when it changes. + * @return a builder + */ + @NonNull + CaptureRequest.Builder getMeteringBuilder(); } private static final String TAG = Meter.class.getSimpleName(); @@ -77,7 +87,6 @@ public class Meter { private static final int FORCED_END_DELAY = 2500; private final CameraEngine mEngine; - private final CaptureRequest.Builder mBuilder; private final CameraCharacteristics mCharacteristics; private final Callback mCallback; private PointF mPoint; @@ -91,17 +100,14 @@ public class Meter { /** * Creates a new meter. * @param engine the engine - * @param builder a capture builder * @param characteristics the camera characteristics * @param callback the callback */ @SuppressWarnings("WeakerAccess") public Meter(@NonNull CameraEngine engine, - @NonNull CaptureRequest.Builder builder, @NonNull CameraCharacteristics characteristics, @NonNull Callback callback) { mEngine = engine; - mBuilder = builder; mCharacteristics = characteristics; mCallback = callback; } @@ -158,9 +164,9 @@ public class Meter { // 7. And finally dispatch everything boolean skipIfPossible = mPoint == null; - mAutoFocus.startMetering(mCharacteristics, mBuilder, areas, lastResult, skipIfPossible); - mAutoWhiteBalance.startMetering(mCharacteristics, mBuilder, areas, lastResult, skipIfPossible); - mAutoExposure.startMetering(mCharacteristics, mBuilder, areas, lastResult, skipIfPossible); + mAutoFocus.startMetering(mCharacteristics, mCallback.getMeteringBuilder(), areas, lastResult, skipIfPossible); + mAutoWhiteBalance.startMetering(mCharacteristics, mCallback.getMeteringBuilder(), areas, lastResult, skipIfPossible); + mAutoExposure.startMetering(mCharacteristics, mCallback.getMeteringBuilder(), areas, lastResult, skipIfPossible); // Dispatch to callback mCallback.onMeteringStarted(mPoint); @@ -239,7 +245,7 @@ public class Meter { // The input point and size refer to the stream rect. // The stream rect is part of the 'crop region', as described below. // https://source.android.com/devices/camera/camera3_crop_reprocess.html - Rect cropRect = mBuilder.get(CaptureRequest.SCALER_CROP_REGION); + Rect cropRect = mCallback.getMeteringBuilder().get(CaptureRequest.SCALER_CROP_REGION); // For now, we don't care about x and y position. Rect should be non-null, but let's be safe. int cropRectWidth = cropRect == null ? referenceSize.getWidth() : cropRect.width(); int cropRectHeight = cropRect == null ? referenceSize.getHeight() : cropRect.height(); @@ -254,7 +260,7 @@ public class Meter { private Size applyActiveArrayCoordinates(@NonNull Size referenceSize, @NonNull PointF referencePoint) { // The input point and size refer to the scaler crop region. // We can query for the crop region position inside the active array, so this is easy. - Rect cropRect = mBuilder.get(CaptureRequest.SCALER_CROP_REGION); + Rect cropRect = mCallback.getMeteringBuilder().get(CaptureRequest.SCALER_CROP_REGION); referencePoint.x += cropRect == null ? 0 : cropRect.left; referencePoint.y += cropRect == null ? 0 : cropRect.top; // Finally, get the active rect width and height from characteristics. @@ -320,9 +326,9 @@ public class Meter { if (!mIsMetering) return; // We're not interested in results anymore if (!(result instanceof TotalCaptureResult)) return; // Let's ignore these, contents are missing/wrong - if (!mAutoFocus.isMetered()) mAutoFocus.onCapture(result); - if (!mAutoExposure.isMetered()) mAutoExposure.onCapture(result); - if (!mAutoWhiteBalance.isMetered()) mAutoWhiteBalance.onCapture(result); + if (!mAutoFocus.isMetered()) mAutoFocus.onCapture(mCallback.getMeteringBuilder(), result); + if (!mAutoExposure.isMetered()) mAutoExposure.onCapture(mCallback.getMeteringBuilder(), result); + if (!mAutoWhiteBalance.isMetered()) mAutoWhiteBalance.onCapture(mCallback.getMeteringBuilder(), result); if (mAutoFocus.isMetered() && mAutoExposure.isMetered() && mAutoWhiteBalance.isMetered()) { LOG.i("onCapture:", "all MeteringParameters have converged. Dispatching onMeteringEnd"); boolean success = mAutoFocus.isSuccessful() @@ -359,9 +365,9 @@ public class Meter { if (wholeRect == null) wholeRect = new Rect(); whole = new MeteringRectangle(wholeRect, MeteringRectangle.METERING_WEIGHT_DONT_CARE); } - mAutoFocus.resetMetering(mCharacteristics, mBuilder, whole); - mAutoWhiteBalance.resetMetering(mCharacteristics, mBuilder, whole); - mAutoExposure.resetMetering(mCharacteristics, mBuilder, whole); + mAutoFocus.resetMetering(mCharacteristics, mCallback.getMeteringBuilder(), whole); + mAutoWhiteBalance.resetMetering(mCharacteristics, mCallback.getMeteringBuilder(), whole); + mAutoExposure.resetMetering(mCharacteristics, mCallback.getMeteringBuilder(), whole); mCallback.onMeteringReset(mPoint); } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoExposure.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoExposure.java index ed237b42..690c7ec3 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoExposure.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoExposure.java @@ -57,6 +57,9 @@ public class AutoExposure extends MeteringParameter { isStarted = false; if (supportsProcessing) { + // Remove any lock. This would make processing be stuck into the process method. + builder.set(CaptureRequest.CONTROL_AE_LOCK, false); + // Launch the precapture trigger. builder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START); } @@ -96,6 +99,11 @@ public class AutoExposure extends MeteringParameter { } } + @Override + protected void onMetered(@NonNull CaptureRequest.Builder builder) { + builder.set(CaptureRequest.CONTROL_AE_LOCK, true); + } + @Override protected void onResetMetering(@NonNull CameraCharacteristics characteristics, @NonNull CaptureRequest.Builder builder, @@ -107,6 +115,7 @@ public class AutoExposure extends MeteringParameter { builder.set(CaptureRequest.CONTROL_AE_REGIONS, new MeteringRectangle[]{area}); } if (supportsProcessing) { + builder.set(CaptureRequest.CONTROL_AE_LOCK, false); // Cleanup any precapture sequence. if (Build.VERSION.SDK_INT >= 23) { builder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER, diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoFocus.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoFocus.java index 6f5bc0ec..c3485ce1 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoFocus.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoFocus.java @@ -37,7 +37,9 @@ public class AutoFocus extends MeteringParameter { @Override protected boolean checkShouldSkip(@NonNull CaptureResult lastResult) { Integer afState = lastResult.get(CaptureResult.CONTROL_AF_STATE); - boolean result = afState != null && afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED; + boolean result = afState != null && + (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED || + afState == CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED); LOG.i("checkShouldSkip:", result); return result; } @@ -83,6 +85,11 @@ public class AutoFocus extends MeteringParameter { } } + @Override + protected void onMetered(@NonNull CaptureRequest.Builder builder) { + // Do nothing. + } + @Override protected void onResetMetering(@NonNull CameraCharacteristics characteristics, @NonNull CaptureRequest.Builder builder, diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoWhiteBalance.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoWhiteBalance.java index 28f7fab4..6b4726d6 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoWhiteBalance.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/AutoWhiteBalance.java @@ -46,8 +46,7 @@ public class AutoWhiteBalance extends MeteringParameter { @NonNull List areas, boolean supportsProcessing) { if (supportsProcessing) { - // Remove any lock. We're not setting any, but just in case. - // This would make processing be stuck into the process method. + // Remove any lock. This would make processing be stuck into the process method. builder.set(CaptureRequest.CONTROL_AWB_LOCK, false); } @@ -80,11 +79,19 @@ public class AutoWhiteBalance extends MeteringParameter { } } + @Override + protected void onMetered(@NonNull CaptureRequest.Builder builder) { + builder.set(CaptureRequest.CONTROL_AWB_LOCK, true); + } + @Override protected void onResetMetering(@NonNull CameraCharacteristics characteristics, @NonNull CaptureRequest.Builder builder, @Nullable MeteringRectangle area, boolean supportsProcessing) { + if (supportsProcessing) { + builder.set(CaptureRequest.CONTROL_AWB_LOCK, false); + } int maxRegions = readCharacteristic(characteristics, CameraCharacteristics.CONTROL_MAX_REGIONS_AWB, 0); if (area != null && maxRegions > 0) { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/MeteringParameter.java b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/MeteringParameter.java index ae774c8b..e2c9cc76 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/MeteringParameter.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/engine/metering/MeteringParameter.java @@ -67,13 +67,17 @@ public abstract class MeteringParameter { @NonNull List areas, boolean supportsProcessing); - public final void onCapture(@NonNull CaptureResult result) { + public final void onCapture(@NonNull CaptureRequest.Builder builder, + @NonNull CaptureResult result) { if (isMetered()) return; processCapture(result); + if (isMetered()) onMetered(builder); } protected abstract void processCapture(@NonNull CaptureResult result); + protected abstract void onMetered(@NonNull CaptureRequest.Builder builder); + public final void resetMetering(@NonNull CameraCharacteristics characteristics, @NonNull CaptureRequest.Builder builder, @Nullable MeteringRectangle area) { diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full2PictureRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full2PictureRecorder.java index f6c8b18e..ce51b09d 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full2PictureRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Full2PictureRecorder.java @@ -68,6 +68,7 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader mState = STATE_WAITING_CAPTURE; mPictureBuilder.addTarget(mPictureReader.getSurface()); mPictureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mResult.rotation); + mPictureBuilder.setTag(CameraDevice.TEMPLATE_STILL_CAPTURE); if (mStopPreviewBeforeCapture) { // These two are present in official samples and are probably meant to speed things up? // But from my tests, they actually make everything slower. So this is disabled by default @@ -87,7 +88,7 @@ public class Full2PictureRecorder extends PictureRecorder implements ImageReader public void onCaptureStarted(@NonNull CaptureRequest request) { if (mState == STATE_WAITING_CAPTURE) { - if (request.getTag() == mPictureBuilder.build().getTag()) { + if (request.getTag() == (Integer) CameraDevice.TEMPLATE_STILL_CAPTURE) { dispatchOnShutter(false); } } diff --git a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Snapshot2PictureRecorder.java b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Snapshot2PictureRecorder.java index 2de83e71..d67ad0b3 100644 --- a/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Snapshot2PictureRecorder.java +++ b/cameraview/src/main/java/com/otaliastudios/cameraview/picture/Snapshot2PictureRecorder.java @@ -24,7 +24,7 @@ import com.otaliastudios.cameraview.preview.RendererFrameCallback; import com.otaliastudios.cameraview.size.AspectRatio; @RequiresApi(Build.VERSION_CODES.LOLLIPOP) -public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder implements RendererFrameCallback { +public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder { private final static String TAG = Snapshot2PictureRecorder.class.getSimpleName(); private final static CameraLogger LOG = CameraLogger.create(TAG); @@ -64,6 +64,27 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder implemen mBuilder = builder; } + private final RendererFrameCallback mRendererCallback = new RendererFrameCallback() { + @Override + public void onRendererTextureCreated(int textureId) { + Snapshot2PictureRecorder.super.onRendererTextureCreated(textureId); + } + + @Override + public void onRendererFilterChanged(@NonNull Filter filter) { + Snapshot2PictureRecorder.super.onRendererFilterChanged(filter); + } + + @Override + public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, float scaleX, float scaleY) { + mLastFrameSurfaceTexture = surfaceTexture; + mLastFrameScaleX = scaleX; + mLastFrameScaleY = scaleY; + mLastFrameScaleEGLContext = EGL14.eglGetCurrentContext(); + maybeTakeFrame(); + } + }; + @Override public void take() { if (!mEngine.getPictureSnapshotMetering()) { @@ -72,7 +93,7 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder implemen } LOG.i("take:", "Engine does metering, adding our CONTROL_CAPTURE_INTENT."); - mPreview.addRendererFrameCallback(this); + mPreview.addRendererFrameCallback(mRendererCallback); mState = STATE_WAITING_CAPTURE; try { mOldCaptureIntent = mBuilder.get(CaptureRequest.CONTROL_CAPTURE_INTENT); @@ -86,25 +107,6 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder implemen } } - @Override - public void onRendererTextureCreated(int textureId) { - super.onRendererTextureCreated(textureId); - } - - @Override - public void onRendererFilterChanged(@NonNull Filter filter) { - super.onRendererFilterChanged(filter); - } - - @Override - public void onRendererFrame(@NonNull SurfaceTexture surfaceTexture, float scaleX, float scaleY) { - mLastFrameSurfaceTexture = surfaceTexture; - mLastFrameScaleX = scaleX; - mLastFrameScaleY = scaleY; - mLastFrameScaleEGLContext = EGL14.eglGetCurrentContext(); - maybeTakeFrame(); - } - public void onCaptureCompleted(@NonNull TotalCaptureResult result) { LOG.i("onCaptureCompleted:", "aeState:", result.get(CaptureResult.CONTROL_AE_STATE), @@ -158,7 +160,7 @@ public class Snapshot2PictureRecorder extends SnapshotGlPictureRecorder implemen mSession.setRepeatingRequest(mBuilder.build(), mCallback, null); } catch (CameraAccessException ignore) {} } - mPreview.removeRendererFrameCallback(this); + mPreview.removeRendererFrameCallback(mRendererCallback); mState = STATE_IDLE; super.dispatchResult(); } diff --git a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java index baa4a94b..50508a71 100644 --- a/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java +++ b/demo/src/main/java/com/otaliastudios/cameraview/demo/CameraActivity.java @@ -7,11 +7,14 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Color; import android.graphics.ImageFormat; +import android.graphics.PointF; import android.graphics.Rect; import android.graphics.YuvImage; import android.os.Bundle; import androidx.annotation.NonNull; import com.google.android.material.bottomsheet.BottomSheetBehavior; + +import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import android.view.View; @@ -237,6 +240,18 @@ public class CameraActivity extends AppCompatActivity implements View.OnClickLis message("Video taken. Processing...", false); LOG.w("onVideoRecordingEnd!"); } + + @Override + public void onExposureCorrectionChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) { + super.onExposureCorrectionChanged(newValue, bounds, fingers); + message("Exposure correction:" + newValue, false); + } + + @Override + public void onZoomChanged(float newValue, @NonNull float[] bounds, @Nullable PointF[] fingers) { + super.onZoomChanged(newValue, bounds, fingers); + message("Zoom:" + newValue, false); + } } @Override diff --git a/demo/src/main/res/layout/activity_camera.xml b/demo/src/main/res/layout/activity_camera.xml index 72fef775..2cc1d8a5 100644 --- a/demo/src/main/res/layout/activity_camera.xml +++ b/demo/src/main/res/layout/activity_camera.xml @@ -20,7 +20,7 @@ app:cameraPreview="glSurface" app:cameraPlaySounds="true" app:cameraGrid="off" - app:cameraFlash="on" + app:cameraFlash="auto" app:cameraAudio="on" app:cameraFacing="back" app:cameraGestureTap="autoFocus" @@ -29,7 +29,6 @@ app:cameraGestureScrollHorizontal="filterControl1" app:cameraGestureScrollVertical="exposureCorrection" app:cameraMode="picture" - app:cameraPictureSnapshotMetering="true" app:cameraAutoFocusMarker="@string/cameraview_default_autofocus_marker">