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 
17 package com.android.camera.session;
18 
19 import android.content.ContentResolver;
20 import android.content.Context;
21 import android.database.Cursor;
22 import android.graphics.BitmapFactory;
23 import android.location.Location;
24 import android.net.Uri;
25 import android.provider.MediaStore;
26 
27 import com.android.camera.Storage;
28 import com.android.camera.debug.Log;
29 import com.android.camera.exif.ExifInterface;
30 import 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  */
36 public 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 
Session(String title, Uri uri, long timestamp)46         Session(String title, Uri uri, long timestamp) {
47             outputTitle = title;
48             outputUri = uri;
49             time = timestamp;
50         }
51     }
52 
PlaceholderManager(Context context)53     public PlaceholderManager(Context context) {
54         mContext = context;
55     }
56 
insertPlaceholder(String title, byte[] placeholder, long timestamp)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      */
convertToPlaceholder(Uri uri)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      */
finishPlaceholder(Session session, Location location, int orientation, ExifInterface exif, byte[] jpeg, int width, int height, String mimeType)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      */
replacePlaceholder(Session session, byte[] jpeg, int width, int height)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      */
createSessionFromUri(Uri uri)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