Home | History | Annotate | Download | only in state
      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 
     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 
     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 
     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
    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
    209     public void onLeave() {
    210         mResourceConstructed.close();
    211         mResourceSurfaceTexture.close();
    212         mResourceOpenedCamera.close();
    213     }
    214 }
    215