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