Home | History | Annotate | Download | only in camera
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.camera;
     18 
     19 import android.graphics.Rect;
     20 import android.graphics.RectF;
     21 import android.hardware.Camera.Area;
     22 import android.os.Handler;
     23 import android.os.Looper;
     24 import android.os.Message;
     25 
     26 import com.android.camera.app.AppController;
     27 import com.android.camera.app.MotionManager;
     28 import com.android.camera.debug.Log;
     29 import com.android.camera.one.Settings3A;
     30 import com.android.camera.settings.Keys;
     31 import com.android.camera.settings.SettingsManager;
     32 import com.android.camera.ui.PreviewStatusListener;
     33 import com.android.camera.ui.TouchCoordinate;
     34 import com.android.camera.util.ApiHelper;
     35 import com.android.camera.ui.focus.CameraCoordinateTransformer;
     36 import com.android.camera.ui.focus.FocusRing;
     37 import com.android.camera.util.CameraUtil;
     38 import com.android.camera.stats.UsageStatistics;
     39 import com.android.ex.camera2.portability.CameraCapabilities;
     40 
     41 import java.lang.ref.WeakReference;
     42 import java.util.ArrayList;
     43 import java.util.List;
     44 
     45 /* A class that handles everything about focus in still picture mode.
     46  * This also handles the metering area because it is the same as focus area.
     47  *
     48  * The test cases:
     49  * (1) The camera has continuous autofocus. Move the camera. Take a picture when
     50  *     CAF is not in progress.
     51  * (2) The camera has continuous autofocus. Move the camera. Take a picture when
     52  *     CAF is in progress.
     53  * (3) The camera has face detection. Point the camera at some faces. Hold the
     54  *     shutter. Release to take a picture.
     55  * (4) The camera has face detection. Point the camera at some faces. Single tap
     56  *     the shutter to take a picture.
     57  * (5) The camera has autofocus. Single tap the shutter to take a picture.
     58  * (6) The camera has autofocus. Hold the shutter. Release to take a picture.
     59  * (7) The camera has no autofocus. Single tap the shutter and take a picture.
     60  * (8) The camera has autofocus and supports focus area. Touch the screen to
     61  *     trigger autofocus. Take a picture.
     62  * (9) The camera has autofocus and supports focus area. Touch the screen to
     63  *     trigger autofocus. Wait until it times out.
     64  * (10) The camera has no autofocus and supports metering area. Touch the screen
     65  *     to change metering area.
     66  */
     67 public class FocusOverlayManager implements PreviewStatusListener.PreviewAreaChangedListener,
     68         MotionManager.MotionListener {
     69     private static final Log.Tag TAG = new Log.Tag("FocusOverlayMgr");
     70 
     71     private static final int RESET_TOUCH_FOCUS = 0;
     72 
     73     private static final int RESET_TOUCH_FOCUS_DELAY_MILLIS = Settings3A.getFocusHoldMillis();
     74 
     75     public static final float AF_REGION_BOX = Settings3A.getAutoFocusRegionWidth();
     76     public static final float AE_REGION_BOX = Settings3A.getMeteringRegionWidth();
     77 
     78     private int mState = STATE_IDLE;
     79     private static final int STATE_IDLE = 0; // Focus is not active.
     80     private static final int STATE_FOCUSING = 1; // Focus is in progress.
     81     // Focus is in progress and the camera should take a picture after focus finishes.
     82     private static final int STATE_FOCUSING_SNAP_ON_FINISH = 2;
     83     private static final int STATE_SUCCESS = 3; // Focus finishes and succeeds.
     84     private static final int STATE_FAIL = 4; // Focus finishes and fails.
     85 
     86     private boolean mInitialized;
     87     private boolean mFocusAreaSupported;
     88     private boolean mMeteringAreaSupported;
     89     private boolean mLockAeAwbNeeded;
     90     private boolean mAeAwbLock;
     91     private CameraCoordinateTransformer mCoordinateTransformer;
     92 
     93     private boolean mMirror; // true if the camera is front-facing.
     94     private int mDisplayOrientation;
     95     private List<Area> mFocusArea; // focus area in driver format
     96     private List<Area> mMeteringArea; // metering area in driver format
     97     private CameraCapabilities.FocusMode mFocusMode;
     98     private final List<CameraCapabilities.FocusMode> mDefaultFocusModes;
     99     private CameraCapabilities.FocusMode mOverrideFocusMode;
    100     private CameraCapabilities mCapabilities;
    101     private final AppController mAppController;
    102     private final SettingsManager mSettingsManager;
    103     private final Handler mHandler;
    104     Listener mListener;
    105     private boolean mPreviousMoving;
    106     private final FocusRing mFocusRing;
    107     private final Rect mPreviewRect = new Rect(0, 0, 0, 0);
    108     private boolean mFocusLocked;
    109 
    110     /** Manual tap to focus parameters */
    111     private TouchCoordinate mTouchCoordinate;
    112     private long mTouchTime;
    113 
    114     public interface Listener {
    115         public void autoFocus();
    116         public void cancelAutoFocus();
    117         public boolean capture();
    118         public void startFaceDetection();
    119         public void stopFaceDetection();
    120         public void setFocusParameters();
    121     }
    122 
    123     /**
    124      * TODO: Refactor this so that we either don't need a handler or make
    125      * mListener not be the activity.
    126      */
    127     private static class MainHandler extends Handler {
    128         /**
    129          * The outer mListener at the moment is actually the CameraActivity,
    130          * which we would leak if we didn't break the GC path here using a
    131          * WeakReference.
    132          */
    133         final WeakReference<FocusOverlayManager> mManager;
    134         public MainHandler(FocusOverlayManager manager, Looper looper) {
    135             super(looper);
    136             mManager = new WeakReference<FocusOverlayManager>(manager);
    137         }
    138 
    139         @Override
    140         public void handleMessage(Message msg) {
    141             FocusOverlayManager manager = mManager.get();
    142             if (manager == null) {
    143                 return;
    144             }
    145 
    146             switch (msg.what) {
    147                 case RESET_TOUCH_FOCUS: {
    148                     manager.cancelAutoFocus();
    149                     manager.mListener.startFaceDetection();
    150                     break;
    151                 }
    152             }
    153         }
    154     }
    155 
    156     public FocusOverlayManager(AppController appController,
    157             List<CameraCapabilities.FocusMode> defaultFocusModes, CameraCapabilities capabilities,
    158             Listener listener, boolean mirror, Looper looper, FocusRing focusRing) {
    159         mAppController = appController;
    160         mSettingsManager = appController.getSettingsManager();
    161         mHandler = new MainHandler(this, looper);
    162         mDefaultFocusModes = new ArrayList<CameraCapabilities.FocusMode>(defaultFocusModes);
    163         updateCapabilities(capabilities);
    164         mListener = listener;
    165         setMirror(mirror);
    166         mFocusRing = focusRing;
    167         mFocusLocked = false;
    168     }
    169 
    170     public void updateCapabilities(CameraCapabilities capabilities) {
    171         // capabilities can only be null when onConfigurationChanged is called
    172         // before camera is open. We will just return in this case, because
    173         // capabilities will be set again later with the right capabilities after
    174         // camera is open.
    175         if (capabilities == null) {
    176             return;
    177         }
    178         mCapabilities = capabilities;
    179         mFocusAreaSupported = mCapabilities.supports(CameraCapabilities.Feature.FOCUS_AREA);
    180         mMeteringAreaSupported = mCapabilities.supports(CameraCapabilities.Feature.METERING_AREA);
    181         mLockAeAwbNeeded = (mCapabilities.supports(CameraCapabilities.Feature.AUTO_EXPOSURE_LOCK)
    182                 || mCapabilities.supports(CameraCapabilities.Feature.AUTO_WHITE_BALANCE_LOCK));
    183     }
    184 
    185     /** This setter should be the only way to mutate mPreviewRect. */
    186     public void setPreviewRect(Rect previewRect) {
    187         if (!mPreviewRect.equals(previewRect)) {
    188             mPreviewRect.set(previewRect);
    189             mFocusRing.configurePreviewDimensions(CameraUtil.rectToRectF(mPreviewRect));
    190             resetCoordinateTransformer();
    191             mInitialized = true;
    192         }
    193     }
    194 
    195     @Override
    196     public void onPreviewAreaChanged(RectF previewArea) {
    197         setPreviewRect(CameraUtil.rectFToRect(previewArea));
    198     }
    199 
    200     public void setMirror(boolean mirror) {
    201         mMirror = mirror;
    202         resetCoordinateTransformer();
    203     }
    204 
    205     public void setDisplayOrientation(int displayOrientation) {
    206         mDisplayOrientation = displayOrientation;
    207         resetCoordinateTransformer();
    208     }
    209 
    210     private void resetCoordinateTransformer() {
    211         if (mPreviewRect.width() > 0 && mPreviewRect.height() > 0) {
    212             mCoordinateTransformer = new CameraCoordinateTransformer(mMirror, mDisplayOrientation,
    213                   CameraUtil.rectToRectF(mPreviewRect));
    214         } else {
    215             Log.w(TAG, "The coordinate transformer could not be built because the preview rect"
    216                   + "did not have a width and height");
    217         }
    218     }
    219 
    220 
    221     private void lockAeAwbIfNeeded() {
    222         if (mLockAeAwbNeeded && !mAeAwbLock) {
    223             mAeAwbLock = true;
    224             mListener.setFocusParameters();
    225         }
    226     }
    227 
    228     private void unlockAeAwbIfNeeded() {
    229         if (mLockAeAwbNeeded && mAeAwbLock && (mState != STATE_FOCUSING_SNAP_ON_FINISH)) {
    230             mAeAwbLock = false;
    231             mListener.setFocusParameters();
    232         }
    233     }
    234 
    235     public void onShutterUp(CameraCapabilities.FocusMode currentFocusMode) {
    236         if (!mInitialized) {
    237             return;
    238         }
    239 
    240         if (needAutoFocusCall(currentFocusMode)) {
    241             // User releases half-pressed focus key.
    242             if (mState == STATE_FOCUSING || mState == STATE_SUCCESS
    243                     || mState == STATE_FAIL) {
    244                 cancelAutoFocus();
    245             }
    246         }
    247 
    248         // Unlock AE and AWB after cancelAutoFocus. Camera API does not
    249         // guarantee setParameters can be called during autofocus.
    250         unlockAeAwbIfNeeded();
    251     }
    252 
    253     public void focusAndCapture(CameraCapabilities.FocusMode currentFocusMode) {
    254         if (!mInitialized) {
    255             return;
    256         }
    257 
    258         if (!needAutoFocusCall(currentFocusMode)) {
    259             // Focus is not needed.
    260             capture();
    261         } else if (mState == STATE_SUCCESS || mState == STATE_FAIL) {
    262             // Focus is done already.
    263             capture();
    264         } else if (mState == STATE_FOCUSING) {
    265             // Still focusing and will not trigger snap upon finish.
    266             mState = STATE_FOCUSING_SNAP_ON_FINISH;
    267         } else if (mState == STATE_IDLE) {
    268             autoFocusAndCapture();
    269         }
    270     }
    271 
    272     public void onAutoFocus(boolean focused, boolean shutterButtonPressed) {
    273         if (mState == STATE_FOCUSING_SNAP_ON_FINISH) {
    274             // Take the picture no matter focus succeeds or fails. No need
    275             // to play the AF sound if we're about to play the shutter
    276             // sound.
    277             if (focused) {
    278                 mState = STATE_SUCCESS;
    279             } else {
    280                 mState = STATE_FAIL;
    281             }
    282             capture();
    283         } else if (mState == STATE_FOCUSING) {
    284             // This happens when (1) user is half-pressing the focus key or
    285             // (2) touch focus is triggered. Play the focus tone. Do not
    286             // take the picture now.
    287             if (focused) {
    288                 mState = STATE_SUCCESS;
    289             } else {
    290                 mState = STATE_FAIL;
    291             }
    292             // If this is triggered by touch focus, cancel focus after a
    293             // while.
    294             if (mFocusArea != null) {
    295                 mFocusLocked = true;
    296                 mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY_MILLIS);
    297             }
    298             if (shutterButtonPressed) {
    299                 // Lock AE & AWB so users can half-press shutter and recompose.
    300                 lockAeAwbIfNeeded();
    301             }
    302         } else if (mState == STATE_IDLE) {
    303             // User has released the focus key before focus completes.
    304             // Do nothing.
    305         }
    306     }
    307 
    308     public void onAutoFocusMoving(boolean moving) {
    309         if (!mInitialized) {
    310             return;
    311         }
    312 
    313         // Ignore if we have requested autofocus. This method only handles
    314         // continuous autofocus.
    315         if (mState != STATE_IDLE) {
    316             return;
    317         }
    318 
    319         // animate on false->true trasition only b/8219520
    320         if (moving && !mPreviousMoving) {
    321             // Auto focus at the center of the preview.
    322             mFocusRing.startPassiveFocus();
    323             mFocusRing.centerFocusLocation();
    324         } else if (!moving && mFocusRing.isPassiveFocusRunning()) {
    325             mFocusRing.stopFocusAnimations();
    326         }
    327         mPreviousMoving = moving;
    328     }
    329 
    330     /** Returns width of auto focus region in pixels. */
    331     private int getAFRegionSizePx() {
    332         return (int) (Math.min(mPreviewRect.width(), mPreviewRect.height()) * AF_REGION_BOX);
    333     }
    334 
    335     /** Returns width of metering region in pixels. */
    336     private int getAERegionSizePx() {
    337         return (int) (Math.min(mPreviewRect.width(), mPreviewRect.height()) * AE_REGION_BOX);
    338     }
    339 
    340     private void initializeFocusAreas(int x, int y) {
    341         if (mFocusArea == null) {
    342             mFocusArea = new ArrayList<Area>();
    343             mFocusArea.add(new Area(new Rect(), 1));
    344         }
    345 
    346         // Convert the coordinates to driver format.
    347         mFocusArea.get(0).rect = computeCameraRectFromPreviewCoordinates(x, y, getAFRegionSizePx());
    348     }
    349 
    350     private void initializeMeteringAreas(int x, int y) {
    351         if (mMeteringArea == null) {
    352             mMeteringArea = new ArrayList<Area>();
    353             mMeteringArea.add(new Area(new Rect(), 1));
    354         }
    355 
    356         // Convert the coordinates to driver format.
    357         mMeteringArea.get(0).rect = computeCameraRectFromPreviewCoordinates(x, y, getAERegionSizePx());
    358     }
    359 
    360     public void onSingleTapUp(int x, int y) {
    361         if (!mInitialized || mState == STATE_FOCUSING_SNAP_ON_FINISH) {
    362             return;
    363         }
    364 
    365         // Let users be able to cancel previous touch focus.
    366         if ((mFocusArea != null) && (mState == STATE_FOCUSING ||
    367                     mState == STATE_SUCCESS || mState == STATE_FAIL)) {
    368             cancelAutoFocus();
    369         }
    370         if (mPreviewRect.width() == 0 || mPreviewRect.height() == 0) {
    371             return;
    372         }
    373         // Initialize variables.
    374         // Initialize mFocusArea.
    375         if (mFocusAreaSupported) {
    376             initializeFocusAreas(x, y);
    377         }
    378         // Initialize mMeteringArea.
    379         if (mMeteringAreaSupported) {
    380             initializeMeteringAreas(x, y);
    381         }
    382 
    383         mFocusRing.startActiveFocus();
    384         mFocusRing.setFocusLocation(x, y);
    385 
    386         // Log manual tap to focus.
    387         mTouchCoordinate = new TouchCoordinate(x, y, mPreviewRect.width(), mPreviewRect.height());
    388         mTouchTime = System.currentTimeMillis();
    389 
    390         // Stop face detection because we want to specify focus and metering area.
    391         mListener.stopFaceDetection();
    392 
    393         // Set the focus area and metering area.
    394         mListener.setFocusParameters();
    395         if (mFocusAreaSupported) {
    396             autoFocus();
    397         } else {  // Just show the indicator in all other cases.
    398             // Reset the metering area in 4 seconds.
    399             mHandler.removeMessages(RESET_TOUCH_FOCUS);
    400             mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY_MILLIS);
    401         }
    402     }
    403 
    404     public void onPreviewStarted() {
    405         mState = STATE_IDLE;
    406         // Avoid resetting touch focus if N4, b/18681082.
    407         if (!ApiHelper.IS_NEXUS_4) {
    408             resetTouchFocus();
    409         }
    410     }
    411 
    412     public void onPreviewStopped() {
    413         // If auto focus was in progress, it would have been stopped.
    414         mState = STATE_IDLE;
    415     }
    416 
    417     public void onCameraReleased() {
    418         onPreviewStopped();
    419     }
    420 
    421     @Override
    422     public void onMoving() {
    423         if (mFocusLocked) {
    424             Log.d(TAG, "onMoving: Early focus unlock.");
    425             cancelAutoFocus();
    426         }
    427     }
    428 
    429     /**
    430      * Triggers the autofocus and sets the specified state.
    431      *
    432      * @param focusingState The state to use when focus is in progress.
    433      */
    434     private void autoFocus(int focusingState) {
    435         mListener.autoFocus();
    436         mState = focusingState;
    437         mHandler.removeMessages(RESET_TOUCH_FOCUS);
    438     }
    439 
    440     /**
    441      * Triggers the autofocus and set the state to indicate the focus is in
    442      * progress.
    443      */
    444     private void autoFocus() {
    445         autoFocus(STATE_FOCUSING);
    446     }
    447 
    448     /**
    449      * Triggers the autofocus and set the state to which a capture will happen
    450      * in the following autofocus callback.
    451      */
    452     private void autoFocusAndCapture() {
    453         autoFocus(STATE_FOCUSING_SNAP_ON_FINISH);
    454     }
    455 
    456     private void cancelAutoFocus() {
    457         Log.v(TAG, "Cancel autofocus.");
    458         // Reset the tap area before calling mListener.cancelAutofocus.
    459         // Otherwise, focus mode stays at auto and the tap area passed to the
    460         // driver is not reset.
    461         resetTouchFocus();
    462         mListener.cancelAutoFocus();
    463         mState = STATE_IDLE;
    464         mFocusLocked = false;
    465         mHandler.removeMessages(RESET_TOUCH_FOCUS);
    466     }
    467 
    468     private void capture() {
    469         if (mListener.capture()) {
    470             mState = STATE_IDLE;
    471             mHandler.removeMessages(RESET_TOUCH_FOCUS);
    472         }
    473     }
    474 
    475     public CameraCapabilities.FocusMode getFocusMode(
    476             final CameraCapabilities.FocusMode currentFocusMode) {
    477         if (mOverrideFocusMode != null) {
    478             Log.v(TAG, "returning override focus: " + mOverrideFocusMode);
    479             return mOverrideFocusMode;
    480         }
    481         if (mCapabilities == null) {
    482             Log.v(TAG, "no capabilities, returning default AUTO focus mode");
    483             return CameraCapabilities.FocusMode.AUTO;
    484         }
    485 
    486         if (mFocusAreaSupported && mFocusArea != null) {
    487             Log.v(TAG, "in tap to focus, returning AUTO focus mode");
    488             // Always use autofocus in tap-to-focus.
    489             mFocusMode = CameraCapabilities.FocusMode.AUTO;
    490         } else {
    491             String focusSetting = mSettingsManager.getString(mAppController.getCameraScope(),
    492                     Keys.KEY_FOCUS_MODE);
    493             Log.v(TAG, "stored focus setting for camera: " + focusSetting);
    494             // The default is continuous autofocus.
    495             mFocusMode = mCapabilities.getStringifier().focusModeFromString(focusSetting);
    496             Log.v(TAG, "focus mode resolved from setting: " + mFocusMode);
    497             // Try to find a supported focus mode from the default list.
    498             if (mFocusMode == null) {
    499                 for (CameraCapabilities.FocusMode mode : mDefaultFocusModes) {
    500                     if (mCapabilities.supports(mode)) {
    501                         mFocusMode = mode;
    502                         Log.v(TAG, "selected supported focus mode from default list" + mode);
    503                         break;
    504                     }
    505                 }
    506             }
    507         }
    508         if (!mCapabilities.supports(mFocusMode)) {
    509             // For some reasons, the driver does not support the current
    510             // focus mode. Fall back to auto.
    511             if (mCapabilities.supports(CameraCapabilities.FocusMode.AUTO)) {
    512                 Log.v(TAG, "no supported focus mode, falling back to AUTO");
    513                 mFocusMode = CameraCapabilities.FocusMode.AUTO;
    514             } else {
    515                 Log.v(TAG, "no supported focus mode, falling back to current: " + currentFocusMode);
    516                 mFocusMode = currentFocusMode;
    517             }
    518         }
    519         return mFocusMode;
    520     }
    521 
    522     public List<Area> getFocusAreas() {
    523         return mFocusArea;
    524     }
    525 
    526     public List<Area> getMeteringAreas() {
    527         return mMeteringArea;
    528     }
    529 
    530     public void resetTouchFocus() {
    531         if (!mInitialized) {
    532             return;
    533         }
    534 
    535         mFocusArea = null;
    536         mMeteringArea = null;
    537         // This will cause current module to call getFocusAreas() and
    538         // getMeteringAreas() and send updated regions to camera.
    539         mListener.setFocusParameters();
    540 
    541         if (mTouchCoordinate != null) {
    542             UsageStatistics.instance().tapToFocus(mTouchCoordinate,
    543                     0.001f * (System.currentTimeMillis() - mTouchTime));
    544             mTouchCoordinate = null;
    545         }
    546     }
    547 
    548     private Rect computeCameraRectFromPreviewCoordinates(int x, int y, int size) {
    549         int left = CameraUtil.clamp(x - size / 2, mPreviewRect.left,
    550                 mPreviewRect.right - size);
    551         int top = CameraUtil.clamp(y - size / 2, mPreviewRect.top,
    552                 mPreviewRect.bottom - size);
    553 
    554         RectF rectF = new RectF(left, top, left + size, top + size);
    555         return CameraUtil.rectFToRect(mCoordinateTransformer.toCameraSpace(rectF));
    556     }
    557 
    558     /* package */ int getFocusState() {
    559         return mState;
    560     }
    561 
    562     public boolean isFocusCompleted() {
    563         return mState == STATE_SUCCESS || mState == STATE_FAIL;
    564     }
    565 
    566     public boolean isFocusingSnapOnFinish() {
    567         return mState == STATE_FOCUSING_SNAP_ON_FINISH;
    568     }
    569 
    570     public void removeMessages() {
    571         mHandler.removeMessages(RESET_TOUCH_FOCUS);
    572     }
    573 
    574     public void overrideFocusMode(CameraCapabilities.FocusMode focusMode) {
    575         mOverrideFocusMode = focusMode;
    576     }
    577 
    578     public void setAeAwbLock(boolean lock) {
    579         mAeAwbLock = lock;
    580     }
    581 
    582     public boolean getAeAwbLock() {
    583         return mAeAwbLock;
    584     }
    585 
    586     private boolean needAutoFocusCall(CameraCapabilities.FocusMode focusMode) {
    587         return !(focusMode == CameraCapabilities.FocusMode.INFINITY
    588                 || focusMode == CameraCapabilities.FocusMode.FIXED
    589                 || focusMode == CameraCapabilities.FocusMode.EXTENDED_DOF);
    590     }
    591 }
    592