Home | History | Annotate | Download | only in imagesaver
      1 /*
      2  * Copyright (C) 2014 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.one.v2.imagesaver;
     18 
     19 import com.android.camera.one.v2.camera2proxy.ImageProxy;
     20 import com.android.camera.one.v2.camera2proxy.TotalCaptureResultProxy;
     21 import com.google.common.base.Optional;
     22 import com.google.common.util.concurrent.ListenableFuture;
     23 
     24 import java.util.ArrayList;
     25 import java.util.HashMap;
     26 import java.util.List;
     27 import java.util.Map;
     28 
     29 import javax.annotation.Nullable;
     30 import javax.annotation.ParametersAreNonnullByDefault;
     31 
     32 /**
     33  * Saves the last image in a burst.
     34  */
     35 @ParametersAreNonnullByDefault
     36 public class MostRecentImageSaver implements ImageSaver {
     37     private final SingleImageSaver mSingleImageSaver;
     38     private final Map<Long, ImageProxy> mThumbnails;
     39     private final Map<Long, MetadataImage> mFullSizeImages;
     40 
     41     public MostRecentImageSaver(SingleImageSaver singleImageSaver) {
     42         mSingleImageSaver = singleImageSaver;
     43         mThumbnails = new HashMap<>();
     44         mFullSizeImages = new HashMap<>();
     45     }
     46 
     47     @Override
     48     public void addThumbnail(ImageProxy imageProxy) {
     49         mThumbnails.put(imageProxy.getTimestamp(), imageProxy);
     50         closeOlderImages();
     51     }
     52 
     53     @Override
     54     public void addFullSizeImage(ImageProxy imageProxy,
     55             ListenableFuture<TotalCaptureResultProxy> metadata) {
     56         mFullSizeImages.put(imageProxy.getTimestamp(), new MetadataImage(imageProxy, metadata));
     57         closeOlderImages();
     58     }
     59 
     60     @Override
     61     public void close() {
     62         try {
     63             MetadataImage fullSize = getLastImage();
     64             if (fullSize != null) {
     65                 // Pop the image out of the map so that closeAllImages() does
     66                 // not close it.
     67                 mFullSizeImages.remove(fullSize.getTimestamp());
     68             } else {
     69                 return;
     70             }
     71 
     72             ImageProxy thumbnail = getThumbnail(fullSize.getTimestamp());
     73             if (thumbnail != null) {
     74                 // Pop the image out of the map so that closeAllImages() does
     75                 // not close it.
     76                 mThumbnails.remove(thumbnail.getTimestamp());
     77             }
     78 
     79             mSingleImageSaver.saveAndCloseImage(fullSize, Optional.fromNullable(thumbnail),
     80                     fullSize.getMetadata());
     81         } finally {
     82             closeAllImages();
     83         }
     84     }
     85 
     86     private void closeAllImages() {
     87         for (ImageProxy image : mThumbnails.values()) {
     88             image.close();
     89         }
     90 
     91         for (ImageProxy image : mFullSizeImages.values()) {
     92             image.close();
     93         }
     94     }
     95 
     96     private void closeOlderImages(long threshold, Map<Long, ? extends ImageProxy> imageMap) {
     97         List<Long> toRemove = new ArrayList<>();
     98         for (long imageTimestamp : imageMap.keySet()) {
     99             if (imageTimestamp < threshold) {
    100                 imageMap.get(imageTimestamp).close();
    101                 toRemove.add(imageTimestamp);
    102             }
    103         }
    104         for (Long timestamp : toRemove) {
    105             imageMap.remove(timestamp);
    106         }
    107     }
    108 
    109     private void closeOlderImages() {
    110         Optional<Long> timestampThreshold = getMostRecentFullSizeImageTimestamp();
    111         if (timestampThreshold.isPresent()) {
    112             closeOlderImages(timestampThreshold.get(), mFullSizeImages);
    113             closeOlderImages(timestampThreshold.get(), mThumbnails);
    114         }
    115     }
    116 
    117     private Optional<Long> getMostRecentFullSizeImageTimestamp() {
    118         if (mFullSizeImages.isEmpty()) {
    119             return Optional.absent();
    120         }
    121         boolean pairFound = false;
    122         long oldestTimestamp = 0;
    123         for (ImageProxy image : mFullSizeImages.values()) {
    124             long timestamp = image.getTimestamp();
    125             if (!pairFound || timestamp > oldestTimestamp) {
    126                 oldestTimestamp = timestamp;
    127                 pairFound = true;
    128             }
    129         }
    130         if (!pairFound) {
    131             return Optional.absent();
    132         } else {
    133             return Optional.of(oldestTimestamp);
    134         }
    135     }
    136 
    137     @Nullable
    138     private MetadataImage getLastImage() {
    139         if (mFullSizeImages.isEmpty()) {
    140             return null;
    141         }
    142         MetadataImage lastImage = null;
    143         for (MetadataImage image : mFullSizeImages.values()) {
    144             if (lastImage == null || image.getTimestamp() > lastImage.getTimestamp()) {
    145                 lastImage = image;
    146             }
    147         }
    148         return lastImage;
    149     }
    150 
    151     @Nullable
    152     private ImageProxy getThumbnail(long timestamp) {
    153         return mThumbnails.get(timestamp);
    154     }
    155 }
    156