blob: 4e797f75e044d7617659fee3180e4e89f5aadcb2 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.providers.contacts;
import static com.android.providers.contacts.ContactsActor.PACKAGE_GREY;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.provider.ContactsContract;
import android.provider.ContactsContract.PhotoFiles;
import android.test.suitebuilder.annotation.MediumTest;
import com.android.providers.contacts.ContactsDatabaseHelper.Tables;
import com.android.providers.contacts.tests.R;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* Tests for {@link PhotoStore}.
*/
@MediumTest
public class PhotoStoreTest extends PhotoLoadingTestCase {
private ContactsActor mActor;
private SynchronousContactsProvider2 mProvider;
private SQLiteDatabase mDb;
// The object under test.
private PhotoStore mPhotoStore;
@Override
protected void setUp() throws Exception {
super.setUp();
mActor = new ContactsActor(getContext(), PACKAGE_GREY, SynchronousContactsProvider2.class,
ContactsContract.AUTHORITY);
mProvider = ((SynchronousContactsProvider2) mActor.provider);
mPhotoStore = mProvider.getPhotoStore();
mProvider.wipeData();
mDb = mProvider.getDatabaseHelper(getContext()).getReadableDatabase();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
mPhotoStore.clear();
}
public void testStoreThumbnailPhoto() throws IOException {
byte[] photo = loadPhotoFromResource(R.drawable.earth_small, PhotoSize.ORIGINAL);
// Since the photo is already thumbnail-sized, no file will be stored.
assertEquals(0, mPhotoStore.insert(newPhotoProcessor(photo, false)));
}
public void testStore200Photo() throws IOException {
// As 200 is below the full photo size, we don't want to see it upscaled
runStorageTestForResource(R.drawable.earth_200, 200, 200);
}
public void testStoreNonSquare300x200Photo() throws IOException {
// The longer side should be downscaled to the target size
runStorageTestForResource(R.drawable.earth_300x200, 256, 170);
}
public void testStoreNonSquare300x200PhotoWithCrop() throws IOException {
// As 300x200 is below the full photo size, we don't want to see it upscaled
// This one is not square, so we expect the longer side to be cropped
runStorageTestForResourceWithCrop(R.drawable.earth_300x200, 200, 200);
}
public void testStoreNonSquare600x400PhotoWithCrop() throws IOException {
// As 600x400 is above the full photo size, we expect the picture to be cropped and then
// scaled
runStorageTestForResourceWithCrop(R.drawable.earth_600x400, 256, 256);
}
public void testStoreMediumPhoto() throws IOException {
// Source Image is 256x256
runStorageTestForResource(R.drawable.earth_normal, 256, 256);
}
public void testStoreLargePhoto() throws IOException {
// Source image is 512x512
runStorageTestForResource(R.drawable.earth_large, 256, 256);
}
public void testStoreHugePhoto() throws IOException {
// Source image is 1024x1024
runStorageTestForResource(R.drawable.earth_huge, 256, 256);
}
/**
* Runs the following steps:
* - Loads the given photo resource.
* - Inserts it into the photo store.
* - Checks that the photo has a photo file ID.
* - Loads the expected display photo for the resource.
* - Gets the photo entry from the photo store.
* - Loads the photo entry's file content from disk.
* - Compares the expected photo content to the disk content.
* - Queries the contacts provider for the photo file entry, checks for its
* existence, and matches it up against the expected metadata.
* - Checks that the total storage taken up by the photo store is equal to
* the size of the photo.
* @param resourceId The resource ID of the photo file to test.
*/
public void runStorageTestForResource(int resourceId, int expectedWidth,
int expectedHeight) throws IOException {
byte[] photo = loadPhotoFromResource(resourceId, PhotoSize.ORIGINAL);
long photoFileId = mPhotoStore.insert(newPhotoProcessor(photo, false));
assertTrue(photoFileId != 0);
File storedFile = new File(mPhotoStore.get(photoFileId).path);
assertTrue(storedFile.exists());
byte[] actualStoredVersion = readInputStreamFully(new FileInputStream(storedFile));
byte[] expectedStoredVersion = loadPhotoFromResource(resourceId, PhotoSize.DISPLAY_PHOTO);
EvenMoreAsserts.assertImageRawData(getContext(),
expectedStoredVersion, actualStoredVersion);
Cursor c = mDb.query(Tables.PHOTO_FILES,
new String[]{PhotoFiles.WIDTH, PhotoFiles.HEIGHT, PhotoFiles.FILESIZE},
PhotoFiles._ID + "=?", new String[]{String.valueOf(photoFileId)}, null, null, null);
try {
assertEquals(1, c.getCount());
c.moveToFirst();
assertEquals(expectedWidth + "/" + expectedHeight, c.getInt(0) + "/" + c.getInt(1));
assertEquals(expectedStoredVersion.length, c.getInt(2));
} finally {
c.close();
}
assertEquals(expectedStoredVersion.length, mPhotoStore.getTotalSize());
}
public void runStorageTestForResourceWithCrop(int resourceId, int expectedWidth,
int expectedHeight) throws IOException {
byte[] photo = loadPhotoFromResource(resourceId, PhotoSize.ORIGINAL);
long photoFileId = mPhotoStore.insert(newPhotoProcessor(photo, true));
assertTrue(photoFileId != 0);
Cursor c = mDb.query(Tables.PHOTO_FILES,
new String[]{PhotoFiles.HEIGHT, PhotoFiles.WIDTH, PhotoFiles.FILESIZE},
PhotoFiles._ID + "=?", new String[]{String.valueOf(photoFileId)}, null, null, null);
try {
assertEquals(1, c.getCount());
c.moveToFirst();
assertEquals(expectedWidth + "/" + expectedHeight, c.getInt(0) + "/" + c.getInt(1));
} finally {
c.close();
}
}
public void testRemoveEntry() throws IOException {
byte[] photo = loadPhotoFromResource(R.drawable.earth_normal, PhotoSize.ORIGINAL);
long photoFileId = mPhotoStore.insert(newPhotoProcessor(photo, false));
PhotoStore.Entry entry = mPhotoStore.get(photoFileId);
assertTrue(new File(entry.path).exists());
mPhotoStore.remove(photoFileId);
// Check that the file has been deleted.
assertFalse(new File(entry.path).exists());
// Check that the database record has also been removed.
Cursor c = mDb.query(Tables.PHOTO_FILES, new String[]{PhotoFiles._ID},
PhotoFiles._ID + "=?", new String[]{String.valueOf(photoFileId)}, null, null, null);
try {
assertEquals(0, c.getCount());
} finally {
c.close();
}
}
public void testCleanup() throws IOException {
// Load some photos into the store.
Set<Long> photoFileIds = new HashSet<Long>();
Map<Integer, Long> resourceIdToPhotoMap = new HashMap<Integer, Long>();
int[] resourceIds = new int[] {
R.drawable.earth_normal, R.drawable.earth_large, R.drawable.earth_huge
};
for (int resourceId : resourceIds) {
long photoFileId = mPhotoStore.insert(
new PhotoProcessor(loadPhotoFromResource(resourceId, PhotoSize.ORIGINAL),
256, 96));
resourceIdToPhotoMap.put(resourceId, photoFileId);
photoFileIds.add(photoFileId);
}
assertFalse(photoFileIds.contains(0L));
assertEquals(3, photoFileIds.size());
// Run cleanup with the indication that only the large and huge photos are in use, along
// with a bogus photo file ID that isn't in the photo store.
long bogusPhotoFileId = 123456789;
Set<Long> photoFileIdsInUse = new HashSet<Long>();
photoFileIdsInUse.add(resourceIdToPhotoMap.get(R.drawable.earth_large));
photoFileIdsInUse.add(resourceIdToPhotoMap.get(R.drawable.earth_huge));
photoFileIdsInUse.add(bogusPhotoFileId);
Set<Long> photoIdsToCleanup = mPhotoStore.cleanup(photoFileIdsInUse);
// The set of photo IDs to clean up should consist of the bogus photo file ID.
assertEquals(1, photoIdsToCleanup.size());
assertTrue(photoIdsToCleanup.contains(bogusPhotoFileId));
// The entry for the normal-sized photo should have been cleaned up, since it isn't being
// used.
long normalPhotoId = resourceIdToPhotoMap.get(R.drawable.earth_normal);
assertNull(mPhotoStore.get(normalPhotoId));
// Check that the database record has also been removed.
Cursor c = mDb.query(Tables.PHOTO_FILES, new String[]{PhotoFiles._ID},
PhotoFiles._ID + "=?", new String[]{String.valueOf(normalPhotoId)},
null, null, null);
try {
assertEquals(0, c.getCount());
} finally {
c.close();
}
}
}