1/*
2 * Copyright (C) 2013 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.session;
18
19import android.content.ContentResolver;
20import android.content.Context;
21import android.database.Cursor;
22import android.graphics.BitmapFactory;
23import android.location.Location;
24import android.net.Uri;
25import android.provider.MediaStore;
26
27import com.android.camera.Storage;
28import com.android.camera.debug.Log;
29import com.android.camera.exif.ExifInterface;
30import com.android.camera.util.CameraUtil;
31
32/**
33 * Handles placeholders in filmstrip that show up temporarily while a final
34 * output media item is being produced.
35 */
36public class PlaceholderManager {
37    private static final Log.Tag TAG = new Log.Tag("PlaceholderMgr");
38
39    private final Context mContext;
40
41    public static class Session {
42        final String outputTitle;
43        final Uri outputUri;
44        final long time;
45
46        Session(String title, Uri uri, long timestamp) {
47            outputTitle = title;
48            outputUri = uri;
49            time = timestamp;
50        }
51    }
52
53    public PlaceholderManager(Context context) {
54        mContext = context;
55    }
56
57    public Session insertPlaceholder(String title, byte[] placeholder, long timestamp) {
58        if (title == null || placeholder == null) {
59            throw new IllegalArgumentException("Null argument passed to insertPlaceholder");
60        }
61
62        // Decode bounds
63        BitmapFactory.Options options = new BitmapFactory.Options();
64        options.inJustDecodeBounds = true;
65        BitmapFactory.decodeByteArray(placeholder, 0, placeholder.length, options);
66        int width = options.outWidth;
67        int height = options.outHeight;
68
69        if (width <= 0 || height <= 0) {
70            throw new IllegalArgumentException("Image had bad height/width");
71        }
72
73        Uri uri =
74                Storage.addPlaceholder(placeholder, width, height);
75        if (uri == null) {
76            return null;
77        }
78        return new Session(title, uri, timestamp);
79    }
80
81    /**
82     * Converts an existing item into a placeholder for re-processing.
83     *
84     * @param uri the URI of an existing media item.
85     * @return A session that can be used to update the progress of the new
86     *         session.
87     */
88    public Session convertToPlaceholder(Uri uri) {
89        return createSessionFromUri(uri);
90    }
91
92    /**
93     * This converts the placeholder in to a real media item
94     *
95     * @param session the session that is being finished.
96     * @param location the location of the image
97     * @param orientation the orientation of the image
98     * @param exif the exif of the image
99     * @param jpeg the bytes of the image
100     * @param width the width of the image
101     * @param height the height of the image
102     * @param mimeType the mime type of the image
103     * @return The content URI of the new media item.
104     */
105    public Uri finishPlaceholder(Session session, Location location, int orientation,
106                                 ExifInterface exif, byte[] jpeg, int width, int height, String mimeType) {
107
108        Uri resultUri = Storage.updateImage(session.outputUri, mContext.getContentResolver(), session.outputTitle,
109                session.time, location, orientation, exif, jpeg, width, height, mimeType);
110        CameraUtil.broadcastNewPicture(mContext, resultUri);
111        return resultUri;
112    }
113
114    /**
115     * This changes the temporary placeholder jpeg without writing it to the media store
116     *
117     * @param session the session to update
118     * @param jpeg the new placeholder bytes
119     * @param width the width of the image
120     * @param height the height of the image
121     */
122    public void replacePlaceholder(Session session,
123                                   byte[] jpeg, int width, int height) {
124
125        Storage.replacePlaceholder(session.outputUri,
126                jpeg, width, height);
127        CameraUtil.broadcastNewPicture(mContext, session.outputUri);
128    }
129
130    /**
131     * Create a new session instance from the given URI by querying the media
132     * store.
133     * <p>
134     * TODO: Make sure this works with types other than images when needed.
135     */
136    private Session createSessionFromUri(Uri uri) {
137        ContentResolver resolver = mContext.getContentResolver();
138
139        Cursor cursor = resolver.query(uri,
140                new String[] {
141                        MediaStore.Images.Media.DATE_TAKEN, MediaStore.Images.Media.DISPLAY_NAME,
142                }, null, null, null);
143        // The count could be 0 if the original media item was deleted before
144        // the session was created.
145        if (cursor == null || cursor.getCount() == 0) {
146            return null;
147        }
148        int dateIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATE_TAKEN);
149        int nameIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DISPLAY_NAME);
150
151        cursor.moveToFirst();
152        long date = cursor.getLong(dateIndex);
153        String name = cursor.getString(nameIndex);
154
155        if (name.toLowerCase().endsWith(Storage.JPEG_POSTFIX)) {
156            name = name.substring(0, name.length() - Storage.JPEG_POSTFIX.length());
157        }
158
159        return new Session(name, uri, date);
160    }
161}
162