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.view.View; 20 21 import com.android.camera.ButtonManager; 22 import com.android.camera.app.CameraAppUI; 23 import com.android.camera.async.RefCountBase; 24 import com.android.camera.captureintent.event.EventOnOpenCameraFailed; 25 import com.android.camera.captureintent.event.EventOnOpenCameraSucceeded; 26 import com.android.camera.captureintent.event.EventPause; 27 import com.android.camera.captureintent.event.EventTapOnCancelIntentButton; 28 import com.android.camera.captureintent.event.EventTapOnConfirmPhotoButton; 29 import com.android.camera.captureintent.event.EventTapOnRetakePhotoButton; 30 import com.android.camera.captureintent.event.EventTapOnSwitchCameraButton; 31 import com.android.camera.captureintent.resource.ResourceConstructed; 32 import com.android.camera.captureintent.resource.ResourceSurfaceTexture; 33 import com.android.camera.captureintent.stateful.EventHandler; 34 import com.android.camera.captureintent.stateful.State; 35 import com.android.camera.captureintent.stateful.StateImpl; 36 import com.android.camera.debug.Log; 37 import com.android.camera.device.CameraId; 38 import com.android.camera.hardware.HardwareSpec; 39 import com.android.camera.one.OneCamera; 40 import com.android.camera.one.OneCameraAccessException; 41 import com.android.camera.one.OneCameraCaptureSetting; 42 import com.android.camera.one.OneCameraCharacteristics; 43 import com.android.camera.one.v2.photo.ImageRotationCalculator; 44 import com.android.camera.one.v2.photo.ImageRotationCalculatorImpl; 45 import com.android.camera.settings.Keys; 46 import com.android.camera.settings.SettingsManager; 47 import com.android.camera.util.Size; 48 import com.google.common.annotations.VisibleForTesting; 49 import com.google.common.base.Optional; 50 51 import javax.annotation.Nonnull; 52 53 /** 54 * Represents a state that the module is waiting for a camera to be opened. 55 */ 56 public final class StateOpeningCamera extends StateImpl { 57 private static final Log.Tag TAG = new Log.Tag("StateOpeningCamera"); 58 59 private final RefCountBase<ResourceConstructed> mResourceConstructed; 60 private final RefCountBase<ResourceSurfaceTexture> mResourceSurfaceTexture; 61 private final OneCamera.Facing mCameraFacing; 62 private final CameraId mCameraId; 63 private final OneCameraCharacteristics mCameraCharacteristics; 64 private final String mCameraSettingsScope; 65 66 /** The desired picture size. */ 67 private Size mPictureSize; 68 69 /** Whether is paused in the middle of opening camera. */ 70 private boolean mIsPaused; 71 72 private OneCameraCaptureSetting mOneCameraCaptureSetting; 73 74 private OneCamera.OpenCallback mCameraOpenCallback = new OneCamera.OpenCallback() { 75 @Override 76 public void onFailure() { 77 getStateMachine().processEvent(new EventOnOpenCameraFailed()); 78 } 79 80 @Override 81 public void onCameraInUse() { 82 getStateMachine().processEvent(new EventOnOpenCameraFailed()); 83 } 84 85 @Override 86 public void onCameraClosed() { 87 // Not used anymore. 88 } 89 90 @Override 91 public void onCameraInterrupted() { 92 // Not used. 93 } 94 95 @Override 96 public void onCameraOpened(@Nonnull final OneCamera camera) { 97 getStateMachine().processEvent(new EventOnOpenCameraSucceeded(camera)); 98 } 99 }; 100 from( State previousState, RefCountBase<ResourceConstructed> resourceConstructed, RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, OneCamera.Facing cameraFacing, CameraId cameraId, OneCameraCharacteristics cameraCharacteristics)101 public static StateOpeningCamera from( 102 State previousState, 103 RefCountBase<ResourceConstructed> resourceConstructed, 104 RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, 105 OneCamera.Facing cameraFacing, 106 CameraId cameraId, 107 OneCameraCharacteristics cameraCharacteristics) { 108 return new StateOpeningCamera(previousState, resourceConstructed, 109 resourceSurfaceTexture, cameraFacing, cameraId, cameraCharacteristics); 110 } 111 StateOpeningCamera(State previousState, RefCountBase<ResourceConstructed> resourceConstructed, RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, OneCamera.Facing cameraFacing, CameraId cameraId, OneCameraCharacteristics cameraCharacteristics)112 private StateOpeningCamera(State previousState, 113 RefCountBase<ResourceConstructed> resourceConstructed, 114 RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, 115 OneCamera.Facing cameraFacing, 116 CameraId cameraId, 117 OneCameraCharacteristics cameraCharacteristics) { 118 super(previousState); 119 mResourceConstructed = resourceConstructed; 120 mResourceConstructed.addRef(); // Will be balanced in onLeave(). 121 mResourceSurfaceTexture = resourceSurfaceTexture; 122 mResourceSurfaceTexture.addRef(); // Will be balanced in onLeave(). 123 mCameraFacing = cameraFacing; 124 mCameraId = cameraId; 125 mCameraCharacteristics = cameraCharacteristics; 126 mIsPaused = false; 127 mCameraSettingsScope = SettingsManager.getCameraSettingScope(mCameraId.getValue()); 128 registerEventHandlers(); 129 } 130 registerEventHandlers()131 private void registerEventHandlers() { 132 /** Handles EventPause. */ 133 EventHandler<EventPause> pauseHandler = new EventHandler<EventPause>() { 134 @Override 135 public Optional<State> processEvent(EventPause event) { 136 mIsPaused = true; 137 return NO_CHANGE; 138 } 139 }; 140 setEventHandler(EventPause.class, pauseHandler); 141 142 /** Handles EventOnOpenCameraSucceeded. */ 143 EventHandler<EventOnOpenCameraSucceeded> onOpenCameraSucceededHandler = 144 new EventHandler<EventOnOpenCameraSucceeded>() { 145 @Override 146 public Optional<State> processEvent(EventOnOpenCameraSucceeded event) { 147 final OneCamera camera = event.getCamera(); 148 if (mIsPaused) { 149 // Just close the camera and finish. 150 camera.close(); 151 return Optional.of((State) StateBackgroundWithSurfaceTexture.from( 152 StateOpeningCamera.this, 153 mResourceConstructed, 154 mResourceSurfaceTexture)); 155 } 156 157 mResourceConstructed.get().getMainThread().execute(new Runnable() { 158 @Override 159 public void run() { 160 mResourceConstructed.get().getModuleUI().applyModuleSpecs( 161 getHardwareSpec(), getBottomBarSpec()); 162 } 163 }); 164 165 return Optional.of((State) StateStartingPreview.from( 166 StateOpeningCamera.this, 167 mResourceConstructed, 168 mResourceSurfaceTexture, 169 camera, 170 mCameraId, 171 mCameraFacing, 172 mCameraCharacteristics, 173 mPictureSize, 174 mOneCameraCaptureSetting)); 175 } 176 }; 177 setEventHandler(EventOnOpenCameraSucceeded.class, onOpenCameraSucceededHandler); 178 179 /** Handles EventOnOpenCameraFailed. */ 180 EventHandler<EventOnOpenCameraFailed> onOpenCameraFailedHandler = 181 new EventHandler<EventOnOpenCameraFailed>() { 182 @Override 183 public Optional<State> processEvent(EventOnOpenCameraFailed event) { 184 Log.e(TAG, "processOnCameraOpenFailure"); 185 return Optional.of((State) StateFatal.from( 186 StateOpeningCamera.this, mResourceConstructed)); 187 } 188 }; 189 setEventHandler(EventOnOpenCameraFailed.class, onOpenCameraFailedHandler); 190 } 191 192 @Override onEnter()193 public Optional<State> onEnter() { 194 if (mCameraCharacteristics == null) { 195 Log.e(TAG, "mCameraCharacteristics is null"); 196 return Optional.of((State) StateFatal.from(this, mResourceConstructed)); 197 } 198 try { 199 mPictureSize = mResourceConstructed.get().getResolutionSetting().getPictureSize( 200 mCameraId, mCameraFacing); 201 mOneCameraCaptureSetting = OneCameraCaptureSetting.create( 202 mPictureSize, 203 mResourceConstructed.get().getAppController().getSettingsManager(), 204 getHardwareSpec(), 205 mCameraSettingsScope, 206 false); 207 } catch (OneCameraAccessException ex) { 208 Log.e(TAG, "Failed while open camera", ex); 209 return Optional.of((State) StateFatal.from(this, mResourceConstructed)); 210 } 211 212 final ImageRotationCalculator imageRotationCalculator = ImageRotationCalculatorImpl.from( 213 mResourceConstructed.get().getOrientationManager(), mCameraCharacteristics); 214 215 mResourceConstructed.get().getOneCameraOpener().open( 216 mCameraId, 217 mOneCameraCaptureSetting, 218 mResourceConstructed.get().getCameraHandler(), 219 mResourceConstructed.get().getMainThread(), 220 imageRotationCalculator, 221 mResourceConstructed.get().getBurstFacade(), 222 mResourceConstructed.get().getSoundPlayer(), 223 mCameraOpenCallback, 224 mResourceConstructed.get().getFatalErrorHandler()); 225 return Optional.absent(); 226 } 227 228 @Override onLeave()229 public void onLeave() { 230 mResourceConstructed.close(); 231 mResourceSurfaceTexture.close(); 232 } 233 234 @VisibleForTesting isPaused()235 public boolean isPaused() { 236 return mIsPaused; 237 } 238 getHardwareSpec()239 private HardwareSpec getHardwareSpec() { 240 return new HardwareSpec() { 241 @Override 242 public boolean isFrontCameraSupported() { 243 return mResourceConstructed.get() 244 .getOneCameraManager().hasCameraFacing(OneCamera.Facing.FRONT); 245 } 246 247 @Override 248 public boolean isHdrSupported() { 249 return false; 250 } 251 252 @Override 253 public boolean isHdrPlusSupported() { 254 return false; 255 } 256 257 @Override 258 public boolean isFlashSupported() { 259 return mCameraCharacteristics.isFlashSupported(); 260 } 261 }; 262 } 263 264 private CameraAppUI.BottomBarUISpec getBottomBarSpec() { 265 CameraAppUI.BottomBarUISpec bottomBarSpec = new CameraAppUI.BottomBarUISpec(); 266 /** Camera switch button UI spec. */ 267 bottomBarSpec.enableCamera = true; 268 bottomBarSpec.cameraCallback = new ButtonManager.ButtonCallback() { 269 @Override 270 public void onStateChanged(int cameraId) { 271 getStateMachine().processEvent(new EventTapOnSwitchCameraButton()); 272 } 273 }; 274 /** Grid lines button UI spec. */ 275 bottomBarSpec.enableGridLines = true; 276 /** HDR button UI spec. */ 277 bottomBarSpec.enableHdr = false; 278 bottomBarSpec.hideHdr = true; 279 bottomBarSpec.hdrCallback = null; 280 /** Timer button UI spec. */ 281 bottomBarSpec.enableSelfTimer = true; 282 bottomBarSpec.showSelfTimer = true; 283 /** Flash button UI spec. */ 284 bottomBarSpec.enableFlash = mCameraCharacteristics.isFlashSupported(); 285 286 /** Setup exposure compensation */ 287 bottomBarSpec.isExposureCompensationSupported = mCameraCharacteristics 288 .isExposureCompensationSupported(); 289 bottomBarSpec.enableExposureCompensation = bottomBarSpec.isExposureCompensationSupported; 290 bottomBarSpec.minExposureCompensation = 291 mCameraCharacteristics.getMinExposureCompensation(); 292 bottomBarSpec.maxExposureCompensation = 293 mCameraCharacteristics.getMaxExposureCompensation(); 294 bottomBarSpec.exposureCompensationStep = 295 mCameraCharacteristics.getExposureCompensationStep(); 296 bottomBarSpec.exposureCompensationSetCallback = 297 new CameraAppUI.BottomBarUISpec.ExposureCompensationSetCallback() { 298 @Override 299 public void setExposure(int value) { 300 mResourceConstructed.get().getSettingsManager().set( 301 mCameraSettingsScope, Keys.KEY_EXPOSURE, value); 302 } 303 }; 304 305 /** Intent image review UI spec. */ 306 bottomBarSpec.showCancel = true; 307 bottomBarSpec.cancelCallback = new View.OnClickListener() { 308 @Override 309 public void onClick(View v) { 310 getStateMachine().processEvent(new EventTapOnCancelIntentButton()); 311 } 312 }; 313 bottomBarSpec.showDone = true; 314 bottomBarSpec.doneCallback = new View.OnClickListener() { 315 @Override 316 public void onClick(View v) { 317 getStateMachine().processEvent(new EventTapOnConfirmPhotoButton()); 318 } 319 }; 320 bottomBarSpec.showRetake = true; 321 bottomBarSpec.retakeCallback = new View.OnClickListener() { 322 @Override 323 public void onClick(View v) { 324 getStateMachine().processEvent(new EventTapOnRetakePhotoButton()); 325 } 326 }; 327 return bottomBarSpec; 328 } 329 } 330