我们在autoFocus功能分析一文中分析了如何启动自动对焦,也在App层focus or face detection界面显示分析中阐述了界面是如何更新的,但是在二者之间有重要的一环还缺失,就是自动对焦成功的是如何被应用捕捉并相应的呢?本文就对此简单分析。
首先,在自动对焦开始的同时,应用就设定了回调监听类的实例。
@Override
public void autoFocus() {
mFocusStartTime = System.currentTimeMillis();
mCameraDevice.autoFocus(mAutoFocusCallback);
setCameraState(FOCUSING);
}
当相机对焦完成,就会触发监听类中的回调函数。
private final class AutoFocusCallback
implements android.hardware.Camera.AutoFocusCallback {
public void onAutoFocus(
boolean focused, android.hardware.Camera camera) {
if (mPausing) return;
mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
Log.v(TAG, "mAutoFocusTime = " + mAutoFocusTime + "ms");
setCameraState(IDLE);
mFocusManager.onAutoFocus(focused);
}
}
进一步调用FocusManager.java的onAutoFocus函数。
public void onAutoFocus(boolean focused) {
if (mState == STATE_FOCUSING_SNAP_ON_FINISH) {
// Take the picture no matter focus succeeds or fails. No need
// to play the AF sound if we're about to play the shutter
// sound.
if (focused) {
mState = STATE_SUCCESS;
} else {
mState = STATE_FAIL;
}
updateFocusUI();
capture();
} else if (mState == STATE_FOCUSING) {
// This happens when (1) user is half-pressing the focus key or
// (2) touch focus is triggered. Play the focus tone. Do not
// take the picture now.
if (focused) {
mState = STATE_SUCCESS;
mListener.playSound(CameraSound.FOCUS_COMPLETE);
} else {
mState = STATE_FAIL;
}
updateFocusUI();
// If this is triggered by touch focus, cancel focus after a
// while.
if (mFocusArea != null) {
mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY);
}
} else if (mState == STATE_IDLE) {
// User has released the focus key before focus completes.
// Do nothing.
}
}
在此函数中会根据是根据何种方式启动的自动对焦而拍照或显示自动对焦完成。
1. Ontouch对焦:对焦成功后会跟新界面并且保持3秒
private static final int RESET_TOUCH_FOCUS_DELAY = 3000;
private class MainHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case RESET_TOUCH_FOCUS: {
cancelAutoFocus();
mListener.startFaceDetection();
break;
}
}
}
}
2. 如果是shutterdown对焦成功后会更新界面,然后拍照,拍照完成后重置对焦。
FocusManager.java
private void capture() {
if (mListener.capture()) {
mState = STATE_IDLE;
mHandler.removeMessages(RESET_TOUCH_FOCUS);
}
}
Camera.java
@Override
public boolean capture() {
// If we are already in the middle of taking a snapshot then ignore.
if (mCameraState == SNAPSHOT_IN_PROGRESS || mCameraDevice == null) {
return false;
}
mCaptureStartTime = System.currentTimeMillis();
mPostViewPictureCallbackTime = 0;
mJpegImageData = null;
// Set rotation and gps data.
Util.setRotationParameter(mParameters, mCameraId, sOrientation);
Location loc = mLocationManager.getCurrentLocation();
Util.setGpsParameters(mParameters, loc);
mCameraDevice.setParameters(mParameters);
mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback,
mPostViewPictureCallback, new JpegPictureCallback(loc));
mFaceDetectionStarted = false;
setCameraState(SNAPSHOT_IN_PROGRESS);
return true;
}
private final class ShutterCallback
implements android.hardware.Camera.ShutterCallback {
public void onShutter() {
mShutterCallbackTime = System.currentTimeMillis();
mShutterLag = mShutterCallbackTime - mCaptureStartTime;
Log.v(TAG, "mShutterLag = " + mShutterLag + "ms");
mFocusManager.onShutter();
}
}
FocusManager.java
public void onShutter() {
resetTouchFocus();
updateFocusUI();
}
public void resetTouchFocus() {
if (!mInitialized) return;
// Put focus indicator to the center.
RelativeLayout.LayoutParams p =
(RelativeLayout.LayoutParams) mFocusIndicatorRotateLayout.getLayoutParams();
int[] rules = p.getRules();
rules[RelativeLayout.CENTER_IN_PARENT] = RelativeLayout.TRUE;
p.setMargins(0, 0, 0, 0);
mFocusArea = null;
mMeteringArea = null;
}
}