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 }