在Camera中,autofocus是個很重要的知識點,一般有移動對焦,點選聚焦和長按聚焦,這裡我們以展銳平台相機的點選聚焦為例,分析下聚焦在app層的流程。
1、聚焦觸發
點選螢幕事件的觸發
PhotoModule.java的onSingleTapUp中
public void onSingleTapUp(View view, int x, int y) {
......
//調用FocusManager的singletap
mFocusManager.onSingleTapUp(x, y);
}
FocusOverlayManager.java的onSingleTapUp中
public void onSingleTapUp(int x, int y) {
lastSingleTap.set(x,y);
//如果目前已經是定焦的,取消定焦,重新對焦
if(isAFLock) {
sendCancleMsg(false);
mListener.setAELock(false);
isAFLock = false;
}
//沒有初始化或者拍照前的聚焦的狀态,直接傳回
if (!mInitialized || mState == STATE_FOCUSING_SNAP_ON_FINISH) {
return;
}
//讓使用者可以取消掉之前未消失的觸摸聚焦
if ((mFocusArea != null) && (mState == STATE_FOCUSING ||
mState == STATE_SUCCESS || mState == STATE_FAIL)) {
cancelAutoFocus();
}
if (mPreviewRect.width() == 0 || mPreviewRect.height() == 0) {
return;
}
// Initialize variables.
if (mAutoChasingSupported && mAutoChasingEnable){
boolean isChasing = isAutoChasing();
if (isChasing) {
initializeAutoChasingRegion(0,0);
Log.d(TAG,"set chasing Region x = 0 , y = 0");
mListener.setAutoChasingParameters();
}
}
//初始化聚焦的區域
// Initialize mFocusArea.
if (mFocusAreaSupported) {
initializeFocusAreas(x, y);
mFocusRing.setFocusLocation(x, y);
}
// Initialize mMeteringArea.
if (mMeteringAreaSupported) {
initializeMeteringAreas(x, y);
}
// Log manual tap to focus.
mTouchCoordinate = new TouchCoordinate(x, y, mPreviewRect.width(), mPreviewRect.height());
mTouchTime = System.currentTimeMillis();
//停止人臉識别,因為要進行識别聚焦和測量area
mListener.stopFaceDetection();
//設定聚焦區域&測量區域
mListener.setFocusParameters();
if (mFocusAreaSupported) {
autoFocus();//開始對焦
} else { // Just show the indicator in all other cases.
// Reset the metering area in 4 seconds.
mHandler.removeMessages(RESET_TOUCH_FOCUS);
mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY_MILLIS);
}
}
接着看FocusOverlayManager這裡的autoFocus()方法
private void autoFocus(int focusingState) {
//監聽autofocus,這裡autofocus的實作是PhotoModule中
mListener.autoFocus();
//目前focus的狀态設定成正在focus
mState = focusingState;
//更新正在對焦的對焦框ui
updateFocusUI();
mHandler.removeMessages(RESET_TOUCH_FOCUS);
initializeCameraSound();
}
在PhotoMudule.java中的autoFocus()中
@Override
public void autoFocus() {
if (mCameraDevice == null) {
return;
}
mNeedCancelAutoFocus = true;
mFocusStartTime = System.currentTimeMillis();
//設定Camera的回調聚焦
mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);
//設定相機的狀态為FOCUSING
setCameraState(FOCUSING);
}
2、聚焦完成回調
接着看上層對于聚焦的回調處理,在PhotoModule中有内部類AutoFocusCallback
private final class AutoFocusCallback implements CameraAFCallback {
@Override
public void onAutoFocus(boolean focused, CameraProxy camera) {
//如果是暫停狀态,不聚焦
if (mPaused) {
return;
}
//算出目前到聚焦開始的時間差
mAutoFocusTime = System.currentTimeMillis() - mFocusStartTime;
//設定Camera狀态為IDLE
setCameraState(IDLE);
//調用FocusManager中的onAutoFocus
mFocusManager.onAutoFocus(focused, false);
}
}
接着去看聚焦完成的具體處理
在FocusManager的onAutoFocus中
public void onAutoFocus(boolean focused, boolean shutterButtonPressed) {
//正在進行聚焦,拍照動作必須再聚焦完之後
if (mState == STATE_FOCUSING_SNAP_ON_FINISH) {
// 無論聚焦成功還是失敗,都會拍照。如果要進行拍照發聲,就無需AF發聲了
if (focused) {
//聚焦成功
mState = STATE_SUCCESS;
} else {
//聚焦失敗
mState = STATE_FAIL;
}
//更新聚焦完成的ui以及各種狀态的設定
updateFocusUI();
//拍照,mState的狀态變為STATE_IDLE
capture();
//如果是聚焦中的狀态
} else if (mState == STATE_FOCUSING || mState == STATE_FOCUSING_SNAP_ON_FINISH) {
//此狀态的發生分為兩種,half-pressing按壓聚焦或者觸摸聚焦被觸發,這個時候不要發生拍照動作
if (focused) {
mState = STATE_SUCCESS;
} else {
mState = STATE_FAIL;
}
//如果是觸摸聚焦,需要延遲一下取消掉聚焦
if (mFocusArea != null) {
mFocusLocked = true;
if(!isAFLock) {
mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY_MILLIS);
}
}
//更新聚焦完成的ui
if(!isAFLock) {
updateFocusUI();
autoChase();
} else {
mFocusRing.setAELockColor(true);
}
if (shutterButtonPressed) {
// Lock AE & AWB so users can half-press shutter and recompose.
lockAeAwbIfNeeded();
}
} else if (mState == STATE_IDLE) {
// User has released the focus key before focus completes.
// Do nothing.
}
}
3、取消聚焦
在FocusManager()中的cancleAutofocus()
private void cancelAutoFocus() {
//清除聚焦區域
clearAfArea();
mMeteringArea = null;
//監聽cancelAutoFocus,在PhotoModule中實作
mListener.cancelAutoFocus();
//重置聚焦,聚焦框恢複到螢幕中間
resetTouchFocus();
//改變聚焦狀态
mState = STATE_IDLE;
mFocusLocked = false;
//移除msg
mHandler.removeMessages(RESET_TOUCH_FOCUS);
}
在PhotoModule的cancelAutoFocus()中
public void cancelAutoFocus() {
if (mCameraDevice == null) {
return;
}
//取消底層聚焦
mCameraDevice.cancelAutoFocus();
//設定相機狀态
setCameraState(IDLE);
if (mFace != null && mFace
&& isCameraIdle() && !isHdr() ) {
//開始人臉檢測
startFaceDetection();
}
setCameraParameters(UPDATE_PARAM_PREFERENCE);
}
以上就是app層聚焦的大緻流程
4、更新聚焦框ui
前面有好幾處有更新ui的操作,我們來看一下具體做了些什麼,其實就是對于聚焦框的改變與展示。
在FucusManager的updateFocusUI中:
public void updateFocusUI() {
//沒有初始化完成
if (!mInitialized) {
// Show only focus indicator or face indicator.
return;
}
//聚焦開始,mFocusRing為聚焦框,可自定義
if (mState == STATE_IDLE) {
if (mFocusArea != null) {
mFocusRing.startActiveFocus();
}
//正在聚焦
} else if (mState == STATE_FOCUSING || mState == STATE_FOCUSING_SNAP_ON_FINISH) {
if (mFocusArea == null) {
mFocusRing.centerFocusLocation();
}
mFocusRing.startActiveFocus();
} else {
//聚焦成功
if (mState == STATE_SUCCESS) {
//拍照
if (mTouchListener != null) {
mTouchListener.touchCapture();
}
//聚焦完成顯示的對焦框
mFocusRing.startActiveFocusedFocus();
//聚焦成功的聲音
if (mFocusArea != null) {
if (mAppController.isPlaySoundEnable()) {
mCameraSound.play(MediaActionSound.FOCUS_COMPLETE);
}
} else {
mFocusRing.centerFocusLocation();
}
//聚焦失敗
} else if (mState == STATE_FAIL) {
if (mTouchListener != null) {
mTouchListener.touchCapture();
}
mFocusRing.startActiveFocusedFocus();
}
}
}
5、相機狀态和聚焦狀态
聚焦過程中,相機狀态的改變和聚焦狀态的改變
相機狀态:
在PhotoModule中設定相機狀态:
protected void setCameraState(int state) {
mCameraState = state;
switch (state) {
case PREVIEW_STOPPED:
case SNAPSHOT_IN_PROGRESS:
case SWITCHING_CAMERA:
// TODO: Tell app UI to disable swipe
break;
case PhotoController.IDLE:
// TODO: Tell app UI to enable swipe
break;
}
}
聚焦狀态:
STATE_IDLE:空閑狀态
capture():空閑狀态可以執行拍照
onAutoFocus(boolean focused):使用者再聚焦完成前放掉了聚焦按鈕,是以不做任何事。
onPreviewStarted(),onPreviewStopped():狀态都變為空閑
cancelAutoFocus():取消聚焦,狀态變為空閑
updateFocusUI():如果空閑&有聚焦區域,顯示聚焦框
STATE_FOCUSING:正在對焦
onShutterUp():如果是focusmode為自動聚焦,狀态為正在聚焦,則取消掉聚焦
capture():如果是正在聚焦狀态,将狀态改為聚焦完拍照狀态
onAutoFocus(boolean focused, boolean shutterButtonPressed):判斷focused,為true變為聚焦成功狀态,為false變為聚焦失敗狀态
onSingleTapUp(int x, int y):如果正在聚焦&之前有手動聚焦了,則取消掉之前的聚焦
autoFocus():狀态變為聚焦狀态
updateFocusUI():顯示聚焦框
STATE_FOCUSING_SNAP_ON_FINISH:聚焦完拍照
onShutterUp():狀态不是聚焦完拍照,可以設定FocusParameters
onAutoFocus(boolean focused, boolean shutterButtonPressed):判斷focused,為true變為聚焦成功狀态,為false變為聚焦失敗狀态,更新聚焦框UI
onSingleTapUp(int x, int y):直接不繼續操作下去
updateFocusUI():顯示聚焦框
STATE_SUCCESS:聚焦成功
onShutterDown():如果是自動聚焦mode,并且不為聚焦成功狀态,執行聚焦
onShutterUp(): 如果是自動聚焦mode,并且為聚焦成功狀态,執行取消聚焦
capture():拍照
onSingleTapUp(int x, int y):讓使用者可以取消掉之前未消失的觸摸聚焦
updateFocusUI():聚焦框顯示成功
STATE_FAIL:聚焦失敗
onShutterDown():如果是自動聚焦mode,并且不為聚焦失敗狀态,執行聚焦
onShutterUp(): 如果是自動聚焦mode,并且為聚焦失敗狀态,執行取消聚焦
capture():拍照
onSingleTapUp(int x, int y):讓使用者可以取消掉之前未消失的觸摸聚焦
updateFocusUI():聚焦框顯示失敗
關于底層的實作,主要是聚焦指令的下發(開始聚焦和結束聚焦),以及聚焦完成的回調
//開始聚焦
mCameraDevice.autoFocus(mHandler, mAutoFocusCallback);//mCameraDevice為CameraProxy的引用,mAutoFocusCallback為聚焦完成的回調
//取消聚焦
mCameraDevice.cancelAutoFocus();
CameraProxy為CameraAgent的内部類
具體實作又在AndroidCamera2AgentImpl中,有興趣的朋友可以自行檢視源碼