手机相机的对焦处理,应用场景很多,今天可以通过应用层的相关处理代码来研究一下对焦需要走哪些流程以及容易遇到或引发什么样的问题。
1.应用层通过对一系列手势事件的监听触发聚焦功能
因为这边涉及到Android开发上对点击、长按等手势事件的处理,我这边就把较全的手势监听处理事件粗略的描述了一下,手势处理不是重点,就先跳过了。
//点击屏幕即触发该事件
@Override
public boolean onDown(MotionEvent event) {
return false;
}
//点击屏幕后松开触发
@Override
public boolean onUp(MotionEvent event) {
return false;
}
//点击屏幕并滑动了一段距离后松开时触发
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
//点击屏幕滑动时触发
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float dx, float dy) {
return false;
}
//点击屏幕没有滑动,没有长时间按压然后松开时触发
@Override
public boolean onSingleTapUp(float x, float y) {
//step1:Check whether auto focus can do
if (!checkAfEnv()) {
return false;
}
//step2:Check to restore af lock state and UI when needed.
handleAfLockRestore();
//step3:Clear any focus UI before show new touch focus UI
mFocusViewController.clearFocusUi();
if (mNeedShowFocusUi) {
mFocusViewController.showActiveFocusAt((int) x, (int) y);
}
mIsAutoFocusTriggered = true;
//step4:init focus and metering area and show focus UI
try {
initializeFocusAreas(x, y);
initializeMeteringArea(x, y);
} catch (IllegalArgumentException e) {
LogHelper.e(mTag, "onSingleTapUp IllegalArgumentException");
return;
}
//step5:notify focus area and parameter
mFocusListener.updateFocusArea(mFocusArea, mMeteringArea);
//step6:do auto focus
mFocusListener.autoFocus();
// exposure need onSingleTapUp to reset exposure progress,so
return false;
}
//单击屏幕之后短时间没有再次点击时触发
@Override
public boolean onSingleTapConfirmed(float x, float y) {
return false;
}
//点击屏幕不松开不移动及触发
@Override
public boolean onShowPress(MotionEvent event) {
return false;
}
//双击屏幕的第二下点击触发
@Override
public boolean onDoubleTap(float x, float y) {
return false;
}
//点击屏幕后不移动不松开一直长按触发
@Override
public boolean onLongPress(float x, float y) {
//step1:Check whether auto focus can do
if (!checkAfEnv()) {
return false;
}
boolean isNeeedCancelAutoFocus = needCancelAutoFocus();
mNeedDoAfLock = false;
if (mFocusViewController == null) {
return;
}
mIsAutoFocusTriggered = true;
mLockPoint.set((int) x, (int) y);
if (isNeeedCancelAutoFocus) {
mFocusListener.cancelAutoFocus();
}
triggerAfLock();
return false;
}
//缩放手势的监听,缩放过程中触发
@Override
public boolean onScale(ScaleGestureDetector scaleGestureDetector) {
return false;
}
//缩放手势的监听,多个手指触碰屏幕是调用
@Override
public boolean onScaleBegin(ScaleGestureDetector scaleGestureDetector) {
return false;
}
//全部手指离开屏幕时结束监听
@Override
public boolean onScaleEnd(ScaleGestureDetector scaleGestureDetector) {
return false;
}
当检测到单击屏幕事件后触发的聚焦UI相关的处理,此时触发的Focus状态为unlock状态
//1.检测聚焦功能可执行环境
private boolean checkAfEnv() {
//ignore touch focus if preview not initialized.
if (!mPreviewStarted) {
LogHelper.w(mTag, "[checkAfEnv] preview not started ");
return false;
}
// If focus view is not ready,do nothing.
if (!mFocusViewController.isReadyTodoFocus()) {
return false;
}
if (!mFocusListener.isFocusCanDo()) {
return false;
}
// do not do touch focus if some one restriction focus to continue only
List<String> entryValues = getEntryValues();
if (entryValues != null && entryValues.size() == 1 &&
(entryValues.contains("continuous-picture")
|| entryValues.contains("continuous-video"))) {
return false;
}
if (mFocusListener.isLastAfTriggerStillOnGoing()) {
return false;
}
return true;
}
//2.发送Focus功能没有触发的状态
private void handleAfLockRestore() {
mSettingController.postRestriction(FocusRestriction.getAfLockRestriction()
.getRelation(FocusRestriction.FOCUS_UNLOCK, true));
mSettingController.postRestriction(FocusRestriction.getAeAfLockRestriction()
.getRelation(FocusRestriction.FOCUS_UNLOCK, true));
mLockState = LockState.STATE_UNLOCKED;
mAppUi.hideScreenHint(mLockIndicatorHint);
}
//Focus为Lock状态时,Exposure也为Lock状态
private static RelationGroup sAfLockRelationGroup = new RelationGroup();
static {
sAfLockRelationGroup.setHeaderKey(KEY_FOCUS);
sAfLockRelationGroup.setBodyKeys(EXPOSURE_KEY);
sAfLockRelationGroup.addRelation(
new Relation.Builder(KEY_FOCUS, FOCUS_LOCK)
.addBody(EXPOSURE_KEY, EXPOSURE_LOCK, "true")
.build());
sAfLockRelationGroup.addRelation(
new Relation.Builder(KEY_FOCUS, FOCUS_UNLOCK)
.addBody(EXPOSURE_KEY, EXPOSURE_LOCK, "false")
.build());
}
//Focus为Lock状态时,Flash为关闭状态
private static RelationGroup sAeAfLockRelationGroup = new RelationGroup();
static {
sAeAfLockRelationGroup.setHeaderKey(KEY_FOCUS);
sAeAfLockRelationGroup.setBodyKeys(FLASH_KEY);
sAeAfLockRelationGroup.addRelation(
new Relation.Builder(KEY_FOCUS, FOCUS_LOCK)
.addBody(FLASH_KEY, "off", "off")
.build());
sAeAfLockRelationGroup.addRelation(
new Relation.Builder(KEY_FOCUS, FOCUS_UNLOCK)
.build());
}
//3.显示聚焦框UI
public void showActiveFocusAt(final int viewX, final int viewY) {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
if (mFocusView == null) {
return;
}
mFeatureRootView.unRegisterView(mFocusView);
mFeatureRootView.registerView(mFocusView, TOUCH_FOCUS_VIEW_PRIORITY);
//Make sure focus view be added to root view when it is not null.
makeSureViewOnTree();
setFocusLocation(viewX, viewY);
mFocusView.setFocusLocation(viewX, viewY);
//Set Focus UI as VISIBLE
mFocusView.startActiveFocus(mApp);
}
});
}
//4.初始化Focus区域
//这边是聚焦UI的区域
private void initializeFocusAreas(float x, float y) {
if (mFocusArea == null) {
mFocusArea = new ArrayList<Area>();
mFocusArea.add(new Area(new Rect(), 1));
}
Rect rect = new Rect();
CameraUtil.rectFToRect(mPreviewRect, rect);
//will dispatch mFocusArea to device
int displayRotation = CameraUtil.getDisplayRotation(mActivity);
mFocusArea.get(0).rect = CoordinatesTransform.uiToSensor(new Point((int) x,
(int) y), rect, displayRotation, AF_REGION_BOX,
mFocusRequestConfigure.getCropRegion(),
mFocusRequestConfigure.getCameraCharacteristics());
}
//这边初始的是曝光调节杆的区域
private void initializeMeteringArea(float x, float y) {
if (mMeteringArea == null) {
mMeteringArea = new ArrayList<Area>();
mMeteringArea.add(new Area(new Rect(), 1));
}
Rect rect = new Rect();
CameraUtil.rectFToRect(mPreviewRect, rect);
//will dispatch mMeteringAreato device
int displayRotation = CameraUtil.getDisplayRotation(mActivity);
mMeteringArea.get(0).rect = CoordinatesTransform.uiToSensor(new Point((int) x,
(int) y), rect, displayRotation, AE_REGION_BOX,
mFocusRequestConfigure.getCropRegion(),
mFocusRequestConfigure.getCameraCharacteristics());
}
}
//5.更新聚焦UI区域
@Override
public void updateFocusArea(List<Camera.Area> focusArea, List<Camera.Area> meteringArea) {
if (focusArea != null) {
mAFRegions = new MeteringRectangle[]{new MeteringRectangle(focusArea.get(0).rect,
CAMERA2_REGION_WEIGHT)};
}
if (meteringArea != null) {
mAERegions = new MeteringRectangle[]{new MeteringRectangle(meteringArea.get(0).rect,
CAMERA2_REGION_WEIGHT)};
}
}
//6.发送触发自动聚焦的相关底层tag,同时Flash、Exposure相关的底层配置Tag也会一同下发
@Override
public void autoFocus() {
sendAutoFocusTriggerCaptureRequest(false);
}
长按屏幕此时触发Focus的lock状态
//1.判断是否可以执行自动聚焦功能
if (!checkAfEnv()) {
return false;
}
//2.判断是否需要取消上个状态的自动聚焦功能
boolean isNeeedCancelAutoFocus = needCancelAutoFocus();
private boolean needCancelAutoFocus() {
if (mFocusViewController == null) {
LogHelper.w(mTag, "[needCancelAutoFocus] mFocusViewController is null");
return false;
}
FocusViewState state = mFocusViewController.getFocusState();
//根据已知更新的Focus状态state去判断是否需要关闭
boolean result = mFocusArea != null && (FocusViewState.STATE_ACTIVE_FOCUSING == state);
return result;
}
//下文会继续讲Focus的几个不同状态及其对应的时机,以及Focus状态的管理机制
//3.如果需要取消自动对焦,发送取消自动对焦的参数
if (isNeeedCancelAutoFocus) {
mFocusListener.cancelAutoFocus();
}
@Override
public void cancelAutoFocus() {
LogHelper.d(TAG, "[cancelAutoFocus] ");
sendAutoFocusCancelCaptureRequest();
}
//4.触发AF mode为lock的转态
triggerAfLock();
/长按触发AF Lock状态处理流程貌似和单击触发自动对焦的流程一样,但是在Focus的状态管理中已经下发了AF Lock的状态
private void triggerAfLock() {
LogHelper.d(mTag, "[triggerAfLock]+ ");
mNeedResetTouchFocus = false;
//Clear any focus UI before show touch focus UI
mFocusViewController.clearFocusUi();
//init focus and metering area and show focus UI
try {
initializeFocusAreas(mLockPoint.x, mLockPoint.y);
initializeMeteringArea(mLockPoint.x, mLockPoint.y);
} catch (IllegalArgumentException e) {
LogHelper.e(mTag, "triggerAfLock IllegalArgumentException");
return;
}
if (mNeedShowFocusUi) {
mFocusViewController.showActiveFocusAt(mLockPoint.x, mLockPoint.y);
mAppUi.hideScreenHint(mLockIndicatorHint);
mAppUi.showScreenHint(mLockIndicatorHint);
}
//notify focus area and parameter
mFocusListener.updateFocusArea(mFocusArea, mMeteringArea);
mModeHandler.removeMessages(RESET_TOUCH_FOCUS);
//post to to ae unlock
//这边和单击触发自动聚焦相比就可以看出比较明显的区别,AEAF仍为Lock状态,只是曝光为UnLock
mSettingController.postRestriction(FocusRestriction.getAfLockRestriction()
.getRelation(FocusRestriction.FOCUS_UNLOCK, true));
//fix focus mode to auto and do auto focus
mFocusListener.autoFocus();
mLockState = LockState.STATE_LOCKING;
mNeedDoAfLock = true;
LogHelper.d(mTag, "[Lock]-");
}
小结:
聚焦这一块的内容一篇文章根本讲不完,下文会继续深入研究Focus PASSIVE_SCAN、ACTIVE_SCAN、PASSIVE_FOCUSED、PASSIVE_UNFOCUSED、ACTIVE_FOCUSED、ACTIVE_UNFOCUSED等不同状态的管理,以及自动聚焦功能触发时下发到底层的Tag管理。