Home | History | Annotate | Download | only in burst
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
      5  * in compliance with the License. You may obtain a copy of the License at
      6  *
      7  * http://www.apache.org/licenses/LICENSE-2.0
      8  *
      9  * Unless required by applicable law or agreed to in writing, software distributed under the License
     10  * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
     11  * or implied. See the License for the specific language governing permissions and limitations under
     12  * the License.
     13  */
     14 
     15 package com.android.camera.burst;
     16 
     17 import android.content.Context;
     18 import android.graphics.SurfaceTexture;
     19 import android.view.Surface;
     20 
     21 import com.android.camera.app.OrientationManager.DeviceOrientation;
     22 import com.android.camera.async.MainThread;
     23 import com.android.camera.burst.BurstController.ImageStreamProperties;
     24 import com.android.camera.debug.Log;
     25 import com.android.camera.debug.Log.Tag;
     26 import com.android.camera.one.OneCamera.Facing;
     27 import com.android.camera.session.CaptureSession;
     28 import com.android.camera.session.StackSaver;
     29 
     30 import java.util.Map;
     31 import java.util.concurrent.atomic.AtomicReference;
     32 
     33 /**
     34  * Helper to manage burst, listen to burst results and saves media items.
     35  * <p/>
     36  * The UI feedback is rudimentary in form of a toast that is displayed on start
     37  * of the burst and when artifacts are saved. TODO: Move functionality of saving
     38  * burst items to a {@link com.android.camera.processing.ProcessingTask} and
     39  * change API to use {@link com.android.camera.processing.ProcessingService}.
     40  * TODO: Hook UI to the listener.
     41  */
     42 class BurstFacadeImpl implements BurstFacade {
     43     /**
     44      * The state of the burst module.
     45      */
     46     private static enum BurstModuleState {
     47         IDLE,
     48         RUNNING,
     49         STOPPING
     50     }
     51 
     52     private static final Tag TAG = new Tag("BurstFacadeImpl");
     53 
     54     private static final int DEFAULT_PREVIEW_WIDTH = 320;
     55     private static final int DEFAULT_PREVIEW_HEIGHT = 240;
     56 
     57     private final AtomicReference<BurstModuleState> mBurstModuleState =
     58             new AtomicReference<BurstModuleState>(BurstModuleState.IDLE);
     59     private final AtomicReference<BurstTaker> mBurstTaker =
     60             new AtomicReference<>(null);
     61 
     62     private final BurstController mBurstController;
     63 
     64     /** A stack saver for the outstanding burst request. */
     65     private StackSaver mActiveStackSaver;
     66 
     67     /**
     68      * Listener for burst controller. Saves the results and interacts with the
     69      * UI.
     70      */
     71     private final BurstResultsListener mBurstResultsListener =
     72             new BurstResultsListener() {
     73                 @Override
     74                 public void onBurstStarted() {
     75                 }
     76 
     77                 @Override
     78                 public void onBurstError(Exception error) {
     79                     Log.e(TAG, "Exception while running the burst" + error);
     80                 }
     81 
     82                 @Override
     83                 public void onBurstCompleted(BurstResult burstResult) {
     84                     BurstResultsSaver.saveBurstResultsInBackground(burstResult, mActiveStackSaver,
     85                             new Runnable() {
     86                         @Override
     87                         public void run() {
     88                             mBurstModuleState.set(BurstModuleState.IDLE);
     89                             }
     90                         });
     91                 }
     92 
     93                 @Override
     94                 public void onArtifactCountAvailable(
     95                         final Map<String, Integer> artifactTypeCount) {
     96                     BurstResultsSaver.logArtifactCount(artifactTypeCount);
     97                 }
     98             };
     99 
    100     private final OrientationLockController mOrientationLockController;
    101     private final BurstReadyStateChangeListener mReadyStateListener;
    102 
    103     private final AtomicReference<SurfaceTextureContainer> mSurfaceTextureContainer =
    104             new AtomicReference<>();
    105 
    106     /**
    107      * Create a new BurstManagerImpl instance.
    108      *
    109      * @param appContext the application context
    110      * @param orientationLockController for locking orientation when burst is
    111      *            running.
    112      * @param readyStateListener gets called when the ready state of Burst
    113      *            changes.
    114      */
    115     public BurstFacadeImpl(Context appContext,
    116             OrientationLockController orientationLockController,
    117             BurstReadyStateChangeListener readyStateListener) {
    118         mOrientationLockController = orientationLockController;
    119         mBurstController = new BurstControllerImpl(appContext);
    120         mReadyStateListener = readyStateListener;
    121     }
    122 
    123     @Override
    124     public void startBurst(CaptureSession.CaptureSessionCreator captureSessionCreator,
    125             DeviceOrientation deviceOrientation,
    126             Facing cameraFacing,
    127             int imageOrientationDegrees) {
    128         MainThread.checkMainThread();
    129         if (mBurstTaker.get() != null &&
    130                 mBurstModuleState.compareAndSet(BurstModuleState.IDLE,
    131                         BurstModuleState.RUNNING)) {
    132             // Only create a session if we do start a burst.
    133             CaptureSession captureSession = captureSessionCreator.createAndStartEmpty();
    134             mActiveStackSaver = captureSession.getStackSaver();
    135 
    136             mOrientationLockController.lockOrientation();
    137             // Disable the shutter button.
    138             mReadyStateListener.onBurstReadyStateChanged(false);
    139 
    140             Log.d(TAG, "Starting burst. Device orientation: " + deviceOrientation.getDegrees()
    141                     + " image orientation: " + imageOrientationDegrees);
    142             int width = DEFAULT_PREVIEW_WIDTH;
    143             int height = DEFAULT_PREVIEW_HEIGHT;
    144             if (imageOrientationDegrees % 180 == 90) {
    145                 int tmp = width;
    146                 width = height;
    147                 height = tmp;
    148             }
    149 
    150             ImageStreamProperties imageStreamProperties =
    151                     new ImageStreamProperties(width, height,
    152                             imageOrientationDegrees, cameraFacing == Facing.FRONT);
    153             EvictionHandler evictionHandler =
    154                     mBurstController.startBurst(
    155                             mSurfaceTextureContainer.get().getSurfaceTexture(),
    156                             imageStreamProperties,
    157                             mBurstResultsListener,
    158                             captureSession);
    159 
    160             // Start burst.
    161             mBurstTaker.get().startBurst(evictionHandler, mBurstController);
    162         } else {
    163             Log.e(TAG, "Cannot start burst.");
    164         }
    165     }
    166 
    167     @Override
    168     public boolean stopBurst() {
    169         MainThread.checkMainThread();
    170             boolean wasStopped = false;
    171             if (mBurstModuleState.compareAndSet(BurstModuleState.RUNNING,
    172                     BurstModuleState.STOPPING)) {
    173                 mBurstTaker.get().stopBurst();
    174                 wasStopped = true;
    175                 reEnableUI();
    176             }
    177             return wasStopped;
    178     }
    179 
    180     @Override
    181     public Surface getInputSurface() {
    182         return mSurfaceTextureContainer.get().getSurface();
    183     }
    184 
    185     @Override
    186     public void initialize(SurfaceTexture surfaceTexture) {
    187         MainThread.checkMainThread();
    188         // TODO: Use preview sizes from Camera API here instead of using the
    189         // default.
    190         surfaceTexture.setDefaultBufferSize(DEFAULT_PREVIEW_WIDTH, DEFAULT_PREVIEW_HEIGHT);
    191 
    192         // Detach from GL context, to allow frame distributor to attach to the
    193         // GL context.
    194         surfaceTexture.detachFromGLContext();
    195         mSurfaceTextureContainer.set(new SurfaceTextureContainer(surfaceTexture));
    196     }
    197 
    198     @Override
    199     public void release() {
    200         MainThread.checkMainThread();
    201         stopBurst();
    202         if (mSurfaceTextureContainer.get() != null) {
    203             mSurfaceTextureContainer.get().close();
    204             mSurfaceTextureContainer.set(null);
    205         }
    206     }
    207 
    208     @Override
    209     public void setBurstTaker(BurstTaker burstTaker) {
    210         mBurstTaker.set(burstTaker);
    211     }
    212 
    213     private void reEnableUI() {
    214         MainThread.checkMainThread();
    215         mOrientationLockController.unlockOrientation();
    216         // Re-enable the shutter button.
    217         mReadyStateListener.onBurstReadyStateChanged(true);
    218     }
    219 }
    220