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 com.android.camera.CaptureModuleUtil; 20 import com.android.camera.async.RefCountBase; 21 import com.android.camera.captureintent.event.EventOnStartPreviewFailed; 22 import com.android.camera.captureintent.event.EventOnStartPreviewSucceeded; 23 import com.android.camera.captureintent.event.EventOnTextureViewLayoutChanged; 24 import com.android.camera.captureintent.event.EventPause; 25 import com.android.camera.captureintent.resource.ResourceConstructed; 26 import com.android.camera.captureintent.resource.ResourceOpenedCamera; 27 import com.android.camera.captureintent.resource.ResourceOpenedCameraImpl; 28 import com.android.camera.captureintent.resource.ResourceSurfaceTexture; 29 import com.android.camera.captureintent.stateful.EventHandler; 30 import com.android.camera.captureintent.stateful.State; 31 import com.android.camera.captureintent.stateful.StateImpl; 32 import com.android.camera.debug.Log; 33 import com.android.camera.device.CameraId; 34 import com.android.camera.exif.Rational; 35 import com.android.camera.one.OneCamera; 36 import com.android.camera.one.OneCameraAccessException; 37 import com.android.camera.one.OneCameraCaptureSetting; 38 import com.android.camera.one.OneCameraCharacteristics; 39 import com.android.camera.util.Size; 40 import com.google.common.base.Optional; 41 42 import java.util.List; 43 44 /** 45 * Represents a state that the module is waiting for the preview video stream 46 * to be started. 47 */ 48 public final class StateStartingPreview extends StateImpl { 49 private static final Log.Tag TAG = new Log.Tag("StStartingPreview"); 50 51 private final RefCountBase<ResourceConstructed> mResourceConstructed; 52 private final RefCountBase<ResourceSurfaceTexture> mResourceSurfaceTexture; 53 private final RefCountBase<ResourceOpenedCamera> mResourceOpenedCamera; 54 from( State previousState, RefCountBase<ResourceConstructed> resourceConstructed, RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, OneCamera camera, CameraId cameraId, OneCamera.Facing cameraFacing, OneCameraCharacteristics cameraCharacteristics, Size pictureSize, OneCameraCaptureSetting captureSetting)55 public static StateStartingPreview from( 56 State previousState, 57 RefCountBase<ResourceConstructed> resourceConstructed, 58 RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, 59 OneCamera camera, 60 CameraId cameraId, 61 OneCamera.Facing cameraFacing, 62 OneCameraCharacteristics cameraCharacteristics, 63 Size pictureSize, 64 OneCameraCaptureSetting captureSetting) { 65 return new StateStartingPreview( 66 previousState, 67 resourceConstructed, 68 resourceSurfaceTexture, 69 camera, 70 cameraId, 71 cameraFacing, 72 cameraCharacteristics, 73 pictureSize, 74 captureSetting); 75 } 76 StateStartingPreview( State previousState, RefCountBase<ResourceConstructed> resourceConstructed, RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, OneCamera camera, CameraId cameraId, OneCamera.Facing cameraFacing, OneCameraCharacteristics cameraCharacteristics, Size pictureSize, OneCameraCaptureSetting captureSetting)77 private StateStartingPreview( 78 State previousState, 79 RefCountBase<ResourceConstructed> resourceConstructed, 80 RefCountBase<ResourceSurfaceTexture> resourceSurfaceTexture, 81 OneCamera camera, 82 CameraId cameraId, 83 OneCamera.Facing cameraFacing, 84 OneCameraCharacteristics cameraCharacteristics, 85 Size pictureSize, 86 OneCameraCaptureSetting captureSetting) { 87 super(previousState); 88 mResourceConstructed = resourceConstructed; 89 mResourceConstructed.addRef(); // Will be balanced in onLeave(). 90 mResourceSurfaceTexture = resourceSurfaceTexture; 91 mResourceSurfaceTexture.addRef(); // Will be balanced in onLeave(). 92 mResourceOpenedCamera = ResourceOpenedCameraImpl.create( 93 camera, cameraId, cameraFacing, cameraCharacteristics, pictureSize, captureSetting); 94 registerEventHandlers(); 95 } 96 registerEventHandlers()97 public void registerEventHandlers() { 98 /** Handles EventPause. */ 99 EventHandler<EventPause> pauseHandler = new EventHandler<EventPause>() { 100 @Override 101 public Optional<State> processEvent(EventPause event) { 102 return Optional.of((State) StateBackgroundWithSurfaceTexture.from( 103 StateStartingPreview.this, 104 mResourceConstructed, 105 mResourceSurfaceTexture)); 106 } 107 }; 108 setEventHandler(EventPause.class, pauseHandler); 109 110 /** Handles EventOnTextureViewLayoutChanged. */ 111 EventHandler<EventOnTextureViewLayoutChanged> onTextureViewLayoutChangedHandler = 112 new EventHandler<EventOnTextureViewLayoutChanged>() { 113 @Override 114 public Optional<State> processEvent(EventOnTextureViewLayoutChanged event) { 115 mResourceSurfaceTexture.get().setPreviewLayoutSize(event.getLayoutSize()); 116 return NO_CHANGE; 117 } 118 }; 119 setEventHandler(EventOnTextureViewLayoutChanged.class, onTextureViewLayoutChangedHandler); 120 121 /** Handles EventOnStartPreviewSucceeded. */ 122 EventHandler<EventOnStartPreviewSucceeded> onStartPreviewSucceededHandler = 123 new EventHandler<EventOnStartPreviewSucceeded>() { 124 @Override 125 public Optional<State> processEvent(EventOnStartPreviewSucceeded event) { 126 mResourceConstructed.get().getMainThread().execute(new Runnable() { 127 @Override 128 public void run() { 129 mResourceConstructed.get().getModuleUI().onPreviewStarted(); 130 } 131 }); 132 return Optional.of((State) StateReadyForCapture.from( 133 StateStartingPreview.this, 134 mResourceConstructed, 135 mResourceSurfaceTexture, 136 mResourceOpenedCamera)); 137 } 138 }; 139 setEventHandler(EventOnStartPreviewSucceeded.class, onStartPreviewSucceededHandler); 140 141 /** Handles EventOnStartPreviewFailed. */ 142 EventHandler<EventOnStartPreviewFailed> onStartPreviewFailedHandler = 143 new EventHandler<EventOnStartPreviewFailed>() { 144 @Override 145 public Optional<State> processEvent(EventOnStartPreviewFailed event) { 146 Log.e(TAG, "processOnPreviewSetupFailed"); 147 return Optional.of((State) StateFatal.from( 148 StateStartingPreview.this, mResourceConstructed)); 149 } 150 }; 151 setEventHandler(EventOnStartPreviewFailed.class, onStartPreviewFailedHandler); 152 } 153 154 @Override onEnter()155 public Optional<State> onEnter() { 156 final Size previewSize; 157 try { 158 // Pick a preview size with the right aspect ratio. 159 final List<Size> supportedPreviewSizes = mResourceOpenedCamera.get() 160 .getCameraCharacteristics().getSupportedPreviewSizes(); 161 if (supportedPreviewSizes.isEmpty()) { 162 return Optional.of((State) StateFatal.from(this, mResourceConstructed)); 163 } 164 165 final Rational pictureAspectRatio = 166 mResourceConstructed.get().getResolutionSetting().getPictureAspectRatio( 167 mResourceOpenedCamera.get().getCameraId(), 168 mResourceOpenedCamera.get().getCameraFacing()); 169 previewSize = CaptureModuleUtil.getOptimalPreviewSize( 170 supportedPreviewSizes.toArray(new Size[(supportedPreviewSizes.size())]), 171 pictureAspectRatio.toDouble(), 172 null); 173 if (previewSize == null) { 174 // TODO: Try to avoid entering StateFatal by seeing if there is 175 // another way to get the correct preview size. 176 return Optional.of((State) StateFatal.from(this, mResourceConstructed)); 177 } 178 } catch (OneCameraAccessException ex) { 179 return Optional.of((State) StateFatal.from(this, mResourceConstructed)); 180 } 181 182 // Must do this before calling ResourceOpenedCamera.startPreview() 183 // since SurfaceTexture.setDefaultBufferSize() needs to be called 184 // before starting preview. Otherwise the size of preview video stream 185 // will be wrong. 186 mResourceSurfaceTexture.get().setPreviewSize(previewSize); 187 188 OneCamera.CaptureReadyCallback captureReadyCallback = 189 new OneCamera.CaptureReadyCallback() { 190 @Override 191 public void onSetupFailed() { 192 getStateMachine().processEvent(new EventOnStartPreviewFailed()); 193 } 194 195 @Override 196 public void onReadyForCapture() { 197 getStateMachine().processEvent(new EventOnStartPreviewSucceeded()); 198 } 199 }; 200 201 // Start preview right away. Don't dispatch it on other threads or it 202 // will cause race condition. b/19522251. 203 mResourceOpenedCamera.get().startPreview( 204 mResourceSurfaceTexture.get().createPreviewSurface(), captureReadyCallback); 205 return Optional.absent(); 206 } 207 208 @Override onLeave()209 public void onLeave() { 210 mResourceConstructed.close(); 211 mResourceSurfaceTexture.close(); 212 mResourceOpenedCamera.close(); 213 } 214 } 215