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