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
17package com.android.camera.captureintent.state;
18
19import com.google.common.base.Optional;
20
21import com.android.camera.async.RefCountBase;
22import com.android.camera.captureintent.CaptureIntentConfig;
23import com.android.camera.captureintent.resource.ResourceConstructed;
24import com.android.camera.captureintent.stateful.State;
25import com.android.camera.captureintent.stateful.StateImpl;
26import com.android.camera.debug.Log;
27import com.android.camera.util.CameraUtil;
28
29import android.content.Intent;
30import android.graphics.Bitmap;
31import android.net.Uri;
32import android.os.Bundle;
33import android.provider.MediaStore;
34
35import java.io.IOException;
36import java.io.OutputStream;
37
38/**
39 * Represents a state that the module is saving the picture to disk.
40 */
41public 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
47    public static StateSavingPicture from(
48            StateReviewingPicture reviewingPicture,
49            RefCountBase<ResourceConstructed> resourceConstructed,
50            byte[] pictureData) {
51        return new StateSavingPicture(reviewingPicture, resourceConstructed, pictureData);
52    }
53
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
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
109    public void onLeave() {
110        mResourceConstructed.close();
111    }
112}