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.google.common.base.Optional;
20 
21 import com.android.camera.async.RefCountBase;
22 import com.android.camera.captureintent.CaptureIntentConfig;
23 import com.android.camera.captureintent.resource.ResourceConstructed;
24 import com.android.camera.captureintent.stateful.State;
25 import com.android.camera.captureintent.stateful.StateImpl;
26 import com.android.camera.debug.Log;
27 import com.android.camera.util.CameraUtil;
28 
29 import android.content.Intent;
30 import android.graphics.Bitmap;
31 import android.net.Uri;
32 import android.os.Bundle;
33 import android.provider.MediaStore;
34 
35 import java.io.IOException;
36 import java.io.OutputStream;
37 
38 /**
39  * Represents a state that the module is saving the picture to disk.
40  */
41 public class StateSavingPicture extends StateImpl {
42     private static final Log.Tag TAG = new Log.Tag("StateSavePic");
43 
44     private final RefCountBase<ResourceConstructed> mResourceConstructed;
45     private final byte[] mPictureData;
46 
from( StateReviewingPicture reviewingPicture, RefCountBase<ResourceConstructed> resourceConstructed, byte[] pictureData)47     public static StateSavingPicture from(
48             StateReviewingPicture reviewingPicture,
49             RefCountBase<ResourceConstructed> resourceConstructed,
50             byte[] pictureData) {
51         return new StateSavingPicture(reviewingPicture, resourceConstructed, pictureData);
52     }
53 
StateSavingPicture( State previousState, RefCountBase<ResourceConstructed> resourceConstructed, byte[] pictureData)54     private StateSavingPicture(
55             State previousState,
56             RefCountBase<ResourceConstructed> resourceConstructed,
57             byte[] pictureData) {
58         super(previousState);
59         mResourceConstructed = resourceConstructed;
60         mResourceConstructed.addRef();  // Will be balanced in onLeave().
61         mPictureData = pictureData;
62     }
63 
64     @Override
onEnter()65     public Optional<State> onEnter() {
66         /**
67          * The caller may pass an extra EXTRA_OUTPUT to control where this
68          * image will be written. If the EXTRA_OUTPUT is not present, then
69          * a small sized image is returned as a Bitmap object in the extra
70          * field. This is useful for applications that only need a small
71          * image. If the EXTRA_OUTPUT is present, then the full-sized image
72          * will be written to the Uri value of EXTRA_OUTPUT.
73          */
74         Optional<Uri> saveUri = Optional.absent();
75         final Bundle myExtras = mResourceConstructed.get().getIntent().getExtras();
76         if (myExtras != null) {
77             saveUri = Optional.of((Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT));
78             String cropValue = myExtras.getString("crop");
79         }
80 
81         if (saveUri.isPresent()) {
82             OutputStream outputStream = null;
83             try {
84                 outputStream = mResourceConstructed.get().getContext().getContentResolver()
85                         .openOutputStream(saveUri.get());
86                 outputStream.write(mPictureData);
87                 outputStream.close();
88 
89                 Log.v(TAG, "saved result to URI: " + saveUri);
90                 return Optional.of((State) StateIntentCompleted.from(
91                         this, mResourceConstructed, new Intent()));
92             } catch (IOException ex) {
93                 Log.e(TAG, "exception while saving result to URI: " + saveUri, ex);
94             } finally {
95                 CameraUtil.closeSilently(outputStream);
96             }
97         } else {
98             /** Inline the bitmap into capture intent result */
99             final Bitmap bitmap = CameraUtil.makeBitmap(
100                     mPictureData, CaptureIntentConfig.INLINE_BITMAP_MAX_PIXEL_NUM);
101             return Optional.of((State) StateIntentCompleted.from(
102                     this, mResourceConstructed,
103                     new Intent("inline-data").putExtra("data", bitmap)));
104         }
105         return Optional.of((State) StateIntentCompleted.from(this, mResourceConstructed));
106     }
107 
108     @Override
onLeave()109     public void onLeave() {
110         mResourceConstructed.close();
111     }
112 }