• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
from( StateStartingPreview startingPreview, RefCountBase<ResourceConstructed> resourceConstructed, RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, RefCountBase<ResourceOpenedCamera> resourceOpenedCamera)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 
from( StateReviewingPicture reviewingPicture, RefCountBase<ResourceCaptureTools> resourceCaptureTools)100     public static StateReadyForCapture from(
101             StateReviewingPicture reviewingPicture,
102             RefCountBase<ResourceCaptureTools> resourceCaptureTools) {
103         return new StateReadyForCapture(reviewingPicture, resourceCaptureTools);
104     }
105 
StateReadyForCapture( State previousState, RefCountBase<ResourceConstructed> resourceConstructed, RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, RefCountBase<ResourceOpenedCamera> resourceOpenedCamera)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 
StateReadyForCapture( State previousState, RefCountBase<ResourceCaptureTools> resourceCaptureTools)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 
takePicture(@ullable final TouchCoordinate touchPointInsideShutterButton)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 
startCountDown( final int countDownDuration, final ResourceCaptureTools.CaptureLoggingInfo captureLoggingInfo)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 
cancelCountDown()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 
takePictureNow(ResourceCaptureTools.CaptureLoggingInfo captureLoggingInfo)204     private void takePictureNow(ResourceCaptureTools.CaptureLoggingInfo captureLoggingInfo) {
205         mIsTakingPicture = true;
206         mResourceCaptureTools.get().takePictureNow(mPictureCallback, captureLoggingInfo);
207     }
208 
registerEventHandlers()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
onEnter()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
onLeave()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 
onFocusStateUpdated(OneCamera.AutoFocusState focusState)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 }