1f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro/* 2f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Copyright (C) 2011 The Android Open Source Project 3f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * 4f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * use this file except in compliance with the License. You may obtain a copy of 6f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * the License at 7f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * 8f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * http://www.apache.org/licenses/LICENSE-2.0 9f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * 10f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Unless required by applicable law or agreed to in writing, software 11f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * License for the specific language governing permissions and limitations under 14f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * the License 15f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 16f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoropackage com.android.providers.contacts; 17f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 18f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.content.ContentValues; 19f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.database.sqlite.SQLiteDatabase; 20f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.graphics.Bitmap; 21f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.provider.ContactsContract.PhotoFiles; 22f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport android.util.Log; 23f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 2438210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.PhotoFilesColumns; 2538210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 2638210445730ee04c351c7cc1b3800cfe23e34325Makoto Onukiimport com.google.common.annotations.VisibleForTesting; 2738210445730ee04c351c7cc1b3800cfe23e34325Makoto Onuki 28f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.File; 29f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.FileOutputStream; 30f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.io.IOException; 31f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.util.HashMap; 32f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.util.HashSet; 33f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.util.Map; 34f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoroimport java.util.Set; 35f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 36f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro/** 37f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Photo storage system that stores the files directly onto the hard disk 38f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * in the specified directory. 39f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 40f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoropublic class PhotoStore { 41f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 42f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final String TAG = PhotoStore.class.getSimpleName(); 43f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 44f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Directory name under the root directory for photo storage. 45f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final String DIRECTORY = "photos"; 46f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 47f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Map of keys to entries in the directory. */ 48f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final Map<Long, Entry> mEntries; 49f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 50f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Total amount of space currently used by the photo store in bytes. */ 51f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mTotalSize = 0; 52f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 53f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The file path for photo storage. */ 54f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final File mStorePath; 55f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 56f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The database helper. */ 57f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final ContactsDatabaseHelper mDatabaseHelper; 58f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 59f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The database to use for storing metadata for the photo files. */ 60f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private SQLiteDatabase mDb; 61f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 62f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 63f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Constructs an instance of the PhotoStore under the specified directory. 64f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rootDirectory The root directory of the storage. 65f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param databaseHelper Helper class for obtaining a database instance. 66f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 67f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public PhotoStore(File rootDirectory, ContactsDatabaseHelper databaseHelper) { 68f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mStorePath = new File(rootDirectory, DIRECTORY); 69f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mStorePath.exists()) { 70f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if(!mStorePath.mkdirs()) { 71f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro throw new RuntimeException("Unable to create photo storage directory " 72f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro + mStorePath.getPath()); 73f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 74f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 75f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDatabaseHelper = databaseHelper; 76f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mEntries = new HashMap<Long, Entry>(); 77f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro initialize(); 78f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 79f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 80f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 81f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Clears the photo storage. Deletes all files from disk. 82f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 83fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public void clear() { 84f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro File[] files = mStorePath.listFiles(); 85f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (files != null) { 86f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro for (File file : files) { 87f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupFile(file); 88f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 89f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 90bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (mDb == null) { 91bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro mDb = mDatabaseHelper.getWritableDatabase(); 92bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 93f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDb.delete(Tables.PHOTO_FILES, null, null); 94f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mEntries.clear(); 95f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mTotalSize = 0; 96f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 97f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 98c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro @VisibleForTesting 99fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public long getTotalSize() { 100f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mTotalSize; 101f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 102f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 103f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 104f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Returns the entry with the specified key if it exists, null otherwise. 105f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 106fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public Entry get(long key) { 107f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mEntries.get(key); 108f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 109f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 110f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 111f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Initializes the PhotoStore by scanning for all files currently in the 112f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * specified root directory. 113f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 114fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public final void initialize() { 115f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro File[] files = mStorePath.listFiles(); 116f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (files == null) { 117f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return; 118f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 119f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro for (File file : files) { 120f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 121f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Entry entry = new Entry(file); 122f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro putEntry(entry.id, entry); 123f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (NumberFormatException nfe) { 124f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Not a valid photo store entry - delete the file. 125f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupFile(file); 126f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 127f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 128f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 129f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Get a reference to the database. 130f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDb = mDatabaseHelper.getWritableDatabase(); 131f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 132f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 133f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 134f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Cleans up the photo store such that only the keys in use still remain as 135f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * entries in the store (all other entries are deleted). 136f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * 137f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If an entry in the keys in use does not exist in the photo store, that key 138f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * will be returned in the result set - the caller should take steps to clean 139f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * up those references, as the underlying photo entries do not exist. 140f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * 141f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param keysInUse The set of all keys that are in use in the photo store. 142f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return The set of the keys in use that refer to non-existent entries. 143f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 144fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public Set<Long> cleanup(Set<Long> keysInUse) { 145f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Set<Long> keysToRemove = new HashSet<Long>(); 146f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro keysToRemove.addAll(mEntries.keySet()); 147f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro keysToRemove.removeAll(keysInUse); 148f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!keysToRemove.isEmpty()) { 149f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.d(TAG, "cleanup removing " + keysToRemove.size() + " entries"); 150f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro for (long key : keysToRemove) { 151f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro remove(key); 152f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 153f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 154f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 155f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Set<Long> missingKeys = new HashSet<Long>(); 156f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro missingKeys.addAll(keysInUse); 157f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro missingKeys.removeAll(mEntries.keySet()); 158f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return missingKeys; 159f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 160f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 161f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 162f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Inserts the photo in the given photo processor into the photo store. If the display photo 163f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * is already thumbnail-sized or smaller, this will do nothing (and will return 0). 164f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoProcessor A photo processor containing the photo data to insert. 165f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return The photo file ID associated with the file, or 0 if the file could not be created or 166f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * is thumbnail-sized or smaller. 167f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 168fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public long insert(PhotoProcessor photoProcessor) { 1696802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return insert(photoProcessor, false); 1706802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 1716802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 1726802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 1736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Inserts the photo in the given photo processor into the photo store. If the display photo 1746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * is already thumbnail-sized or smaller, this will do nothing (and will return 0) unless 1756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * allowSmallImageStorage is specified. 1766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param photoProcessor A photo processor containing the photo data to insert. 1776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param allowSmallImageStorage Whether thumbnail-sized or smaller photos should still be 1786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * stored in the file store. 1796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return The photo file ID associated with the file, or 0 if the file could not be created or 1806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * is thumbnail-sized or smaller and allowSmallImageStorage is false. 1816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 182fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public long insert(PhotoProcessor photoProcessor, boolean allowSmallImageStorage) { 183f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Bitmap displayPhoto = photoProcessor.getDisplayPhoto(); 184f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int width = displayPhoto.getWidth(); 185f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int height = displayPhoto.getHeight(); 186f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int thumbnailDim = photoProcessor.getMaxThumbnailPhotoDim(); 1876802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (allowSmallImageStorage || width > thumbnailDim || height > thumbnailDim) { 1886802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Write the photo to a temp file, create the DB record for tracking it, and rename the 1896802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // temp file to match. 190f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro File file = null; 191f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 192f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Write the display photo to a temp file. 193f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro byte[] photoBytes = photoProcessor.getDisplayPhotoBytes(); 194f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro file = File.createTempFile("img", null, mStorePath); 195f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro FileOutputStream fos = new FileOutputStream(file); 196eae25ef81bfe12946f50c72be9647447bb2a16b5Daniel Lehmann fos.write(photoBytes); 197f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro fos.close(); 198f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 199f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Create the DB entry. 200f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues values = new ContentValues(); 201f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro values.put(PhotoFiles.HEIGHT, height); 202f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro values.put(PhotoFiles.WIDTH, width); 203f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro values.put(PhotoFiles.FILESIZE, photoBytes.length); 204f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long id = mDb.insert(Tables.PHOTO_FILES, null, values); 205f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (id != 0) { 206f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Rename the temp file. 207f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro File target = getFileForPhotoFileId(id); 208f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (file.renameTo(target)) { 209f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Entry entry = new Entry(target); 210f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro putEntry(entry.id, entry); 211f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return id; 212f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 213f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 214f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException e) { 215f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Write failed - will delete the file below. 216f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 217f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 218f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If anything went wrong, clean up the file before returning. 219f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (file != null) { 220f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupFile(file); 221f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 222f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 223f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return 0; 224f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 225f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 226f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private void cleanupFile(File file) { 227f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean deleted = file.delete(); 228f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!deleted) { 229f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.d("Could not clean up file %s", file.getAbsolutePath()); 230f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 231f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 232f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 233f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 234f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Removes the specified photo file from the store if it exists. 235f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 236fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public void remove(long id) { 237f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupFile(getFileForPhotoFileId(id)); 238f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro removeEntry(id); 239f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 240f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 241f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 242f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Returns a file object for the given photo file ID. 243f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 244f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private File getFileForPhotoFileId(long id) { 245f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return new File(mStorePath, String.valueOf(id)); 246f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 247f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 248f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 249f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Puts the entry with the specified photo file ID into the store. 250f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param id The photo file ID to identify the entry by. 251f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param entry The entry to store. 252f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 253f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private void putEntry(long id, Entry entry) { 254f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mEntries.containsKey(id)) { 255f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mTotalSize += entry.size; 256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Entry oldEntry = mEntries.get(id); 258f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mTotalSize += (entry.size - oldEntry.size); 259f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 260f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mEntries.put(id, entry); 261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Removes the entry identified by the given photo file ID from the store, removing 265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * the associated photo file entry from the database. 266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private void removeEntry(long id) { 268f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Entry entry = mEntries.get(id); 269f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mTotalSize -= entry.size; 271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mEntries.remove(id); 272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 273f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDb.delete(ContactsDatabaseHelper.Tables.PHOTO_FILES, PhotoFilesColumns.CONCRETE_ID + "=?", 274f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(id)}); 275f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 276f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public static class Entry { 278f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The photo file ID that identifies the entry. */ 279f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public final long id; 280f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 281f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The size of the data, in bytes. */ 282f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public final long size; 283f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 284f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The path to the file. */ 285f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public final String path; 286f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 287f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public Entry(File file) { 288f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro id = Long.parseLong(file.getName()); 289f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro size = file.length(); 290f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro path = file.getAbsolutePath(); 291f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 292f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 293f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro} 294