Home | History | Annotate | Download | only in state
      1 /*
      2  * Copyright (C) 2015 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.captureintent.state;
     18 
     19 import android.graphics.Bitmap;
     20 import android.graphics.Matrix;
     21 import android.graphics.Point;
     22 import android.graphics.PointF;
     23 import android.graphics.RectF;
     24 import android.media.MediaActionSound;
     25 import android.net.Uri;
     26 
     27 import com.android.camera.async.RefCountBase;
     28 import com.android.camera.captureintent.CaptureIntentConfig;
     29 import com.android.camera.captureintent.CaptureIntentModuleUI;
     30 import com.android.camera.captureintent.PictureDecoder;
     31 import com.android.camera.captureintent.event.EventCameraBusy;
     32 import com.android.camera.captureintent.event.EventCameraQuickExpose;
     33 import com.android.camera.captureintent.event.EventCameraReady;
     34 import com.android.camera.captureintent.event.EventClickOnCameraKey;
     35 import com.android.camera.captureintent.event.EventFastPictureBitmapAvailable;
     36 import com.android.camera.captureintent.event.EventOnSurfaceTextureUpdated;
     37 import com.android.camera.captureintent.event.EventOnTextureViewLayoutChanged;
     38 import com.android.camera.captureintent.event.EventPause;
     39 import com.android.camera.captureintent.event.EventPictureCompressed;
     40 import com.android.camera.captureintent.event.EventPictureDecoded;
     41 import com.android.camera.captureintent.event.EventTapOnCancelShutterButton;
     42 import com.android.camera.captureintent.event.EventTapOnPreview;
     43 import com.android.camera.captureintent.event.EventTapOnShutterButton;
     44 import com.android.camera.captureintent.event.EventTapOnSwitchCameraButton;
     45 import com.android.camera.captureintent.event.EventTimerCountDownToZero;
     46 import com.android.camera.captureintent.event.EventZoomRatioChanged;
     47 import com.android.camera.captureintent.resource.ResourceCaptureTools;
     48 import com.android.camera.captureintent.resource.ResourceCaptureToolsImpl;
     49 import com.android.camera.captureintent.resource.ResourceConstructed;
     50 import com.android.camera.captureintent.resource.ResourceOpenedCamera;
     51 import com.android.camera.captureintent.resource.ResourceSurfaceTexture;
     52 import com.android.camera.captureintent.stateful.EventHandler;
     53 import com.android.camera.captureintent.stateful.State;
     54 import com.android.camera.captureintent.stateful.StateImpl;
     55 import com.android.camera.debug.Log;
     56 import com.android.camera.device.CameraId;
     57 import com.android.camera.one.OneCamera;
     58 import com.android.camera.one.OneCamera.Facing;
     59 import com.android.camera.one.OneCameraAccessException;
     60 import com.android.camera.one.OneCameraCharacteristics;
     61 import com.android.camera.session.CaptureSession;
     62 import com.android.camera.session.CaptureSessionManager;
     63 import com.android.camera.settings.Keys;
     64 import com.android.camera.settings.SettingsManager;
     65 import com.android.camera.ui.CountDownView;
     66 import com.android.camera.ui.TouchCoordinate;
     67 import com.android.camera.ui.focus.FocusController;
     68 import com.android.camera.util.Size;
     69 
     70 import com.google.common.base.Optional;
     71 
     72 import javax.annotation.Nullable;
     73 
     74 /**
     75  * Represents a state that allows users to take a picture. The capture UI
     76  * should be presented in this state so users can perform actions:
     77  * 1. tap on shutter button to take a picture.
     78  * 2. tap on viewfinder to focus.
     79  * 3. switch between front and back camera.
     80  */
     81 public final class StateReadyForCapture extends StateImpl {
     82     private static final Log.Tag TAG = new Log.Tag("StateReadyCap");
     83 
     84     private final RefCountBase<ResourceCaptureTools> mResourceCaptureTools;
     85 
     86     private boolean mShouldUpdateTransformOnNextSurfaceTextureUpdate;
     87     private boolean mIsCountingDown;
     88     private boolean mIsTakingPicture;
     89     private boolean mIsDecodingPicture;
     90 
     91     public static StateReadyForCapture from(
     92             StateStartingPreview startingPreview,
     93             RefCountBase<ResourceConstructed> resourceConstructed,
     94             RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture,
     95             RefCountBase<ResourceOpenedCamera> resourceOpenedCamera) {
     96         return new StateReadyForCapture(
     97                 startingPreview, resourceConstructed, resourceSurfaceTexture, resourceOpenedCamera);
     98     }
     99 
    100     public static StateReadyForCapture from(
    101             StateReviewingPicture reviewingPicture,
    102             RefCountBase<ResourceCaptureTools> resourceCaptureTools) {
    103         return new StateReadyForCapture(reviewingPicture, resourceCaptureTools);
    104     }
    105 
    106     private StateReadyForCapture(
    107             State previousState,
    108             RefCountBase<ResourceConstructed> resourceConstructed,
    109             RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture,
    110             RefCountBase<ResourceOpenedCamera> resourceOpenedCamera) {
    111         super(previousState);
    112         mResourceCaptureTools = ResourceCaptureToolsImpl.create(
    113                 resourceConstructed, resourceSurfaceTexture, resourceOpenedCamera);
    114         mIsCountingDown = false;
    115         mIsTakingPicture = false;
    116         mIsDecodingPicture = false;
    117         mShouldUpdateTransformOnNextSurfaceTextureUpdate = true;
    118         registerEventHandlers();
    119     }
    120 
    121     private StateReadyForCapture(
    122             State previousState,
    123             RefCountBase<ResourceCaptureTools> resourceCaptureTools) {
    124         super(previousState);
    125         mResourceCaptureTools = resourceCaptureTools;
    126         mResourceCaptureTools.addRef();  // Will be balanced in onLeave().
    127         mIsCountingDown = false;
    128         mIsTakingPicture = false;
    129         mIsDecodingPicture = false;
    130         mShouldUpdateTransformOnNextSurfaceTextureUpdate = true;
    131         registerEventHandlers();
    132     }
    133 
    134     private void takePicture(@Nullable final TouchCoordinate touchPointInsideShutterButton) {
    135         final int countDownDuration =
    136                 mResourceCaptureTools.get().getResourceConstructed().get()
    137                         .getSettingsManager().getInteger(
    138                         SettingsManager.SCOPE_GLOBAL, Keys.KEY_COUNTDOWN_DURATION);
    139 
    140         /** Prepare a CaptureLoggingInfo object. */
    141         final ResourceCaptureTools.CaptureLoggingInfo captureLoggingInfo
    142                 = new ResourceCaptureTools.CaptureLoggingInfo() {
    143             @Override
    144             public TouchCoordinate getTouchPointInsideShutterButton() {
    145                 return touchPointInsideShutterButton;
    146             }
    147 
    148             @Override
    149             public int getCountDownDuration() {
    150                 return countDownDuration;
    151             }
    152         };
    153 
    154         /** Start counting down if the duration is not zero. */
    155         if (countDownDuration > 0) {
    156             startCountDown(countDownDuration, captureLoggingInfo);
    157         } else {
    158             /** Otherwise, just take a picture immediately. */
    159             takePictureNow(captureLoggingInfo);
    160         }
    161     }
    162 
    163     private void startCountDown(
    164             final int countDownDuration,
    165             final ResourceCaptureTools.CaptureLoggingInfo captureLoggingInfo) {
    166         mIsCountingDown = true;
    167         mResourceCaptureTools.get().getMainThread().execute(new Runnable() {
    168             @Override
    169             public void run() {
    170                 CaptureIntentModuleUI moduleUI = mResourceCaptureTools.get().getModuleUI();
    171                 moduleUI.setCountdownFinishedListener(
    172                         new CountDownView.OnCountDownStatusListener() {
    173                             @Override
    174                             public void onRemainingSecondsChanged(
    175                                     int remainingSeconds) {
    176                                 mResourceCaptureTools.get()
    177                                         .playCountDownSound(remainingSeconds);
    178                             }
    179 
    180                             @Override
    181                             public void onCountDownFinished() {
    182                                 getStateMachine().processEvent(
    183                                         new EventTimerCountDownToZero(
    184                                                 captureLoggingInfo));
    185                             }
    186                         });
    187                 moduleUI.startCountdown(countDownDuration);
    188             }
    189         });
    190     }
    191 
    192     private void cancelCountDown() {
    193         // Cancel in this state means that the countdown was cancelled.
    194         mIsCountingDown = false;
    195         mResourceCaptureTools.get().getMainThread().execute(new Runnable() {
    196             @Override
    197             public void run() {
    198                 mResourceCaptureTools.get().getModuleUI().cancelCountDown();
    199                 mResourceCaptureTools.get().getModuleUI().showPictureCaptureUI();
    200             }
    201         });
    202     }
    203 
    204     private void takePictureNow(ResourceCaptureTools.CaptureLoggingInfo captureLoggingInfo) {
    205         mIsTakingPicture = true;
    206         mResourceCaptureTools.get().takePictureNow(mPictureCallback, captureLoggingInfo);
    207     }
    208 
    209     private void registerEventHandlers() {
    210         /** Handles EventPause. */
    211         EventHandler<EventPause> pauseHandler = new EventHandler<EventPause>() {
    212             @Override
    213             public Optional<State> processEvent(EventPause event) {
    214                 return Optional.of((State) StateBackgroundWithSurfaceTexture.from(
    215                         StateReadyForCapture.this,
    216                         mResourceCaptureTools.get().getResourceConstructed(),
    217                         mResourceCaptureTools.get().getResourceSurfaceTexture()));
    218             }
    219         };
    220         setEventHandler(EventPause.class, pauseHandler);
    221 
    222         /** Handles EventOnSurfaceTextureUpdated. */
    223         EventHandler<EventOnSurfaceTextureUpdated> onSurfaceTextureUpdatedHandler =
    224                 new EventHandler<EventOnSurfaceTextureUpdated>() {
    225                     @Override
    226                     public Optional<State> processEvent(EventOnSurfaceTextureUpdated event) {
    227                         if (mShouldUpdateTransformOnNextSurfaceTextureUpdate) {
    228                             mShouldUpdateTransformOnNextSurfaceTextureUpdate = false;
    229 
    230                             // We have to provide a preview layout size to
    231                             // ResourceSurfaceTexture. Otherwise, it will
    232                             // not be able to calculate transform matrix.
    233                             Size previewSurfaceSize = mResourceCaptureTools.get().getModuleUI()
    234                                     .getPreviewSurfaceSize();
    235                             mResourceCaptureTools.get().getResourceSurfaceTexture().get()
    236                                     .setPreviewLayoutSize(previewSurfaceSize);
    237 
    238                             removeEventHandler(EventOnSurfaceTextureUpdated.class);
    239                         }
    240                         return NO_CHANGE;
    241                     }
    242                 };
    243         setEventHandler(EventOnSurfaceTextureUpdated.class, onSurfaceTextureUpdatedHandler);
    244 
    245         /** Handles EventOnTextureViewLayoutChanged. */
    246         EventHandler<EventOnTextureViewLayoutChanged> onTextureViewLayoutChangedHandler =
    247                 new EventHandler<EventOnTextureViewLayoutChanged>() {
    248                     @Override
    249                     public Optional<State> processEvent(EventOnTextureViewLayoutChanged event) {
    250                         mResourceCaptureTools.get().getResourceSurfaceTexture().get()
    251                                 .setPreviewLayoutSize(event.getLayoutSize());
    252                         return NO_CHANGE;
    253                     }
    254                 };
    255         setEventHandler(
    256                 EventOnTextureViewLayoutChanged.class, onTextureViewLayoutChangedHandler);
    257 
    258         /** Handles EventCameraBusy. */
    259         setEventHandler(
    260                 EventCameraBusy.class, mEventCameraBusyHandler);
    261 
    262         /** Handles EventCameraReady. */
    263         setEventHandler(
    264                 EventCameraReady.class, mEventCameraReadyHandler);
    265 
    266         /** Handles EventTapOnShutterButton. */
    267         EventHandler<EventTapOnShutterButton> tapOnShutterButtonHandler =
    268                 new EventHandler<EventTapOnShutterButton>() {
    269                     @Override
    270                     public Optional<State> processEvent(final EventTapOnShutterButton event) {
    271                         takePicture(event.getTouchCoordinate());
    272                         return NO_CHANGE;
    273                     }
    274                 };
    275         setEventHandler(EventTapOnShutterButton.class, tapOnShutterButtonHandler);
    276 
    277         /** Handles EventClickOnCameraKey */
    278         EventHandler<EventClickOnCameraKey> clickOnVolumeKeyHandler =
    279                 new EventHandler<EventClickOnCameraKey>() {
    280                     @Override
    281                     public Optional<State> processEvent(EventClickOnCameraKey event) {
    282                         if (mIsCountingDown) {
    283                             cancelCountDown();
    284                             return NO_CHANGE;
    285                         }
    286                         takePicture(null);
    287                         return NO_CHANGE;
    288                     }
    289                 };
    290         setEventHandler(EventClickOnCameraKey.class, clickOnVolumeKeyHandler);
    291 
    292         /** Handles EventTimerCountDownToZero. */
    293         EventHandler<EventTimerCountDownToZero> timerCountDownToZeroHandler =
    294                 new EventHandler<EventTimerCountDownToZero>() {
    295                     @Override
    296                     public Optional<State> processEvent(EventTimerCountDownToZero event) {
    297                         if (mIsCountingDown) {
    298                             mIsCountingDown = false;
    299                             takePictureNow(event.getCaptureLoggingInfo());
    300                         }
    301                         return NO_CHANGE;
    302                     }
    303                 };
    304         setEventHandler(EventTimerCountDownToZero.class, timerCountDownToZeroHandler);
    305 
    306         /** Handles EventTapOnSwitchCameraButton. */
    307         EventHandler<EventTapOnSwitchCameraButton> tapOnSwitchCameraButtonHandler =
    308                 new EventHandler<EventTapOnSwitchCameraButton>() {
    309                     @Override
    310                     public Optional<State> processEvent(EventTapOnSwitchCameraButton event) {
    311                         final ResourceConstructed resourceConstructed =
    312                                 mResourceCaptureTools.get().getResourceConstructed().get();
    313 
    314                         // Freeze the screen.
    315                         mResourceCaptureTools.get().getMainThread().execute(new Runnable() {
    316                             @Override
    317                             public void run() {
    318                                 resourceConstructed.getModuleUI().freezeScreenUntilPreviewReady();
    319                             }
    320                         });
    321 
    322                         OneCamera.Facing cameraFacing =
    323                                 resourceConstructed.getCameraFacingSetting().getCameraFacing();
    324                         CameraId cameraId =  resourceConstructed.getOneCameraManager()
    325                               .findFirstCameraFacing(cameraFacing);
    326                         OneCameraCharacteristics characteristics;
    327                         try {
    328                             characteristics = resourceConstructed.getOneCameraManager()
    329                                     .getOneCameraCharacteristics(cameraId);
    330                         } catch (OneCameraAccessException ex) {
    331                             return Optional.of((State) StateFatal.from(
    332                                     StateReadyForCapture.this,
    333                                     mResourceCaptureTools.get().getResourceConstructed()));
    334                         }
    335 
    336                         return Optional.of((State) StateOpeningCamera.from(
    337                                 StateReadyForCapture.this,
    338                                 mResourceCaptureTools.get().getResourceConstructed(),
    339                                 mResourceCaptureTools.get().getResourceSurfaceTexture(),
    340                                 cameraFacing,
    341                                 cameraId,
    342                                 characteristics));
    343                     }
    344                 };
    345         setEventHandler(EventTapOnSwitchCameraButton.class, tapOnSwitchCameraButtonHandler);
    346 
    347         /** Handles EventTapOnPreview. */
    348         EventHandler<EventTapOnPreview> tapOnPreviewHandler = new EventHandler<EventTapOnPreview>() {
    349             @Override
    350             public Optional<State> processEvent(EventTapOnPreview event) {
    351                 OneCameraCharacteristics cameraCharacteristics = mResourceCaptureTools.get()
    352                       .getResourceOpenedCamera().get().getCameraCharacteristics();
    353                 if (cameraCharacteristics.isAutoExposureSupported() ||
    354                       cameraCharacteristics.isAutoFocusSupported()) {
    355                     final Point tapPoint = event.getTapPoint();
    356                     mResourceCaptureTools.get().getFocusController().showActiveFocusAt(
    357                           tapPoint.x, tapPoint.y);
    358 
    359                     RectF previewRect = mResourceCaptureTools.get().getModuleUI().getPreviewRect();
    360                     int rotationDegree = mResourceCaptureTools.get().getResourceConstructed().get()
    361                           .getOrientationManager().getDisplayRotation().getDegrees();
    362 
    363                     // Normalize coordinates to [0,1] per CameraOne API.
    364                     float points[] = new float[2];
    365                     points[0] = (tapPoint.x - previewRect.left) / previewRect.width();
    366                     points[1] = (tapPoint.y - previewRect.top) / previewRect.height();
    367 
    368                     // Rotate coordinates to portrait orientation per CameraOne API.
    369                     Matrix rotationMatrix = new Matrix();
    370                     rotationMatrix.setRotate(rotationDegree, 0.5f, 0.5f);
    371                     rotationMatrix.mapPoints(points);
    372 
    373                     // Invert X coordinate on front camera since the display is mirrored.
    374                     if (cameraCharacteristics.getCameraDirection() == Facing.FRONT) {
    375                         points[0] = 1 - points[0];
    376                     }
    377 
    378                     mResourceCaptureTools.get().getResourceOpenedCamera().get()
    379                           .triggerFocusAndMeterAtPoint(
    380                                 new PointF(points[0], points[1]));
    381                 }
    382 
    383                 return NO_CHANGE;
    384             }
    385         };
    386         setEventHandler(EventTapOnPreview.class, tapOnPreviewHandler);
    387 
    388         /** Handles EventZoomRatioChanged. */
    389         EventHandler<EventZoomRatioChanged> zoomRatioChangedHandler =
    390                 new EventHandler<EventZoomRatioChanged>() {
    391                     @Override
    392                     public Optional<State> processEvent(EventZoomRatioChanged event) {
    393                         mResourceCaptureTools.get().getResourceOpenedCamera().get().setZoomRatio(
    394                                 event.getZoomRatio());
    395                         return NO_CHANGE;
    396                     }
    397                 };
    398         setEventHandler(EventZoomRatioChanged.class, zoomRatioChangedHandler);
    399 
    400         /** Handles EventPictureCompressed. */
    401         EventHandler<EventPictureCompressed> pictureCompressedHandler =
    402                 new EventHandler<EventPictureCompressed>() {
    403                     @Override
    404                     public Optional<State> processEvent(EventPictureCompressed event) {
    405                         if (mIsTakingPicture) {
    406                             mIsTakingPicture = false;
    407                             mIsDecodingPicture = true;
    408 
    409                             final byte[] pictureData = event.getPictureData();
    410                             final int pictureOrientation = event.getOrientation();
    411                             mResourceCaptureTools.get().getResourceConstructed().get().getCameraHandler().post(
    412                                     new Runnable() {
    413                                         @Override
    414                                         public void run() {
    415                                             final Bitmap pictureBitmap = PictureDecoder.decode(
    416                                                     pictureData,
    417                                                     CaptureIntentConfig.DOWN_SAMPLE_FACTOR,
    418                                                     pictureOrientation,
    419                                                     false);
    420                                             getStateMachine().processEvent(
    421                                                     new EventPictureDecoded(pictureBitmap, pictureData));
    422                                         }
    423                                     });
    424                         }
    425                         return NO_CHANGE;
    426                     }
    427                 };
    428         setEventHandler(EventPictureCompressed.class, pictureCompressedHandler);
    429 
    430         /** Handles EventPictureDecoded. */
    431         EventHandler<EventPictureDecoded> pictureDecodedHandler =
    432                 new EventHandler<EventPictureDecoded>() {
    433                     @Override
    434                     public Optional<State> processEvent(EventPictureDecoded event) {
    435                         // Do nothing if we are not in the decoding image sub-state. There is a
    436                         // chance that EventPictureDecoded for an old image might come after people
    437                         // hitting retake button. We have to ignore it or it will take us to
    438                         // StateReviewingPicture.
    439                         if (!mIsDecodingPicture) {
    440                             return NO_CHANGE;
    441                         }
    442 
    443                         mIsDecodingPicture = false;
    444                         return Optional.of((State) StateReviewingPicture.from(
    445                                 StateReadyForCapture.this, mResourceCaptureTools,
    446                                 event.getPictureBitmap(), Optional.of(event.getPictureData())));
    447                     }
    448                 };
    449         setEventHandler(EventPictureDecoded.class, pictureDecodedHandler);
    450 
    451         /** Handles EventFastPictureBitmapAvailable. */
    452         EventHandler<EventFastPictureBitmapAvailable> fastPictureBitmapAvailableHandler =
    453                 new EventHandler<EventFastPictureBitmapAvailable>() {
    454                     @Override
    455                     public Optional<State> processEvent(EventFastPictureBitmapAvailable event) {
    456                         if (mIsTakingPicture && !mIsDecodingPicture) {
    457                             return Optional.of((State) StateReviewingPicture.from(
    458                                     StateReadyForCapture.this, mResourceCaptureTools,
    459                                     event.getThumbnailBitmap(), Optional.<byte[]>absent()));
    460                         }
    461                         return NO_CHANGE;
    462                     }
    463                 };
    464         setEventHandler(EventFastPictureBitmapAvailable.class, fastPictureBitmapAvailableHandler);
    465 
    466         /** Handles EventCameraQuickExpose. */
    467         EventHandler<EventCameraQuickExpose> cameraQuickExposeHandler =
    468                 new EventHandler<EventCameraQuickExpose>() {
    469                     @Override
    470                     public Optional<State> processEvent(EventCameraQuickExpose event) {
    471                         if (mIsTakingPicture) {
    472                             mResourceCaptureTools.get().getMainThread().execute(new Runnable() {
    473                                 @Override
    474                                 public void run() {
    475 
    476                                     ResourceConstructed resourceConstructed =
    477                                             mResourceCaptureTools.get().getResourceConstructed()
    478                                                     .get();
    479                                     // Freeze the screen.
    480                                     resourceConstructed.getModuleUI()
    481                                             .freezeScreenUntilPreviewReady();
    482                                     // Disable shutter button.
    483                                     mResourceCaptureTools.get().getModuleUI()
    484                                             .setShutterButtonEnabled(false);
    485                                     // Starts the short version of the capture animation UI.
    486                                     mResourceCaptureTools.get().getModuleUI()
    487                                             .startFlashAnimation(true);
    488                                     mResourceCaptureTools.get().getMediaActionSound().play(
    489                                             MediaActionSound.SHUTTER_CLICK);
    490                                 }
    491                             });
    492                         }
    493                         return NO_CHANGE;
    494                     }
    495                 };
    496         setEventHandler(EventCameraQuickExpose.class, cameraQuickExposeHandler);
    497 
    498         /** Handles EventTapOnCancelShutterButton. */
    499         EventHandler<EventTapOnCancelShutterButton> tapOnCancelShutterButtonHandler =
    500                 new EventHandler<EventTapOnCancelShutterButton>() {
    501                     @Override
    502                     public Optional<State> processEvent(EventTapOnCancelShutterButton event) {
    503                         cancelCountDown();
    504                         return NO_CHANGE;
    505                     }
    506                 };
    507         setEventHandler(EventTapOnCancelShutterButton.class, tapOnCancelShutterButtonHandler);
    508     }
    509 
    510     @Override
    511     public Optional<State> onEnter() {
    512         // Register various listeners. These will be unregistered in onLeave().
    513         final OneCamera camera =
    514                 mResourceCaptureTools.get().getResourceOpenedCamera().get().getCamera();
    515         camera.setFocusDistanceListener(mResourceCaptureTools.get().getFocusController());
    516         camera.setFocusStateListener(mFocusStateListener);
    517         camera.setReadyStateChangedListener(mReadyStateChangedListener);
    518         mResourceCaptureTools.get().getCaptureSessionManager()
    519                 .addSessionListener(mCaptureSessionListener);
    520 
    521         // Display capture UI.
    522         mResourceCaptureTools.get().getMainThread().execute(new Runnable() {
    523             @Override
    524             public void run() {
    525                 mResourceCaptureTools.get().getModuleUI().cancelCountDown();
    526                 mResourceCaptureTools.get().getModuleUI().showPictureCaptureUI();
    527                 mResourceCaptureTools.get().getModuleUI().initializeZoom(
    528                         mResourceCaptureTools.get().getResourceOpenedCamera().get().getZoomRatio());
    529             }
    530         });
    531         return NO_CHANGE;
    532     }
    533 
    534     @Override
    535     public void onLeave() {
    536         final OneCamera camera =
    537                 mResourceCaptureTools.get().getResourceOpenedCamera().get().getCamera();
    538         camera.setFocusDistanceListener(null);
    539         camera.setFocusStateListener(null);
    540         camera.setReadyStateChangedListener(null);
    541 
    542         mResourceCaptureTools.get().getCaptureSessionManager()
    543                 .removeSessionListener(mCaptureSessionListener);
    544         mResourceCaptureTools.close();
    545     }
    546 
    547     private void onFocusStateUpdated(OneCamera.AutoFocusState focusState) {
    548         final FocusController focusController = mResourceCaptureTools.get().getFocusController();
    549         switch (focusState) {
    550             case PASSIVE_SCAN:
    551                 focusController.showPassiveFocusAtCenter();
    552                 break;
    553             case ACTIVE_SCAN:
    554                 break;
    555             case PASSIVE_FOCUSED:
    556             case PASSIVE_UNFOCUSED:
    557                 focusController.clearFocusIndicator();
    558                 break;
    559             case ACTIVE_FOCUSED:
    560             case ACTIVE_UNFOCUSED:
    561                 focusController.clearFocusIndicator();
    562                 break;
    563         }
    564     }
    565 
    566     private final OneCamera.FocusStateListener mFocusStateListener =
    567             new OneCamera.FocusStateListener() {
    568                 @Override
    569                 public void onFocusStatusUpdate(final OneCamera.AutoFocusState focusState,
    570                         final long frameNumber) {
    571                     onFocusStateUpdated(focusState);
    572                 }
    573             };
    574 
    575     private final EventHandler<EventCameraBusy> mEventCameraBusyHandler =
    576             new EventHandler<EventCameraBusy>() {
    577                 @Override
    578                 public Optional<State> processEvent(EventCameraBusy event) {
    579                     mResourceCaptureTools.get().getMainThread().execute(new Runnable() {
    580                         @Override
    581                         public void run() {
    582                             mResourceCaptureTools.get().getModuleUI().setShutterButtonEnabled(
    583                                     false);
    584                         }
    585                     });
    586                     return NO_CHANGE;
    587                 }
    588             };
    589 
    590     private final EventHandler<EventCameraReady> mEventCameraReadyHandler =
    591             new EventHandler<EventCameraReady>() {
    592                 @Override
    593                 public Optional<State> processEvent(EventCameraReady event) {
    594                     mResourceCaptureTools.get().getMainThread().execute(new Runnable() {
    595                         @Override
    596                         public void run() {
    597                             mResourceCaptureTools.get().getModuleUI().setShutterButtonEnabled(true);
    598                         }
    599                     });
    600                     return NO_CHANGE;
    601                 }
    602             };
    603 
    604     private final OneCamera.ReadyStateChangedListener mReadyStateChangedListener =
    605             new OneCamera.ReadyStateChangedListener() {
    606                 /**
    607                  * Called when the camera is either ready or not ready to take a picture
    608                  * right now.
    609                  */
    610                 @Override
    611                 public void onReadyStateChanged(final boolean readyForCapture) {
    612                     if (readyForCapture) {
    613                         getStateMachine().processEvent(new EventCameraReady());
    614                     } else {
    615                         getStateMachine().processEvent(new EventCameraBusy());
    616                     }
    617                 }
    618             };
    619 
    620     private final OneCamera.PictureCallback mPictureCallback = new OneCamera.PictureCallback() {
    621         @Override
    622         public void onQuickExpose() {
    623             getStateMachine().processEvent(new EventCameraQuickExpose());
    624         }
    625 
    626         @Override
    627         public void onThumbnailResult(byte[] jpegData) {
    628         }
    629 
    630         @Override
    631         public void onPictureTaken(CaptureSession session) {
    632         }
    633 
    634         @Override
    635         public void onPictureSaved(Uri uri) {
    636         }
    637 
    638         @Override
    639         public void onPictureTakingFailed() {
    640         }
    641 
    642         @Override
    643         public void onTakePictureProgress(float progress) {
    644         }
    645     };
    646 
    647     private final CaptureSessionManager.SessionListener mCaptureSessionListener =
    648             new CaptureSessionManager.SessionListener() {
    649                 @Override
    650                 public void onSessionThumbnailUpdate(Bitmap thumbnailBitmap) {
    651                     getStateMachine().processEvent(
    652                             new EventFastPictureBitmapAvailable(thumbnailBitmap));
    653                 }
    654 
    655                 @Override
    656                 public void onSessionPictureDataUpdate(byte[] pictureData, int orientation) {
    657                     getStateMachine().processEvent(
    658                             new EventPictureCompressed(pictureData, orientation));
    659                 }
    660 
    661                 @Override
    662                 public void onSessionQueued(Uri sessionUri) {
    663                 }
    664 
    665                 @Override
    666                 public void onSessionUpdated(Uri sessionUri) {
    667                 }
    668 
    669                 @Override
    670                 public void onSessionCaptureIndicatorUpdate(Bitmap bitmap, int rotationDegrees) {
    671                 }
    672 
    673                 @Override
    674                 public void onSessionDone(Uri sessionUri) {
    675                 }
    676 
    677                 @Override
    678                 public void onSessionFailed(Uri sessionUri, int failureMessageId,
    679                         boolean removeFromFilmstrip) {
    680                 }
    681 
    682                 @Override
    683                 public void onSessionCanceled(Uri mediaUri) {
    684                 }
    685 
    686                 @Override
    687                 public void onSessionProgress(Uri sessionUri, int progress) {
    688                 }
    689 
    690                 @Override
    691                 public void onSessionProgressText(Uri sessionUri, int messageId) {
    692                 }
    693             };
    694 }