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