From ecbee10d740381d11df172de027ef76a6136ace3 Mon Sep 17 00:00:00 2001 From: Byunghun Jeon Date: Wed, 9 Mar 2016 17:54:54 -0800 Subject: SnapdragonCamera: Camera2 add touch to focus Add touch to focus to Camera2 CRs-Fixed: 989750 Change-Id: I5c7c85dcc12eefb11e5f1b5e6a823a327b2647e4 --- src/com/android/camera/CaptureModule.java | 128 ++++++++++++++++++++++++- src/com/android/camera/CaptureUI.java | 20 +++- src/com/android/camera/FocusStateListener.java | 66 +++++++++++++ src/com/android/camera/util/CameraUtil.java | 25 ++++- 4 files changed, 232 insertions(+), 7 deletions(-) create mode 100644 src/com/android/camera/FocusStateListener.java diff --git a/src/com/android/camera/CaptureModule.java b/src/com/android/camera/CaptureModule.java index 7362a6582..41a26c59d 100644 --- a/src/com/android/camera/CaptureModule.java +++ b/src/com/android/camera/CaptureModule.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.Intent; import android.content.res.Configuration; import android.graphics.ImageFormat; +import android.graphics.Point; import android.graphics.Rect; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCaptureSession; @@ -36,6 +37,7 @@ import android.hardware.camera2.CameraMetadata; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; import android.hardware.camera2.TotalCaptureResult; +import android.hardware.camera2.params.MeteringRectangle; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.CameraProfile; import android.media.Image; @@ -118,6 +120,10 @@ public class CaptureModule implements CameraModule, PhotoController, ORIENTATIONS.append(Surface.ROTATION_270, 180); } + MeteringRectangle[][] mAFRegions = new MeteringRectangle[MAX_NUM_CAM][]; + private int mLastResultAFState = -1; + private Rect[] mCropRegion = new Rect[MAX_NUM_CAM]; + private boolean mAutoFocusSupported; // The degrees of the device rotated clockwise from its natural orientation. private int mOrientation = OrientationEventListener.ORIENTATION_UNKNOWN; private int mJpegQuality; @@ -137,7 +143,7 @@ public class CaptureModule implements CameraModule, PhotoController, private CameraCharacteristics[] mCharacteristics = new CameraCharacteristics[MAX_NUM_CAM]; private List mCharacteristicsIndex; private float mZoomValue = 1f; - + private FocusStateListener mFocusStateListener; private LocationManager mLocationManager; /** * A {@link CameraCaptureSession } for camera preview. @@ -273,6 +279,8 @@ public class CaptureModule implements CameraModule, PhotoController, public void onCaptureProgressed(CameraCaptureSession session, CaptureRequest request, CaptureResult partialResult) { + int id = (int) partialResult.getRequest().getTag(); + if (id == getMainCameraId()) updateFocusStateChange(partialResult); process(partialResult); } @@ -280,6 +288,8 @@ public class CaptureModule implements CameraModule, PhotoController, public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request, TotalCaptureResult result) { + int id = (int) result.getRequest().getTag(); + if (id == getMainCameraId()) updateFocusStateChange(result); process(result); } }; @@ -562,6 +572,7 @@ public class CaptureModule implements CameraModule, PhotoController, mContentResolver = mActivity.getContentResolver(); mUI = new CaptureUI(activity, this, parent); mUI.initializeControlByIntent(); + mFocusStateListener = new FocusStateListener(mUI); mLocationManager = new LocationManager(mActivity, mUI); Storage.setSaveSDCard( mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1")); @@ -609,6 +620,26 @@ public class CaptureModule implements CameraModule, PhotoController, } } + private void autoFocusTrigger(int id) { + Log.d(TAG, "autoFocusTrigger " + id); + try { + CaptureRequest.Builder builder = mCameraDevice[id].createCaptureRequest(CameraDevice + .TEMPLATE_PREVIEW); + builder.setTag(id); + builder.addTarget(getPreviewSurface(id)); + + builder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO); + builder.set(CaptureRequest.CONTROL_AF_MODE, CameraMetadata.CONTROL_AF_MODE_AUTO); + builder.set(CaptureRequest.CONTROL_AF_TRIGGER, CaptureRequest.CONTROL_AF_TRIGGER_START); + applyWhiteBalance(builder); + applyZoom(builder, id); + applyAFRegions(builder, id); + mCaptureSession[id].capture(builder.build(), mCaptureCallback, mCameraHandler); + } catch (CameraAccessException e) { + e.printStackTrace(); + } + } + /** * Capture a still picture. This method should be called when we get a response in * {@link #mCaptureCallback} from both {@link #lockFocus()}. @@ -719,6 +750,8 @@ public class CaptureModule implements CameraModule, PhotoController, mOnImageAvailableListener, mImageAvailableHandler); mCameraId[i] = cameraId; } + mAutoFocusSupported = CameraUtil.isAutoFocusSupported(mCharacteristics, + mCharacteristicsIndex); } catch (CameraAccessException e) { e.printStackTrace(); } catch (NullPointerException e) { @@ -1009,7 +1042,42 @@ public class CaptureModule implements CameraModule, PhotoController, @Override public void onSingleTapUp(View view, int x, int y) { + if (mPaused || mCameraDevice == null || !mFirstTimeInitialized || !mAutoFocusSupported || + !isStatePreview()) { + return; + } + mUI.setFocusPosition(x, y); + mUI.onFocusStarted(); + switch (MODE) { + case DUAL_MODE: + triggerFocusAtPoint(x, y, BAYER_ID); + triggerFocusAtPoint(x, y, MONO_ID); + break; + case BAYER_MODE: + triggerFocusAtPoint(x, y, BAYER_ID); + break; + case MONO_MODE: + triggerFocusAtPoint(x, y, MONO_ID); + break; + } + } + + private int getMainCameraId() { + switch (MODE) { + case DUAL_MODE: + case BAYER_MODE: + return BAYER_ID; + case MONO_MODE: + return MONO_ID; + } + return 0; + } + private boolean isStatePreview() { + for (int i = 0; i < mState.length; i++) { + if (mState[i] != STATE_PREVIEW) return false; + } + return true; } @Override @@ -1185,6 +1253,7 @@ public class CaptureModule implements CameraModule, PhotoController, } public Rect cropRegionForZoom(int id) { + Log.d(TAG, "cropRegionForZoom " + id); Rect activeRegion = mCharacteristics[id].get(CameraCharacteristics .SENSOR_INFO_ACTIVE_ARRAY_SIZE); Rect cropRegion = new Rect(); @@ -1194,7 +1263,8 @@ public class CaptureModule implements CameraModule, PhotoController, int xDelta = (int) (activeRegion.width() / (2 * mZoomValue)); int yDelta = (int) (activeRegion.height() / (2 * mZoomValue)); cropRegion.set(xCenter - xDelta, yCenter - yDelta, xCenter + xDelta, yCenter + yDelta); - return cropRegion; + mCropRegion[id] = cropRegion; + return mCropRegion[id]; } private void applyZoom(CaptureRequest.Builder request, int id) { @@ -1255,6 +1325,10 @@ public class CaptureModule implements CameraModule, PhotoController, request.set(CaptureRequest.JPEG_QUALITY, (byte) mJpegQuality); } + private void applyAFRegions(CaptureRequest.Builder request, int id) { + request.set(CaptureRequest.CONTROL_AF_REGIONS, mAFRegions[id]); + } + private void applyWhiteBalance(CaptureRequest.Builder request) { String value = readSetting(CameraSettings.KEY_WHITE_BALANCE); switch (value) { @@ -1320,6 +1394,56 @@ public class CaptureModule implements CameraModule, PhotoController, mUI.enableShutter(!full); } + public void triggerFocusAtPoint(float x, float y, int id) { + Point p; + if (id == getMainCameraId()) { + p = mUI.getSurfaceViewSize(); + } else { + p = mUI.getSurfaceView2Size(); + } + int width = p.x; + int height = p.y; + x = x / width; + y = y / height; + mAFRegions[id] = afRectangle(x, y, mCropRegion[id]); + autoFocusTrigger(id); + } + + private MeteringRectangle[] afRectangle(float x, float y, Rect cropRegion) { + int side = Math.max(cropRegion.width(), cropRegion.height()) / 8; + int xCenter = (int) (cropRegion.left + x * cropRegion.width()); + int yCenter = (int) (cropRegion.top + y * cropRegion.height()); + Rect meteringRegion = new Rect(xCenter - side / 2, yCenter - side / 2, xCenter + + side / 2, yCenter + side / 2); + + meteringRegion.left = CameraUtil.clamp(meteringRegion.left, cropRegion.left, cropRegion + .right); + meteringRegion.top = CameraUtil.clamp(meteringRegion.top, cropRegion.top, cropRegion + .bottom); + meteringRegion.right = CameraUtil.clamp(meteringRegion.right, cropRegion.left, cropRegion + .right); + meteringRegion.bottom = CameraUtil.clamp(meteringRegion.bottom, cropRegion.top, + cropRegion.bottom); + MeteringRectangle[] meteringRectangle = new MeteringRectangle[1]; + meteringRectangle[0] = new MeteringRectangle(meteringRegion, 1); + return meteringRectangle; + } + + private void updateFocusStateChange(CaptureResult result) { + final int resultAFState = result.get(CaptureResult.CONTROL_AF_STATE); + + // Report state change when AF state has changed. + if (resultAFState != mLastResultAFState && mFocusStateListener != null) { + mActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mFocusStateListener.onFocusStatusUpdate(resultAFState); + } + }); + } + mLastResultAFState = resultAFState; + } + /** * Compares two {@code Size}s based on their areas. */ diff --git a/src/com/android/camera/CaptureUI.java b/src/com/android/camera/CaptureUI.java index 01b66fb70..a6accae7b 100644 --- a/src/com/android/camera/CaptureUI.java +++ b/src/com/android/camera/CaptureUI.java @@ -281,6 +281,12 @@ public class CaptureUI implements PieListener, public void onCameraOpened(CameraCharacteristics[] characteristics, List characteristicsIndex, PreferenceGroup prefGroup, OnPreferenceChangedListener listener) { + if (mPieRenderer == null) { + mPieRenderer = new PieRenderer(mActivity); + mPieRenderer.setPieListener(this); + mRenderOverlay.addRenderer(mPieRenderer); + } + if (mMenu == null) { mMenu = new CaptureMenu(mActivity, this); mMenu.setListener(listener); @@ -686,7 +692,7 @@ public class CaptureUI implements PieListener, // focus UI implementation private FocusIndicator getFocusIndicator() { - return null; + return mPieRenderer; } @Override @@ -780,6 +786,18 @@ public class CaptureUI implements PieListener, } } + public Point getSurfaceViewSize() { + Point point = new Point(); + if (mSurfaceView != null) point.set(mSurfaceView.getWidth(), mSurfaceView.getHeight()); + return point; + } + + public Point getSurfaceView2Size() { + Point point = new Point(); + if (mSurfaceView2 != null) point.set(mSurfaceView2.getWidth(), mSurfaceView2.getHeight()); + return point; + } + public int getOrientation() { return mOrientation; } diff --git a/src/com/android/camera/FocusStateListener.java b/src/com/android/camera/FocusStateListener.java new file mode 100644 index 000000000..42edd5c34 --- /dev/null +++ b/src/com/android/camera/FocusStateListener.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.android.camera; + +import android.hardware.camera2.CaptureResult; + +public class FocusStateListener { + private CaptureUI mUI; + + public FocusStateListener(CaptureUI ui) { + mUI = ui; + } + + public void onFocusStatusUpdate(int focusState) { + switch (focusState) { + case CaptureResult.CONTROL_AF_STATE_ACTIVE_SCAN: + mUI.onFocusStarted(); + break; + case CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED: + mUI.onFocusSucceeded(true); + break; + case CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED: + mUI.onFocusFailed(true); + break; + case CaptureResult.CONTROL_AF_STATE_PASSIVE_FOCUSED: + mUI.onFocusSucceeded(true); + break; + case CaptureResult.CONTROL_AF_STATE_PASSIVE_SCAN: + mUI.onFocusStarted(); + break; + case CaptureResult.CONTROL_AF_STATE_PASSIVE_UNFOCUSED: + mUI.onFocusFailed(true); + break; + case CaptureResult.CONTROL_AF_STATE_INACTIVE: + mUI.clearFocus(); + break; + } + } +} diff --git a/src/com/android/camera/util/CameraUtil.java b/src/com/android/camera/util/CameraUtil.java index be66091e2..b1deca6e0 100644 --- a/src/com/android/camera/util/CameraUtil.java +++ b/src/com/android/camera/util/CameraUtil.java @@ -1171,13 +1171,30 @@ public class CameraUtil { public static boolean isZoomSupported(CameraCharacteristics[] characteristics, List characteristicsIndex) { - boolean supported = true; + for (int i = 0; i < characteristicsIndex.size(); i++) { + if (!isZoomSupported(characteristics[characteristicsIndex.get(i)])) + return false; + } + return true; + } + public static boolean isZoomSupported(CameraCharacteristics characteristic) { + return characteristic.get(CameraCharacteristics + .SCALER_AVAILABLE_MAX_DIGITAL_ZOOM) > 1f; + } + + public static boolean isAutoFocusSupported(CameraCharacteristics[] characteristics, List + characteristicsIndex) { for (int i = 0; i < characteristicsIndex.size(); i++) { - if (characteristics[characteristicsIndex.get(i)].get(CameraCharacteristics - .SCALER_AVAILABLE_MAX_DIGITAL_ZOOM) <= 1f) + if (!isAutoFocusSupported(characteristics[characteristicsIndex.get(i)])) return false; } - return supported; + return true; + } + + public static boolean isAutoFocusSupported(CameraCharacteristics characteristic) { + Integer maxAfRegions = characteristic.get( + CameraCharacteristics.CONTROL_MAX_REGIONS_AF); + return maxAfRegions != null && maxAfRegions > 0; } } -- cgit v1.2.3