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 onCameraClosed() { 82 // Not used anymore. 83 } 84 85 @Override 86 public void onCameraOpened(@Nonnull final OneCamera camera) { 87 getStateMachine().processEvent(new EventOnOpenCameraSucceeded(camera)); 88 } 89 }; 90 from( State previousState, RefCountBase<ResourceConstructed> resourceConstructed, RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, OneCamera.Facing cameraFacing, CameraId cameraId, OneCameraCharacteristics cameraCharacteristics)91 public static StateOpeningCamera from( 92 State previousState, 93 RefCountBase<ResourceConstructed> resourceConstructed, 94 RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, 95 OneCamera.Facing cameraFacing, 96 CameraId cameraId, 97 OneCameraCharacteristics cameraCharacteristics) { 98 return new StateOpeningCamera(previousState, resourceConstructed, 99 resourceSurfaceTexture, cameraFacing, cameraId, cameraCharacteristics); 100 } 101 StateOpeningCamera(State previousState, RefCountBase<ResourceConstructed> resourceConstructed, RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, OneCamera.Facing cameraFacing, CameraId cameraId, OneCameraCharacteristics cameraCharacteristics)102 private StateOpeningCamera(State previousState, 103 RefCountBase<ResourceConstructed> resourceConstructed, 104 RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, 105 OneCamera.Facing cameraFacing, 106 CameraId cameraId, 107 OneCameraCharacteristics cameraCharacteristics) { 108 super(previousState); 109 mResourceConstructed = resourceConstructed; 110 mResourceConstructed.addRef(); // Will be balanced in onLeave(). 111 mResourceSurfaceTexture = resourceSurfaceTexture; 112 mResourceSurfaceTexture.addRef(); // Will be balanced in onLeave(). 113 mCameraFacing = cameraFacing; 114 mCameraId = cameraId; 115 mCameraCharacteristics = cameraCharacteristics; 116 mIsPaused = false; 117 mCameraSettingsScope = SettingsManager.getCameraSettingScope(mCameraId.getValue()); 118 registerEventHandlers(); 119 } 120 registerEventHandlers()121 private void registerEventHandlers() { 122 /** Handles EventPause. */ 123 EventHandler<EventPause> pauseHandler = new EventHandler<EventPause>() { 124 @Override 125 public Optional<State> processEvent(EventPause event) { 126 mIsPaused = true; 127 return NO_CHANGE; 128 } 129 }; 130 setEventHandler(EventPause.class, pauseHandler); 131 132 /** Handles EventOnOpenCameraSucceeded. */ 133 EventHandler<EventOnOpenCameraSucceeded> onOpenCameraSucceededHandler = 134 new EventHandler<EventOnOpenCameraSucceeded>() { 135 @Override 136 public Optional<State> processEvent(EventOnOpenCameraSucceeded event) { 137 final OneCamera camera = event.getCamera(); 138 if (mIsPaused) { 139 // Just close the camera and finish. 140 camera.close(); 141 return Optional.of((State) StateBackgroundWithSurfaceTexture.from( 142 StateOpeningCamera.this, 143 mResourceConstructed, 144 mResourceSurfaceTexture)); 145 } 146 147 mResourceConstructed.get().getMainThread().execute(new Runnable() { 148 @Override 149 public void run() { 150 mResourceConstructed.get().getModuleUI().applyModuleSpecs( 151 getHardwareSpec(), getBottomBarSpec()); 152 } 153 }); 154 155 return Optional.of((State) StateStartingPreview.from( 156 StateOpeningCamera.this, 157 mResourceConstructed, 158 mResourceSurfaceTexture, 159 camera, 160 mCameraId, 161 mCameraFacing, 162 mCameraCharacteristics, 163 mPictureSize, 164 mOneCameraCaptureSetting)); 165 } 166 }; 167 setEventHandler(EventOnOpenCameraSucceeded.class, onOpenCameraSucceededHandler); 168 169 /** Handles EventOnOpenCameraFailed. */ 170 EventHandler<EventOnOpenCameraFailed> onOpenCameraFailedHandler = 171 new EventHandler<EventOnOpenCameraFailed>() { 172 @Override 173 public Optional<State> processEvent(EventOnOpenCameraFailed event) { 174 Log.e(TAG, "processOnCameraOpenFailure"); 175 return Optional.of((State) StateFatal.from( 176 StateOpeningCamera.this, mResourceConstructed)); 177 } 178 }; 179 setEventHandler(EventOnOpenCameraFailed.class, onOpenCameraFailedHandler); 180 } 181 182 @Override onEnter()183 public Optional<State> onEnter() { 184 if (mCameraCharacteristics == null) { 185 Log.e(TAG, "mCameraCharacteristics is null"); 186 return Optional.of((State) StateFatal.from(this, mResourceConstructed)); 187 } 188 try { 189 mPictureSize = mResourceConstructed.get().getResolutionSetting().getPictureSize( 190 mCameraId, mCameraFacing); 191 mOneCameraCaptureSetting = OneCameraCaptureSetting.create( 192 mPictureSize, 193 mResourceConstructed.get().getAppController().getSettingsManager(), 194 getHardwareSpec(), 195 mCameraSettingsScope, 196 false); 197 } catch (OneCameraAccessException ex) { 198 Log.e(TAG, "Failed while open camera", ex); 199 return Optional.of((State) StateFatal.from(this, mResourceConstructed)); 200 } 201 202 final ImageRotationCalculator imageRotationCalculator = ImageRotationCalculatorImpl.from( 203 mResourceConstructed.get().getOrientationManager(), mCameraCharacteristics); 204 205 mResourceConstructed.get().getOneCameraOpener().open( 206 mCameraId, 207 mOneCameraCaptureSetting, 208 mResourceConstructed.get().getCameraHandler(), 209 mResourceConstructed.get().getMainThread(), 210 imageRotationCalculator, 211 mResourceConstructed.get().getBurstFacade(), 212 mResourceConstructed.get().getSoundPlayer(), 213 mCameraOpenCallback, 214 mResourceConstructed.get().getFatalErrorHandler()); 215 return Optional.absent(); 216 } 217 218 @Override onLeave()219 public void onLeave() { 220 mResourceConstructed.close(); 221 mResourceSurfaceTexture.close(); 222 } 223 224 @VisibleForTesting isPaused()225 public boolean isPaused() { 226 return mIsPaused; 227 } 228 getHardwareSpec()229 private HardwareSpec getHardwareSpec() { 230 return new HardwareSpec() { 231 @Override 232 public boolean isFrontCameraSupported() { 233 return mResourceConstructed.get() 234 .getOneCameraManager().hasCameraFacing(OneCamera.Facing.FRONT); 235 } 236 237 @Override 238 public boolean isHdrSupported() { 239 return false; 240 } 241 242 @Override 243 public boolean isHdrPlusSupported() { 244 return false; 245 } 246 247 @Override 248 public boolean isFlashSupported() { 249 return mCameraCharacteristics.isFlashSupported(); 250 } 251 }; 252 } 253 254 private CameraAppUI.BottomBarUISpec getBottomBarSpec() { 255 CameraAppUI.BottomBarUISpec bottomBarSpec = new CameraAppUI.BottomBarUISpec(); 256 /** Camera switch button UI spec. */ 257 bottomBarSpec.enableCamera = true; 258 bottomBarSpec.cameraCallback = new ButtonManager.ButtonCallback() { 259 @Override 260 public void onStateChanged(int cameraId) { 261 getStateMachine().processEvent(new EventTapOnSwitchCameraButton()); 262 } 263 }; 264 /** Grid lines button UI spec. */ 265 bottomBarSpec.enableGridLines = true; 266 /** HDR button UI spec. */ 267 bottomBarSpec.enableHdr = false; 268 bottomBarSpec.hideHdr = true; 269 bottomBarSpec.hdrCallback = null; 270 /** Timer button UI spec. */ 271 bottomBarSpec.enableSelfTimer = true; 272 bottomBarSpec.showSelfTimer = true; 273 /** Flash button UI spec. */ 274 bottomBarSpec.enableFlash = mCameraCharacteristics.isFlashSupported(); 275 276 /** Setup exposure compensation */ 277 bottomBarSpec.isExposureCompensationSupported = mCameraCharacteristics 278 .isExposureCompensationSupported(); 279 bottomBarSpec.enableExposureCompensation = bottomBarSpec.isExposureCompensationSupported; 280 bottomBarSpec.minExposureCompensation = 281 mCameraCharacteristics.getMinExposureCompensation(); 282 bottomBarSpec.maxExposureCompensation = 283 mCameraCharacteristics.getMaxExposureCompensation(); 284 bottomBarSpec.exposureCompensationStep = 285 mCameraCharacteristics.getExposureCompensationStep(); 286 bottomBarSpec.exposureCompensationSetCallback = 287 new CameraAppUI.BottomBarUISpec.ExposureCompensationSetCallback() { 288 @Override 289 public void setExposure(int value) { 290 mResourceConstructed.get().getSettingsManager().set( 291 mCameraSettingsScope, Keys.KEY_EXPOSURE, value); 292 } 293 }; 294 295 /** Intent image review UI spec. */ 296 bottomBarSpec.showCancel = true; 297 bottomBarSpec.cancelCallback = new View.OnClickListener() { 298 @Override 299 public void onClick(View v) { 300 getStateMachine().processEvent(new EventTapOnCancelIntentButton()); 301 } 302 }; 303 bottomBarSpec.showDone = true; 304 bottomBarSpec.doneCallback = new View.OnClickListener() { 305 @Override 306 public void onClick(View v) { 307 getStateMachine().processEvent(new EventTapOnConfirmPhotoButton()); 308 } 309 }; 310 bottomBarSpec.showRetake = true; 311 bottomBarSpec.retakeCallback = new View.OnClickListener() { 312 @Override 313 public void onClick(View v) { 314 getStateMachine().processEvent(new EventTapOnRetakePhotoButton()); 315 } 316 }; 317 return bottomBarSpec; 318 } 319 } 320