<dimen name="zoom_font_size">14pt</dimen>
<dimen name="shutter_offset">-22dp</dimen>
<dimen name="margin_systemui_offset">6dip</dimen>
+ <dimen name="size_thumbnail">200dip</dimen>
+ <dimen name="size_preview">600dip</dimen>
</resources>
--- /dev/null
+/*
+ * Copyright (C) 2013 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.photos.data;
+
+import android.net.Uri;
+
+import com.android.photos.data.PhotoProvider.ChangeNotification;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Used for capturing notifications from PhotoProvider without relying on
+ * ContentResolver. MockContentResolver does not allow sending notification to
+ * ContentObservers, so PhotoProvider allows this alternative for testing.
+ */
+public class NotificationWatcher implements ChangeNotification {
+ private Set<Uri> mUris = new HashSet<Uri>();
+
+ @Override
+ public void notifyChange(Uri uri) {
+ mUris.add(uri);
+ }
+
+ public boolean isNotified(Uri uri) {
+ return mUris.contains(uri);
+ }
+
+ public int notificationCount() {
+ return mUris.size();
+ }
+
+ public void reset() {
+ mUris.clear();
+ }
+}
public class PhotoDatabase extends SQLiteOpenHelper {
@SuppressWarnings("unused")
private static final String TAG = PhotoDatabase.class.getSimpleName();
- static final String DB_NAME = "photo.db";
static final int DB_VERSION = 1;
private static final String SQL_CREATE_TABLE = "CREATE TABLE ";
createTable(db, Metadata.TABLE, CREATE_METADATA);
}
- public PhotoDatabase(Context context) {
- super(context, DB_NAME, null, DB_VERSION);
+ public PhotoDatabase(Context context, String dbName) {
+ super(context, dbName, null, DB_VERSION);
}
@Override
package com.android.photos.data;
import android.content.ContentProvider;
-import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
-import android.database.sqlite.SQLiteStatement;
+import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.os.CancellationSignal;
import android.provider.BaseColumns;
+import com.google.android.gms.common.util.VisibleForTesting;
+
import java.util.ArrayList;
import java.util.List;
public class PhotoProvider extends ContentProvider {
@SuppressWarnings("unused")
private static final String TAG = PhotoProvider.class.getSimpleName();
- static final String AUTHORITY = "com.android.gallery3d.photoprovider";
+
+ protected static final String DB_NAME = "photo.db";
+ public static final String AUTHORITY = PhotoProviderAuthority.AUTHORITY;
static final Uri BASE_CONTENT_URI = new Uri.Builder().scheme("content").authority(AUTHORITY)
.build();
+ // Used to allow mocking out the change notification because
+ // MockContextResolver disallows system-wide notification.
+ public static interface ChangeNotification {
+ void notifyChange(Uri uri);
+ }
+
/**
* Contains columns that can be accessed via PHOTOS_CONTENT_URI.
*/
/**
* Foreign key to the photos._id. Long value.
*/
- public static final String PHOTO_ID = "photos_id";
+ public static final String PHOTO_ID = "photo_id";
/**
* One of IMAGE_TYPE_* values.
*/
Photos.MIME_TYPE,
};
+ private static final String[] BASE_COLUMNS_ID = {
+ BaseColumns._ID,
+ };
+
+ protected ChangeNotification mNotifier = null;
private SQLiteOpenHelper mOpenHelper;
protected static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
}
@Override
+ public void shutdown() {
+ getDatabaseHelper().close();
+ }
+
+ @Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
return rowsUpdated;
}
+ @VisibleForTesting
+ public void setMockNotification(ChangeNotification notification) {
+ mNotifier = notification;
+ }
+
protected static String addIdToSelection(int match, String selection) {
String where;
switch (match) {
}
protected SQLiteOpenHelper createDatabaseHelper() {
- return new PhotoDatabase(getContext());
+ return new PhotoDatabase(getContext(), DB_NAME);
}
private int modifyMetadata(SQLiteDatabase db, ContentValues values) {
}
protected void notifyChanges(Uri uri) {
- ContentResolver resolver = getContext().getContentResolver();
- resolver.notifyChange(uri, null, false);
+ if (mNotifier != null) {
+ mNotifier.notifyChange(uri);
+ } else {
+ getContext().getContentResolver().notifyChange(uri, null, false);
+ }
}
protected static IllegalArgumentException unknownUri(Uri uri) {
return new IllegalArgumentException("Unknown Uri format: " + uri);
}
- protected static String nestSql(String base, String columnMatch, String nested) {
- StringBuilder sql = new StringBuilder(base);
- sql.append(WHERE);
- sql.append(columnMatch);
- sql.append(IN);
- sql.append(NESTED_SELECT_START);
- sql.append(nested);
- sql.append(NESTED_SELECT_END);
- return sql.toString();
- }
-
- protected static String addWhere(String base, String where) {
- if (where == null || where.isEmpty()) {
- return base;
- }
- return base + WHERE + where;
+ protected static String nestWhere(String matchColumn, String table, String nestedWhere) {
+ String query = SQLiteQueryBuilder.buildQueryString(false, table, BASE_COLUMNS_ID,
+ nestedWhere, null, null, null, null);
+ return matchColumn + IN + NESTED_SELECT_START + query + NESTED_SELECT_END;
}
protected static int deleteCascade(SQLiteDatabase db, int match, String selection,
switch (match) {
case MATCH_PHOTO:
case MATCH_PHOTO_ID: {
- String selectPhotoIdsSql = addWhere(SELECT_PHOTO_ID, selection);
- deleteCascadeMetadata(db, selectPhotoIdsSql, selectionArgs, changeUris);
+ deleteCascadeMetadata(db, selection, selectionArgs, changeUris);
break;
}
case MATCH_ALBUM:
case MATCH_ALBUM_ID: {
- String selectAlbumIdSql = addWhere(SELECT_ALBUM_ID, selection);
- deleteCascadePhotos(db, selectAlbumIdSql, selectionArgs, changeUris);
+ deleteCascadePhotos(db, selection, selectionArgs, changeUris);
break;
}
}
String table = getTableFromMatch(match, uri);
- changeUris.add(uri);
- return db.delete(table, selection, selectionArgs);
- }
-
- protected static void execSql(SQLiteDatabase db, String sql, String[] args) {
- if (args == null) {
- db.execSQL(sql);
- } else {
- db.execSQL(sql, args);
+ int deleted = db.delete(table, selection, selectionArgs);
+ if (deleted > 0) {
+ changeUris.add(uri);
}
+ return deleted;
}
private static void deleteCascadePhotos(SQLiteDatabase db, String albumSelect,
String[] selectArgs, List<Uri> changeUris) {
- String selectPhotoIdSql = nestSql(SELECT_PHOTO_ID, Photos.ALBUM_ID, albumSelect);
- deleteCascadeMetadata(db, selectPhotoIdSql, selectArgs, changeUris);
- String deletePhotoSql = nestSql(DELETE_PHOTOS, Photos.ALBUM_ID, albumSelect);
- SQLiteStatement statement = db.compileStatement(deletePhotoSql);
- statement.bindAllArgsAsStrings(selectArgs);
- int deleted = statement.executeUpdateDelete();
+ String photoWhere = nestWhere(Photos.ALBUM_ID, Albums.TABLE, albumSelect);
+ deleteCascadeMetadata(db, photoWhere, selectArgs, changeUris);
+ int deleted = db.delete(Photos.TABLE, photoWhere, selectArgs);
if (deleted > 0) {
changeUris.add(Photos.CONTENT_URI);
}
private static void deleteCascadeMetadata(SQLiteDatabase db, String photosSelect,
String[] selectArgs, List<Uri> changeUris) {
- String deleteMetadataSql = nestSql(DELETE_METADATA, Metadata.PHOTO_ID, photosSelect);
- SQLiteStatement statement = db.compileStatement(deleteMetadataSql);
- statement.bindAllArgsAsStrings(selectArgs);
- int deleted = statement.executeUpdateDelete();
+ String metadataWhere = nestWhere(Metadata.PHOTO_ID, Photos.TABLE, photosSelect);
+ int deleted = db.delete(Metadata.TABLE, metadataWhere, selectArgs);
if (deleted > 0) {
changeUris.add(Metadata.CONTENT_URI);
}
--- /dev/null
+/*
+ * Copyright (C) 2013 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.photos.data;
+
+interface PhotoProviderAuthority {
+ public static final String AUTHORITY = "com.android.gallery3d.photoprovider";
+}
public class PhotoDatabaseTest extends InstrumentationTestCase {
private PhotoDatabase mDBHelper;
+ private static final String DB_NAME = "dummy.db";
@Override
- protected void setUp() {
+ protected void setUp() throws Exception {
+ super.setUp();
Context context = getInstrumentation().getTargetContext();
- mDBHelper = new PhotoDatabase(context);
+ context.deleteDatabase(DB_NAME);
+ mDBHelper = new PhotoDatabase(context, DB_NAME);
}
@Override
- protected void tearDown() {
+ protected void tearDown() throws Exception {
mDBHelper.close();
+ mDBHelper = null;
+ Context context = getInstrumentation().getTargetContext();
+ context.deleteDatabase(DB_NAME);
+ super.tearDown();
}
public void testCreateDatabase() throws IOException {
Context context = getInstrumentation().getTargetContext();
- File dbFile = context.getDatabasePath(PhotoDatabase.DB_NAME);
- if (dbFile.exists()) {
- dbFile.delete();
- }
+ File dbFile = context.getDatabasePath(DB_NAME);
SQLiteDatabase db = getReadableDB();
db.beginTransaction();
db.endTransaction();
assertTrue(dbFile.exists());
- dbFile.delete();
}
public void testTables() {
values.put(Metadata.VALUE, value);
return db.insert(Metadata.TABLE, null, values) != -1;
}
-
- public static void deleteAllContent(SQLiteDatabase db) {
- db.delete(Metadata.TABLE, null, null);
- db.delete(Photos.TABLE, null, null);
- db.delete(Albums.TABLE, null, null);
- }
}
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
-import android.content.Context;
-import android.database.ContentObserver;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
import android.provider.BaseColumns;
-import android.test.InstrumentationTestCase;
+import android.test.ProviderTestCase2;
import com.android.photos.data.PhotoProvider.Albums;
import com.android.photos.data.PhotoProvider.Metadata;
import com.android.photos.data.PhotoProvider.Photos;
-public class PhotoProviderTest extends InstrumentationTestCase {
+public class PhotoProviderTest extends ProviderTestCase2<PhotoProvider> {
@SuppressWarnings("unused")
private static final String TAG = PhotoProviderTest.class.getSimpleName();
private static final String WHERE_METADATA = Metadata.PHOTO_ID + " = ? AND " + Metadata.KEY
+ " = ?";
- private static final long WAIT_FOR_CHANGE_MILLIS = 200;
-
private long mAlbumId;
private long mPhotoId;
private long mMetadataId;
- private PhotoDatabase mDBHelper;
+ private SQLiteOpenHelper mDBHelper;
private ContentResolver mResolver;
+ private NotificationWatcher mNotifications = new NotificationWatcher();
- private static class WatchContentObserverThread extends Thread {
- private WatchContentObserver mObserver;
- private Looper mLooper;
-
- @Override
- public void run() {
- Looper.prepare();
- mLooper = Looper.myLooper();
- WatchContentObserver observer = new WatchContentObserver();
- synchronized (this) {
- mObserver = observer;
- this.notifyAll();
- }
- Looper.loop();
- }
-
- public void waitForObserver() throws InterruptedException {
- synchronized (this) {
- while (mObserver == null) {
- this.wait();
- }
- }
- }
-
- public WatchContentObserver getObserver() {
- return mObserver;
- }
-
- public void stopLooper() {
- mLooper.quit();
- }
- };
-
- private static class WatchContentObserver extends ContentObserver {
- private boolean mOnChangeReceived = false;
- private Uri mUri = null;
-
- public WatchContentObserver() {
- super(new Handler());
- }
-
- @Override
- public synchronized void onChange(boolean selfChange, Uri uri) {
- mOnChangeReceived = true;
- mUri = uri;
- notifyAll();
- }
-
- @Override
- public synchronized void onChange(boolean selfChange) {
- mOnChangeReceived = true;
- notifyAll();
- }
-
- public boolean waitForNotification() {
- synchronized (this) {
- if (!mOnChangeReceived) {
- try {
- wait(WAIT_FOR_CHANGE_MILLIS);
- } catch (InterruptedException e) {
- }
- }
- }
- return mOnChangeReceived;
- }
- };
+ public PhotoProviderTest() {
+ super(PhotoProvider.class, PhotoProvider.AUTHORITY);
+ }
@Override
- protected void setUp() {
- Context context = getInstrumentation().getTargetContext();
- mDBHelper = new PhotoDatabase(context);
- mResolver = context.getContentResolver();
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResolver = getMockContentResolver();
+ PhotoProvider provider = (PhotoProvider) getProvider();
+ provider.setMockNotification(mNotifications);
+ mDBHelper = provider.getDatabaseHelper();
SQLiteDatabase db = mDBHelper.getWritableDatabase();
db.beginTransaction();
try {
mMetadataId = cursor.getLong(0);
cursor.close();
db.setTransactionSuccessful();
+ mNotifications.reset();
} finally {
db.endTransaction();
}
}
@Override
- protected void tearDown() {
- SQLiteDatabase db = mDBHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- PhotoDatabaseUtils.deleteAllContent(db);
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
+ protected void tearDown() throws Exception {
mDBHelper.close();
mDBHelper = null;
+ super.tearDown();
+ getMockContext().deleteDatabase(PhotoProvider.DB_NAME);
}
public void testDelete() {
assertEquals(0, cursor.getCount());
cursor.close();
}
+
// Delete the album and ensure that the photos referring to the album are
// deleted.
public void testDeleteAlbumCascade() {
- WatchContentObserverThread observerThread = createObserverThread();
- WatchContentObserver observer = observerThread.getObserver();
- mResolver.registerContentObserver(Photos.CONTENT_URI, true, observer);
- try {
- Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
- mResolver.delete(albumUri, null, null);
- assertTrue(observer.waitForNotification());
- assertEquals(observer.mUri, Photos.CONTENT_URI);
- Cursor cursor = mResolver.query(Photos.CONTENT_URI,
- PhotoDatabaseUtils.PROJECTION_PHOTOS, null, null, null);
- assertEquals(0, cursor.getCount());
- cursor.close();
- } finally {
- mResolver.unregisterContentObserver(observer);
- observerThread.stopLooper();
- }
- }
-
- // Delete the album and ensure that the metadata referring to photos in that
- // album are deleted.
- public void testDeleteAlbumCascade2() {
- WatchContentObserverThread observerThread = createObserverThread();
- WatchContentObserver observer = observerThread.getObserver();
- mResolver.registerContentObserver(Metadata.CONTENT_URI, true, observer);
- try {
- Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
- mResolver.delete(albumUri, null, null);
- assertTrue(observer.waitForNotification());
- assertEquals(observer.mUri, Metadata.CONTENT_URI);
- Cursor cursor = mResolver.query(Metadata.CONTENT_URI,
- PhotoDatabaseUtils.PROJECTION_METADATA, null, null, null);
- assertEquals(0, cursor.getCount());
- cursor.close();
- } finally {
- mResolver.unregisterContentObserver(observer);
- observerThread.stopLooper();
- }
+ Uri albumUri = ContentUris.withAppendedId(Albums.CONTENT_URI, mAlbumId);
+ mResolver.delete(albumUri, null, null);
+ assertTrue(mNotifications.isNotified(Photos.CONTENT_URI));
+ assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
+ assertTrue(mNotifications.isNotified(albumUri));
+ assertEquals(3, mNotifications.notificationCount());
+ Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
+ null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
}
// Delete all albums and ensure that photos in any album are deleted.
- public void testDeleteAlbumCascade3() {
- WatchContentObserverThread observerThread = createObserverThread();
- WatchContentObserver observer = observerThread.getObserver();
- mResolver.registerContentObserver(Photos.CONTENT_URI, true, observer);
- try {
- mResolver.delete(Albums.CONTENT_URI, null, null);
- assertTrue(observer.waitForNotification());
- assertEquals(observer.mUri, Photos.CONTENT_URI);
- Cursor cursor = mResolver.query(Photos.CONTENT_URI,
- PhotoDatabaseUtils.PROJECTION_PHOTOS, null, null, null);
- assertEquals(0, cursor.getCount());
- cursor.close();
- } finally {
- mResolver.unregisterContentObserver(observer);
- observerThread.stopLooper();
- }
+ public void testDeleteAlbumCascade2() {
+ mResolver.delete(Albums.CONTENT_URI, null, null);
+ assertTrue(mNotifications.isNotified(Photos.CONTENT_URI));
+ assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
+ assertTrue(mNotifications.isNotified(Albums.CONTENT_URI));
+ assertEquals(3, mNotifications.notificationCount());
+ Cursor cursor = mResolver.query(Photos.CONTENT_URI, PhotoDatabaseUtils.PROJECTION_PHOTOS,
+ null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
}
// Delete a photo and ensure that the metadata for that photo are deleted.
public void testDeletePhotoCascade() {
- WatchContentObserverThread observerThread = createObserverThread();
- WatchContentObserver observer = observerThread.getObserver();
- mResolver.registerContentObserver(Metadata.CONTENT_URI, true, observer);
- try {
- Uri albumUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
- mResolver.delete(albumUri, null, null);
- assertTrue(observer.waitForNotification());
- assertEquals(observer.mUri, Metadata.CONTENT_URI);
- Cursor cursor = mResolver.query(Metadata.CONTENT_URI,
- PhotoDatabaseUtils.PROJECTION_METADATA, null, null, null);
- assertEquals(0, cursor.getCount());
- cursor.close();
- } finally {
- mResolver.unregisterContentObserver(observer);
- observerThread.stopLooper();
- }
+ Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
+ mResolver.delete(photoUri, null, null);
+ assertTrue(mNotifications.isNotified(photoUri));
+ assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
+ assertEquals(2, mNotifications.notificationCount());
+ Cursor cursor = mResolver.query(Metadata.CONTENT_URI,
+ PhotoDatabaseUtils.PROJECTION_METADATA, null, null, null);
+ assertEquals(0, cursor.getCount());
+ cursor.close();
}
public void testGetType() {
}
public void testUpdatePhotoNotification() {
- WatchContentObserverThread observerThread = createObserverThread();
- WatchContentObserver observer = observerThread.getObserver();
- mResolver.registerContentObserver(Photos.CONTENT_URI, true, observer);
- try {
- Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
- ContentValues values = new ContentValues();
- values.put(Photos.MIME_TYPE, "not-a/mime-type");
- mResolver.update(photoUri, values, null, null);
- assertTrue(observer.waitForNotification());
- assertEquals(observer.mUri, photoUri);
- } finally {
- mResolver.unregisterContentObserver(observer);
- observerThread.stopLooper();
- }
+ Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
+ ContentValues values = new ContentValues();
+ values.put(Photos.MIME_TYPE, "not-a/mime-type");
+ mResolver.update(photoUri, values, null, null);
+ assertTrue(mNotifications.isNotified(photoUri));
}
public void testUpdateMetadataNotification() {
- WatchContentObserverThread observerThread = createObserverThread();
- WatchContentObserver observer = observerThread.getObserver();
- mResolver.registerContentObserver(Metadata.CONTENT_URI, true, observer);
- try {
- ContentValues values = new ContentValues();
- values.put(Metadata.PHOTO_ID, mPhotoId);
- values.put(Metadata.KEY, META_KEY);
- values.put(Metadata.VALUE, "hello world");
- mResolver.update(Metadata.CONTENT_URI, values, null, null);
- assertTrue(observer.waitForNotification());
- assertEquals(observer.mUri, Metadata.CONTENT_URI);
- } finally {
- mResolver.unregisterContentObserver(observer);
- observerThread.stopLooper();
- }
- }
-
- public void testDeletePhotoNotification() {
- WatchContentObserverThread observerThread = createObserverThread();
- WatchContentObserver observer = observerThread.getObserver();
- mResolver.registerContentObserver(Photos.CONTENT_URI, true, observer);
- try {
- Uri photoUri = ContentUris.withAppendedId(Photos.CONTENT_URI, mPhotoId);
- mResolver.delete(photoUri, null, null);
- assertTrue(observer.waitForNotification());
- assertEquals(observer.mUri, photoUri);
- } finally {
- mResolver.unregisterContentObserver(observer);
- observerThread.stopLooper();
- }
- }
-
- private WatchContentObserverThread createObserverThread() {
- WatchContentObserverThread thread = new WatchContentObserverThread();
- thread.start();
- try {
- thread.waitForObserver();
- return thread;
- } catch (InterruptedException e) {
- thread.stopLooper();
- fail("Interruption while waiting for observer being created.");
- return null;
- }
+ ContentValues values = new ContentValues();
+ values.put(Metadata.PHOTO_ID, mPhotoId);
+ values.put(Metadata.KEY, META_KEY);
+ values.put(Metadata.VALUE, "hello world");
+ mResolver.update(Metadata.CONTENT_URI, values, null, null);
+ assertTrue(mNotifications.isNotified(Metadata.CONTENT_URI));
}
}
--- /dev/null
+/*
+ * Copyright (C) 2013 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.photos.data;
+
+import android.util.Log;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.lang.reflect.Method;
+
+public class TestHelper {
+ private static String TAG = TestHelper.class.getSimpleName();
+
+ public interface TestInitialization {
+ void initialize(TestCase testCase);
+ }
+
+ public static void addTests(Class<? extends TestCase> testClass, TestSuite suite,
+ TestInitialization initialization) {
+ for (Method method : testClass.getDeclaredMethods()) {
+ if (method.getName().startsWith("test") && method.getParameterTypes().length == 0) {
+ TestCase test;
+ try {
+ test = testClass.newInstance();
+ test.setName(method.getName());
+ initialization.initialize(test);
+ suite.addTest(test);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Failed to create test case", e);
+ } catch (InstantiationException e) {
+ Log.e(TAG, "Failed to create test case", e);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Failed to create test case", e);
+ }
+ }
+ }
+ }
+
+}