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 42240d10d677b4acfeda5aa6e66c2cdea9ae02769bZheng Fu private static final Object MKDIRS_LOCK = new Object(); 43240d10d677b4acfeda5aa6e66c2cdea9ae02769bZheng Fu 44f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final String TAG = PhotoStore.class.getSimpleName(); 45f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 46f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Directory name under the root directory for photo storage. 47f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final String DIRECTORY = "photos"; 48f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 49f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Map of keys to entries in the directory. */ 50f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final Map<Long, Entry> mEntries; 51f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 52f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** Total amount of space currently used by the photo store in bytes. */ 53f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private long mTotalSize = 0; 54f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 55f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The file path for photo storage. */ 56f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final File mStorePath; 57f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 58f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The database helper. */ 59f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private final ContactsDatabaseHelper mDatabaseHelper; 60f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 61f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The database to use for storing metadata for the photo files. */ 62f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private SQLiteDatabase mDb; 63f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 64f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 65f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Constructs an instance of the PhotoStore under the specified directory. 66f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param rootDirectory The root directory of the storage. 67f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param databaseHelper Helper class for obtaining a database instance. 68f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 69f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public PhotoStore(File rootDirectory, ContactsDatabaseHelper databaseHelper) { 70f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mStorePath = new File(rootDirectory, DIRECTORY); 71240d10d677b4acfeda5aa6e66c2cdea9ae02769bZheng Fu synchronized (MKDIRS_LOCK) { 72240d10d677b4acfeda5aa6e66c2cdea9ae02769bZheng Fu if (!mStorePath.exists()) { 73240d10d677b4acfeda5aa6e66c2cdea9ae02769bZheng Fu if (!mStorePath.mkdirs()) { 74240d10d677b4acfeda5aa6e66c2cdea9ae02769bZheng Fu throw new RuntimeException("Unable to create photo storage directory " 75240d10d677b4acfeda5aa6e66c2cdea9ae02769bZheng Fu + mStorePath.getPath()); 76240d10d677b4acfeda5aa6e66c2cdea9ae02769bZheng Fu } 77f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 78f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 79f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDatabaseHelper = databaseHelper; 80f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mEntries = new HashMap<Long, Entry>(); 81f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro initialize(); 82f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 83f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 84f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 85f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Clears the photo storage. Deletes all files from disk. 86f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 87fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public void clear() { 88f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro File[] files = mStorePath.listFiles(); 89f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (files != null) { 90f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro for (File file : files) { 91f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupFile(file); 92f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 93f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 94bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro if (mDb == null) { 95bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro mDb = mDatabaseHelper.getWritableDatabase(); 96bd20dbedba706fdf2db7acb1c7d4391e57129d44Dave Santoro } 97f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDb.delete(Tables.PHOTO_FILES, null, null); 98f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mEntries.clear(); 99f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mTotalSize = 0; 100f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 101f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 102c6eab5080340824edd2c6676c4e6b96e142f87e4Dave Santoro @VisibleForTesting 103fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public long getTotalSize() { 104f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mTotalSize; 105f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 106f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 107f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 108f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Returns the entry with the specified key if it exists, null otherwise. 109f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 110fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public Entry get(long key) { 111f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return mEntries.get(key); 112f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 113f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 114f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 115f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Initializes the PhotoStore by scanning for all files currently in the 116f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * specified root directory. 117f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 118fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public final void initialize() { 119f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro File[] files = mStorePath.listFiles(); 120f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (files == null) { 121f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return; 122f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 123f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro for (File file : files) { 124f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 125f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Entry entry = new Entry(file); 126f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro putEntry(entry.id, entry); 127f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (NumberFormatException nfe) { 128f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Not a valid photo store entry - delete the file. 129f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupFile(file); 130f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 131f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 132f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 133f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Get a reference to the database. 134f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDb = mDatabaseHelper.getWritableDatabase(); 135f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 136f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 137f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 138f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Cleans up the photo store such that only the keys in use still remain as 139f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * entries in the store (all other entries are deleted). 140f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * 141f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * If an entry in the keys in use does not exist in the photo store, that key 142f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * will be returned in the result set - the caller should take steps to clean 143f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * up those references, as the underlying photo entries do not exist. 144f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * 145f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param keysInUse The set of all keys that are in use in the photo store. 146f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return The set of the keys in use that refer to non-existent entries. 147f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 148fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public Set<Long> cleanup(Set<Long> keysInUse) { 149f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Set<Long> keysToRemove = new HashSet<Long>(); 150f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro keysToRemove.addAll(mEntries.keySet()); 151f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro keysToRemove.removeAll(keysInUse); 152f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!keysToRemove.isEmpty()) { 153f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.d(TAG, "cleanup removing " + keysToRemove.size() + " entries"); 154f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro for (long key : keysToRemove) { 155f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro remove(key); 156f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 157f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 158f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 159f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Set<Long> missingKeys = new HashSet<Long>(); 160f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro missingKeys.addAll(keysInUse); 161f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro missingKeys.removeAll(mEntries.keySet()); 162f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return missingKeys; 163f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 164f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 165f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 166f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Inserts the photo in the given photo processor into the photo store. If the display photo 167f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * is already thumbnail-sized or smaller, this will do nothing (and will return 0). 168f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param photoProcessor A photo processor containing the photo data to insert. 169f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @return The photo file ID associated with the file, or 0 if the file could not be created or 170f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * is thumbnail-sized or smaller. 171f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 172fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public long insert(PhotoProcessor photoProcessor) { 1736802030a777c0c3ba1dc029c534cca4784260632Dave Santoro return insert(photoProcessor, false); 1746802030a777c0c3ba1dc029c534cca4784260632Dave Santoro } 1756802030a777c0c3ba1dc029c534cca4784260632Dave Santoro 1766802030a777c0c3ba1dc029c534cca4784260632Dave Santoro /** 1776802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * Inserts the photo in the given photo processor into the photo store. If the display photo 1786802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * is already thumbnail-sized or smaller, this will do nothing (and will return 0) unless 1796802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * allowSmallImageStorage is specified. 1806802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param photoProcessor A photo processor containing the photo data to insert. 1816802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @param allowSmallImageStorage Whether thumbnail-sized or smaller photos should still be 1826802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * stored in the file store. 1836802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * @return The photo file ID associated with the file, or 0 if the file could not be created or 1846802030a777c0c3ba1dc029c534cca4784260632Dave Santoro * is thumbnail-sized or smaller and allowSmallImageStorage is false. 1856802030a777c0c3ba1dc029c534cca4784260632Dave Santoro */ 186fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public long insert(PhotoProcessor photoProcessor, boolean allowSmallImageStorage) { 187f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Bitmap displayPhoto = photoProcessor.getDisplayPhoto(); 188f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int width = displayPhoto.getWidth(); 189f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int height = displayPhoto.getHeight(); 190f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro int thumbnailDim = photoProcessor.getMaxThumbnailPhotoDim(); 1916802030a777c0c3ba1dc029c534cca4784260632Dave Santoro if (allowSmallImageStorage || width > thumbnailDim || height > thumbnailDim) { 1926802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // Write the photo to a temp file, create the DB record for tracking it, and rename the 1936802030a777c0c3ba1dc029c534cca4784260632Dave Santoro // temp file to match. 194f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro File file = null; 195f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro try { 196f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Write the display photo to a temp file. 197f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro byte[] photoBytes = photoProcessor.getDisplayPhotoBytes(); 198f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro file = File.createTempFile("img", null, mStorePath); 199f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro FileOutputStream fos = new FileOutputStream(file); 200eae25ef81bfe12946f50c72be9647447bb2a16b5Daniel Lehmann fos.write(photoBytes); 201f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro fos.close(); 202f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 203f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Create the DB entry. 204f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro ContentValues values = new ContentValues(); 205f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro values.put(PhotoFiles.HEIGHT, height); 206f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro values.put(PhotoFiles.WIDTH, width); 207f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro values.put(PhotoFiles.FILESIZE, photoBytes.length); 208f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro long id = mDb.insert(Tables.PHOTO_FILES, null, values); 209f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (id != 0) { 210f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Rename the temp file. 211f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro File target = getFileForPhotoFileId(id); 212f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (file.renameTo(target)) { 213f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Entry entry = new Entry(target); 214f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro putEntry(entry.id, entry); 215f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return id; 216f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 217f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 218f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } catch (IOException e) { 219f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // Write failed - will delete the file below. 220f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 221f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 222f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro // If anything went wrong, clean up the file before returning. 223f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (file != null) { 224f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupFile(file); 225f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 226f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 227f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return 0; 228f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 229f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 230f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private void cleanupFile(File file) { 231f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro boolean deleted = file.delete(); 232f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!deleted) { 233f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Log.d("Could not clean up file %s", file.getAbsolutePath()); 234f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 235f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 236f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 237f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 238f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Removes the specified photo file from the store if it exists. 239f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 240fa4db3db4146a26f154ef2e89352ad70a5415b8eDaniel Lehmann public void remove(long id) { 241f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro cleanupFile(getFileForPhotoFileId(id)); 242f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro removeEntry(id); 243f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 244f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 245f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 246f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Returns a file object for the given photo file ID. 247f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 248f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private File getFileForPhotoFileId(long id) { 249f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro return new File(mStorePath, String.valueOf(id)); 250f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 251f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 252f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 253f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Puts the entry with the specified photo file ID into the store. 254f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param id The photo file ID to identify the entry by. 255f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * @param entry The entry to store. 256f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 257f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private void putEntry(long id, Entry entry) { 258f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (!mEntries.containsKey(id)) { 259f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mTotalSize += entry.size; 260f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } else { 261f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Entry oldEntry = mEntries.get(id); 262f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mTotalSize += (entry.size - oldEntry.size); 263f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 264f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mEntries.put(id, entry); 265f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 266f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 267f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** 268f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * Removes the entry identified by the given photo file ID from the store, removing 269f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro * the associated photo file entry from the database. 270f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro */ 271f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro private void removeEntry(long id) { 272f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro Entry entry = mEntries.get(id); 273f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro if (entry != null) { 274f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mTotalSize -= entry.size; 275f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mEntries.remove(id); 276f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 277f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro mDb.delete(ContactsDatabaseHelper.Tables.PHOTO_FILES, PhotoFilesColumns.CONCRETE_ID + "=?", 278f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro new String[]{String.valueOf(id)}); 279f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 280f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 281f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public static class Entry { 282f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The photo file ID that identifies the entry. */ 283f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public final long id; 284f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 285f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The size of the data, in bytes. */ 286f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public final long size; 287f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 288f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro /** The path to the file. */ 289f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public final String path; 290f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro 291f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro public Entry(File file) { 292f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro id = Long.parseLong(file.getName()); 293f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro size = file.length(); 294f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro path = file.getAbsolutePath(); 295f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 296f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro } 297f547fd54d7933e1c03af4a8dc10560c71c38f6b8Dave Santoro} 298