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 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 
     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 
    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 
    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
    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
    219     public void onLeave() {
    220         mResourceConstructed.close();
    221         mResourceSurfaceTexture.close();
    222     }
    223 
    224     @VisibleForTesting
    225     public boolean isPaused() {
    226         return mIsPaused;
    227     }
    228 
    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