Home | History | Annotate | Download | only in burst
      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.burst;
     18 
     19 import android.os.AsyncTask;
     20 import android.text.TextUtils;
     21 
     22 import com.android.camera.debug.Log;
     23 import com.android.camera.debug.Log.Tag;
     24 import com.android.camera.session.StackSaver;
     25 
     26 import java.util.ArrayList;
     27 import java.util.List;
     28 import java.util.Map;
     29 import java.util.concurrent.TimeUnit;
     30 
     31 class BurstResultsSaver {
     32     private static final Tag TAG = new Tag("BurstResultsSaver");
     33 
     34     /**
     35      * The format string of burst media item file name (without extension).
     36      * <p/>
     37      * An media item file name has the following format: "Burst_" + artifact
     38      * type + "_" + index of artifact + "_" + index of media item + "_" +
     39      * timestamp
     40      */
     41     private static final String MEDIA_ITEM_FILENAME_FORMAT_STRING = "Burst_%s_%d_%d_%d";
     42 
     43     /**
     44      * Generates sequential timestamp with 1 second difference.
     45      */
     46     private static class SequentialTimestampGenerator {
     47         private long mSeedTimestampMillis;
     48 
     49         /**
     50          * New instance of generator.
     51          *
     52          * @param seedTimestampMillis the timestamp in milliseconds for
     53          *            initializing the generator.
     54          */
     55         public SequentialTimestampGenerator(long seedTimestampMillis) {
     56             mSeedTimestampMillis = seedTimestampMillis;
     57         }
     58 
     59         /**
     60          * Returns the next timestamp.
     61          */
     62         public synchronized long getNextTimestampMillis() {
     63             mSeedTimestampMillis += TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS);
     64             return mSeedTimestampMillis;
     65         }
     66     }
     67 
     68     public static void logArtifactCount(final Map<String, Integer> artifactTypeCount) {
     69         final String prefix = "Finished burst. Creating ";
     70         List<String> artifactDescription = new ArrayList<String>();
     71         for (Map.Entry<String, Integer> entry : artifactTypeCount.entrySet()) {
     72             artifactDescription.add(entry.getValue() + " " + entry.getKey());
     73         }
     74 
     75         String message = prefix + TextUtils.join(" and ", artifactDescription) + ".";
     76         Log.d(TAG, message);
     77     }
     78 
     79     /**
     80      * Saves the burst result and on completion re-enables the shutter button.
     81      *
     82      * @param burstResult the result of the burst.
     83      */
     84     public static void saveBurstResultsInBackground(final BurstResult burstResult,
     85             final StackSaver stackSaver, final Runnable onCompletetionCallback) {
     86         Log.i(TAG, "Saving results of of the burst.");
     87 
     88         AsyncTask<Void, String, Void> saveTask =
     89                 new AsyncTask<Void, String, Void>() {
     90                     @Override
     91                     protected Void doInBackground(Void... arg0) {
     92                         // The timestamp with which a media item is saved
     93                         // determines its place in the film strip. The newer
     94                         // items appear first.
     95                         // We save artifacts and their corresponding media
     96                         // items sequentially in the desired order. The order
     97                         // of the artifacts is implicitly defined by
     98                         // burstResult.getTypes() and the media items inside the
     99                         // artifacts are assumed to be sorted in ascending order
    100                         // by timestamps.
    101                         // We create a timestamp-generator that generates
    102                         // timestamps in order and use it to save timestamps.
    103                         SequentialTimestampGenerator timestampGen =
    104                                 new SequentialTimestampGenerator(System.currentTimeMillis());
    105                         for (String artifactType : burstResult.getTypes()) {
    106                             publishProgress(artifactType);
    107                             saveArtifacts(stackSaver, burstResult, artifactType,
    108                                     timestampGen);
    109                         }
    110                         return null;
    111                     }
    112 
    113                     @Override
    114                     protected void onPostExecute(Void result) {
    115                         onCompletetionCallback.run();
    116                     }
    117 
    118                     @Override
    119                     protected void onProgressUpdate(String... artifactTypes) {
    120                         logProgressUpdate(artifactTypes, burstResult);
    121                     }
    122                 };
    123         saveTask.execute(null, null, null);
    124     }
    125 
    126     /**
    127      * Save individual artifacts for bursts.
    128      */
    129     private static void saveArtifacts(final StackSaver stackSaver, final BurstResult burstResult,
    130             final String artifactType, SequentialTimestampGenerator timestampGenerator) {
    131         List<BurstArtifact> artifactList = burstResult.getArtifactsByType(artifactType);
    132         for (int artifactIndex = 0; artifactIndex < artifactList.size(); artifactIndex++) {
    133             List<BurstMediaItem> mediaItems = artifactList.get(artifactIndex).getMediaItems();
    134             for (int index = 0; index < mediaItems.size(); index++) {
    135                 saveBurstMediaItem(stackSaver, mediaItems.get(index),
    136                         artifactType, artifactIndex + 1, index + 1, timestampGenerator);
    137             }
    138         }
    139     }
    140 
    141     private static void saveBurstMediaItem(StackSaver stackSaver,
    142             BurstMediaItem mediaItem,
    143             String artifactType,
    144             int artifactIndex,
    145             int index,
    146             SequentialTimestampGenerator timestampGenerator) {
    147         // Use ordered timestamp for saving the media item, this way media
    148         // items appear to be in the correct order when user swipes to the
    149         // film strip.
    150         long timestamp = timestampGenerator.getNextTimestampMillis();
    151         final String title = String.format(MEDIA_ITEM_FILENAME_FORMAT_STRING,
    152                 artifactType, artifactIndex, index, mediaItem.getTimestamp());
    153         String mimeType = mediaItem.getMimeType();
    154 
    155         stackSaver.saveStackedImage(mediaItem.getFilePath(),
    156                 title,
    157                 mediaItem.getWidth(),
    158                 mediaItem.getHeight(),
    159                 0, // Artifacts returned from burst have upright orientation.
    160                 timestamp,
    161                 mimeType);
    162     }
    163 
    164     private static void logProgressUpdate(String[] artifactTypes, BurstResult burstResult) {
    165         for (String artifactType : artifactTypes) {
    166             List<BurstArtifact> artifacts =
    167                     burstResult.getArtifactsByType(artifactType);
    168             if (!artifacts.isEmpty()) {
    169                 Log.d(TAG, "Saving " + artifacts.size()
    170                         + " " + artifactType + "s.");
    171             }
    172         }
    173     }
    174 
    175 }
    176