summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/camera/ImageGallery.java2
-rwxr-xr-x[-rw-r--r--]src/com/android/camera/ImageManager.java20
-rw-r--r--src/com/android/camera/TimeCounter.java6
-rw-r--r--src/com/android/camera/Util.java2
-rw-r--r--src/com/android/camera/ViewImage.java2
-rw-r--r--src/com/android/camera/gallery/BaseImage.java166
-rw-r--r--src/com/android/camera/gallery/BaseImageList.java306
-rw-r--r--src/com/android/camera/gallery/DrmImageList.java74
-rw-r--r--src/com/android/camera/gallery/IImage.java10
-rw-r--r--src/com/android/camera/gallery/IImageList.java4
-rw-r--r--src/com/android/camera/gallery/Image.java66
-rw-r--r--src/com/android/camera/gallery/ImageList.java155
-rw-r--r--src/com/android/camera/gallery/ImageListUber.java295
-rw-r--r--src/com/android/camera/gallery/LruCache.java19
-rw-r--r--src/com/android/camera/gallery/SingleImageList.java48
-rw-r--r--src/com/android/camera/gallery/UriImage.java4
-rw-r--r--src/com/android/camera/gallery/VideoList.java157
-rw-r--r--src/com/android/camera/gallery/VideoObject.java26
18 files changed, 549 insertions, 813 deletions
diff --git a/src/com/android/camera/ImageGallery.java b/src/com/android/camera/ImageGallery.java
index 5610191..c1603b6 100644
--- a/src/com/android/camera/ImageGallery.java
+++ b/src/com/android/camera/ImageGallery.java
@@ -793,7 +793,7 @@ public class ImageGallery extends Activity implements
IImage image = mAllImages.getImageForUri(mCropResultUri);
mCropResultUri = null;
if (image != null) {
- mSelectedIndex = image.getRow();
+ mSelectedIndex = mAllImages.getImageIndex(image);
}
}
mGvs.select(mSelectedIndex, false);
diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java
index 19113f1..b5ee041 100644..100755
--- a/src/com/android/camera/ImageManager.java
+++ b/src/com/android/camera/ImageManager.java
@@ -223,7 +223,12 @@ public class ImageManager {
long id = ContentUris.parseId(mUri);
BaseImageList il = new ImageList(mCr, STORAGE_URI,
THUMB_URI, SORT_ASCENDING, null);
- Image image = new Image(id, 0, mCr, il, il.getCount(), 0);
+
+ // TODO: Redesign the process of adding new images. We should
+ // create an <code>IImage</code> in "ImageManager.addImage"
+ // and pass the image object to here.
+ Image image = new Image(il, mCr, id, 0, il.contentUri(id), null,
+ 0, null, 0, null, null, 0);
String[] projection = new String[] {
ImageColumns._ID,
ImageColumns.MINI_THUMB_MAGIC, ImageColumns.DATA};
@@ -324,7 +329,12 @@ public class ImageManager {
return false;
}
- public void removeImageAt(int i) {
+ public boolean removeImageAt(int i) {
+ return false;
+ }
+
+ public int getImageIndex(IImage image) {
+ throw new UnsupportedOperationException();
}
}
@@ -360,15 +370,13 @@ public class ImageManager {
}
if ((inclusion & INCLUDE_VIDEOS) != 0) {
try {
- l.add(new VideoList(cr, VIDEO_STORAGE_URI,
- VIDEO_THUMBNAIL_URI, sort, bucketId));
+ l.add(new VideoList(cr, VIDEO_STORAGE_URI, sort, bucketId));
} catch (UnsupportedOperationException ex) {
// ignore exception
}
}
}
- if (location == DataLocation.INTERNAL
- || location == DataLocation.ALL) {
+ if (location == DataLocation.INTERNAL || location == DataLocation.ALL) {
if ((inclusion & INCLUDE_IMAGES) != 0) {
try {
l.add(new ImageList(cr,
diff --git a/src/com/android/camera/TimeCounter.java b/src/com/android/camera/TimeCounter.java
index 2e1ae7f..d21df0f 100644
--- a/src/com/android/camera/TimeCounter.java
+++ b/src/com/android/camera/TimeCounter.java
@@ -30,9 +30,9 @@ import android.util.Log;
// between begin() and end() every 128 times.
public class TimeCounter {
private static final String TAG = "TimeCounter";
- private String mName;
+ private final String mName;
private int mSamples;
- private int mPeriod;
+ private final int mPeriod;
// To avoid overflow, these values are in microseconds.
private long mSum;
@@ -81,4 +81,4 @@ public class TimeCounter {
+ ", Max = " + mMax
+ ", Min = " + mMin);
}
-};
+}
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index 028725b..d19d698 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -276,7 +276,7 @@ public class Util {
return bitmap;
}
- public static int indexOf(String [] array, String s) {
+ public static <T> int indexOf(T [] array, T s) {
for (int i = 0; i < array.length; i++) {
if (array[i].equals(s)) {
return i;
diff --git a/src/com/android/camera/ViewImage.java b/src/com/android/camera/ViewImage.java
index 0cdcdbc..9ce5e5c 100644
--- a/src/com/android/camera/ViewImage.java
+++ b/src/com/android/camera/ViewImage.java
@@ -876,7 +876,7 @@ public class ViewImage extends Activity implements View.OnClickListener {
IImage image = mAllImages.getImageForUri(uri);
if (image != null) {
- mCurrentPosition = image.getRow();
+ mCurrentPosition = mAllImages.getImageIndex(image);
mLastSlideShowImage = mCurrentPosition;
}
}
diff --git a/src/com/android/camera/gallery/BaseImage.java b/src/com/android/camera/gallery/BaseImage.java
index 1caae09..815c0ef 100644
--- a/src/com/android/camera/gallery/BaseImage.java
+++ b/src/com/android/camera/gallery/BaseImage.java
@@ -20,19 +20,18 @@ import com.android.camera.BitmapManager;
import com.android.camera.Util;
import android.content.ContentResolver;
-import android.database.Cursor;
+import android.content.ContentValues;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
-import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Images.ImageColumns;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.util.HashMap;
/**
* Represents a particular image and provides access to the underlying bitmap
@@ -47,21 +46,38 @@ public abstract class BaseImage implements IImage {
new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
protected ContentResolver mContentResolver;
- protected long mId, mMiniThumbMagic;
+
+
+ // Database field
+ protected Uri mUri;
+ protected long mId;
+ protected String mDataPath;
+ protected long mMiniThumbMagic;
+ protected final int mIndex;
+ protected String mMimeType;
+ private final long mDateTaken;
+ private String mTitle;
+ private final String mDisplayName;
+
protected BaseImageList mContainer;
- protected HashMap<String, String> mExifData;
- protected int mCursorRow;
private int mWidth = UNKNOWN_LENGTH;
private int mHeight = UNKNOWN_LENGTH;
- protected BaseImage(long id, long miniThumbMagic, ContentResolver cr,
- BaseImageList container, int cursorRow) {
+ protected BaseImage(BaseImageList container, ContentResolver cr,
+ long id, int index, Uri uri, String dataPath, long miniThumbMagic,
+ String mimeType, long dateTaken, String title, String displayName) {
+ mContainer = container;
mContentResolver = cr;
- mId = id;
- mMiniThumbMagic = miniThumbMagic;
- mContainer = container;
- mCursorRow = cursorRow;
+ mId = id;
+ mIndex = index;
+ mUri = uri;
+ mDataPath = dataPath;
+ mMiniThumbMagic = miniThumbMagic;
+ mMimeType = mimeType;
+ mDateTaken = dateTaken;
+ mTitle = title;
+ mDisplayName = displayName;
}
protected abstract Bitmap.CompressFormat compressionType();
@@ -70,12 +86,12 @@ public abstract class BaseImage implements IImage {
private ThreadSafeOutputStream mOutputStream = null;
private final Bitmap mBitmap;
- private final Uri mUri;
+ private final Uri mDestinationUri;
private final byte[] mJpegData;
public CompressImageToFile(Bitmap bitmap, byte[] jpegData, Uri uri) {
mBitmap = bitmap;
- mUri = uri;
+ mDestinationUri = uri;
mJpegData = jpegData;
}
@@ -93,7 +109,8 @@ public abstract class BaseImage implements IImage {
@Override
public Boolean execute() {
try {
- OutputStream delegate = mContentResolver.openOutputStream(mUri);
+ OutputStream delegate =
+ mContentResolver.openOutputStream(mDestinationUri);
synchronized (this) {
mOutputStream = new ThreadSafeOutputStream(delegate);
}
@@ -126,15 +143,19 @@ public abstract class BaseImage implements IImage {
return new CompressImageToFile(bitmap, jpegData, uri);
}
+ public String getDataPath() {
+ return mDataPath;
+ }
+
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof Image)) return false;
- return fullSizeImageUri().equals(((Image) other).fullSizeImageUri());
+ return mUri.equals(((Image) other).mUri);
}
@Override
public int hashCode() {
- return fullSizeImageUri().toString().hashCode();
+ return mUri.hashCode();
}
public Bitmap fullSizeBitmap(int targetWidthHeight) {
@@ -177,8 +198,7 @@ public abstract class BaseImage implements IImage {
@Override
protected Bitmap execute() {
try {
- Bitmap b = Util.makeBitmap(
- mTargetWidthHeight, fullSizeImageUri(),
+ Bitmap b = Util.makeBitmap(mTargetWidthHeight, mUri,
mContentResolver, mPFD, mOptions);
if (b != null) {
b = Util.rotate(b, getDegreesRotated());
@@ -192,12 +212,11 @@ public abstract class BaseImage implements IImage {
}
}
-
public Cancelable<Bitmap> fullSizeBitmapCancelable(
int targetWidthHeight) {
try {
ParcelFileDescriptor pfdInput = mContentResolver
- .openFileDescriptor(fullSizeImageUri(), "r");
+ .openFileDescriptor(mUri, "r");
return new LoadBitmapCancelable(pfdInput, targetWidthHeight);
} catch (FileNotFoundException ex) {
return null;
@@ -208,8 +227,7 @@ public abstract class BaseImage implements IImage {
public InputStream fullSizeImageData() {
try {
- InputStream input = mContentResolver.openInputStream(
- fullSizeImageUri());
+ InputStream input = mContentResolver.openInputStream(mUri);
return input;
} catch (IOException ex) {
return null;
@@ -221,24 +239,15 @@ public abstract class BaseImage implements IImage {
}
public Uri fullSizeImageUri() {
- return mContainer.contentUri(mId);
+ return mUri;
}
public IImageList getContainer() {
return mContainer;
}
- Cursor getCursor() {
- return mContainer.getCursor();
- }
-
public long getDateTaken() {
- if (mContainer.indexDateTaken() < 0) return 0;
- Cursor c = getCursor();
- synchronized (c) {
- c.moveToPosition(getRow());
- return c.getLong(mContainer.indexDateTaken());
- }
+ return mDateTaken;
}
protected int getDegreesRotated() {
@@ -246,74 +255,21 @@ public abstract class BaseImage implements IImage {
}
public String getMimeType() {
- if (mContainer.indexMimeType() < 0) {
- Cursor c = mContentResolver.query(fullSizeImageUri(),
- new String[] { "_id", Images.Media.MIME_TYPE },
- null, null, null);
- try {
- return c.moveToFirst() ? c.getString(1) : "";
- } finally {
- c.close();
- }
- } else {
- String mimeType = null;
- Cursor c = getCursor();
- synchronized (c) {
- if (c.moveToPosition(getRow())) {
- mimeType = c.getString(mContainer.indexMimeType());
- }
- }
- return mimeType;
- }
+ return mMimeType;
}
public String getTitle() {
- String name = null;
- Cursor c = getCursor();
- synchronized (c) {
- if (c.moveToPosition(getRow())) {
- if (mContainer.indexTitle() != -1) {
- name = c.getString(mContainer.indexTitle());
- }
- }
- }
- return name != null && name.length() > 0 ? name : String.valueOf(mId);
+ return mTitle;
}
public String getDisplayName() {
- if (mContainer.indexDisplayName() < 0) {
- Cursor c = mContentResolver.query(fullSizeImageUri(),
- new String[] { "_id", Images.Media.DISPLAY_NAME },
- null, null, null);
- try {
- if (c.moveToFirst()) return c.getString(1);
- } finally {
- c.close();
- }
- } else {
- String name = null;
- Cursor c = getCursor();
- synchronized (c) {
- if (c.moveToPosition(getRow())) {
- name = c.getString(mContainer.indexDisplayName());
- }
- }
- if (name != null && name.length() > 0) {
- return name;
- }
- }
- return String.valueOf(mId);
- }
-
- public int getRow() {
- return mCursorRow;
+ return mDisplayName;
}
private void setupDimension() {
ParcelFileDescriptor input = null;
try {
- input = mContentResolver
- .openFileDescriptor(fullSizeImageUri(), "r");
+ input = mContentResolver.openFileDescriptor(mUri, "r");
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapManager.instance().decodeFileDescriptor(
@@ -343,8 +299,8 @@ public abstract class BaseImage implements IImage {
long id = mId;
long dbMagic = mMiniThumbMagic;
if (dbMagic == 0 || dbMagic == id) {
- dbMagic = ((BaseImageList) getContainer())
- .checkThumbnail(this, getRow(), null);
+ dbMagic = ((BaseImageList)
+ getContainer()).checkThumbnail(this, null);
}
synchronized (sMiniThumbData) {
@@ -355,8 +311,7 @@ public abstract class BaseImage implements IImage {
byte[][] createdThumbData = new byte[1][];
try {
dbMagic = ((BaseImageList) getContainer())
- .checkThumbnail(this, getRow(),
- createdThumbData);
+ .checkThumbnail(this, createdThumbData);
} catch (IOException ex) {
// Typically IOException because the sd card is full.
// But createdThumbData may have been filled in, so
@@ -388,8 +343,7 @@ public abstract class BaseImage implements IImage {
}
}
- public void onRemove() {
- mContainer.mCache.remove(mId);
+ protected void onRemove() {
}
protected void saveMiniThumb(Bitmap source) throws IOException {
@@ -397,25 +351,21 @@ public abstract class BaseImage implements IImage {
}
public void setTitle(String name) {
- Cursor c = getCursor();
- synchronized (c) {
- if (c.moveToPosition(getRow())) {
- c.updateString(mContainer.indexTitle(), name);
- c.commitUpdates();
- }
- }
+ if (mTitle.equals(name)) return;
+ mTitle = name;
+ ContentValues values = new ContentValues();
+ values.put(ImageColumns.TITLE, name);
+ mContentResolver.update(mUri, values, null, null);
}
public Uri thumbUri() {
- Uri uri = fullSizeImageUri();
// The value for the query parameter cannot be null :-(,
// so using a dummy "1"
- uri = uri.buildUpon().appendQueryParameter("thumb", "1").build();
- return uri;
+ return mUri.buildUpon().appendQueryParameter("thumb", "1").build();
}
@Override
public String toString() {
- return fullSizeImageUri().toString();
+ return mUri.toString();
}
}
diff --git a/src/com/android/camera/gallery/BaseImageList.java b/src/com/android/camera/gallery/BaseImageList.java
index ee56f80..1d29231 100644
--- a/src/com/android/camera/gallery/BaseImageList.java
+++ b/src/com/android/camera/gallery/BaseImageList.java
@@ -17,7 +17,6 @@
package com.android.camera.gallery;
import com.android.camera.ExifInterface;
-import com.android.camera.ImageManager;
import com.android.camera.Util;
import android.content.ContentResolver;
@@ -27,31 +26,35 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
+import android.os.SystemClock;
import android.provider.BaseColumns;
-import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.Images.Thumbnails;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
-import java.util.HashMap;
+import java.util.Random;
/**
* A collection of <code>BaseImage</code>s.
*/
public abstract class BaseImageList implements IImageList {
private static final String TAG = "BaseImageList";
+ private static final int CACHE_CAPACITY = 512;
+ private final LruCache<Integer, BaseImage> mCache =
+ new LruCache<Integer, BaseImage>(CACHE_CAPACITY);
protected ContentResolver mContentResolver;
protected int mSort;
+
protected Uri mBaseUri;
protected Cursor mCursor;
- protected boolean mCursorDeactivated;
protected String mBucketId;
- protected HashMap<Long, IImage> mCache = new HashMap<Long, IImage>();
protected MiniThumbFile mMiniThumbFile;
protected Uri mThumbUri;
+ protected boolean mCursorDeactivated = false;
public BaseImageList(ContentResolver cr, Uri uri, int sort,
String bucketId) {
@@ -60,16 +63,15 @@ public abstract class BaseImageList implements IImageList {
mBucketId = bucketId;
mContentResolver = cr;
mMiniThumbFile = new MiniThumbFile(uri);
+ mCursor = createCursor();
}
/**
* Store a given thumbnail in the database.
*/
- protected Bitmap storeThumbnail(Bitmap thumb, long imageId) {
+ protected Bitmap storeThumbnail(Bitmap thumb, Uri uri) {
if (thumb == null) return null;
try {
- Uri uri = getThumbnailUri(
- imageId, thumb.getWidth(), thumb.getHeight());
if (uri == null) {
return thumb;
}
@@ -111,39 +113,32 @@ public abstract class BaseImageList implements IImageList {
};
private Uri getThumbnailUri(long imageId, int width, int height) {
+
// we do not store thumbnails for DRM'd images
if (mThumbUri == null) {
return null;
}
- Uri uri = null;
-
Cursor c = mContentResolver.query(mThumbUri, THUMB_PROJECTION,
Thumbnails.IMAGE_ID + "=?",
new String[]{String.valueOf(imageId)}, null);
try {
- if (c.moveToFirst()) {
- // If, for some reason, we already have a row with a matching
- // image id, then just update that row rather than creating a
- // new row.
- uri = ContentUris.withAppendedId(mThumbUri, c.getLong(0));
+ if (c.moveToNext()) {
+ return ContentUris.withAppendedId(mThumbUri, c.getLong(0));
}
} finally {
c.close();
}
- if (uri == null) {
- ContentValues values = new ContentValues(4);
- values.put(Images.Thumbnails.KIND, Images.Thumbnails.MINI_KIND);
- values.put(Images.Thumbnails.IMAGE_ID, imageId);
- values.put(Images.Thumbnails.HEIGHT, height);
- values.put(Images.Thumbnails.WIDTH, width);
- uri = mContentResolver.insert(mThumbUri, values);
- }
- return uri;
+ ContentValues values = new ContentValues(4);
+ values.put(Thumbnails.KIND, Thumbnails.MINI_KIND);
+ values.put(Thumbnails.IMAGE_ID, imageId);
+ values.put(Thumbnails.HEIGHT, height);
+ values.put(Thumbnails.WIDTH, width);
+ return mContentResolver.insert(mThumbUri, values);
}
- private static final java.util.Random sRandom =
- new java.util.Random(System.currentTimeMillis());
+ private static final Random sRandom =
+ new Random(System.currentTimeMillis());
// If the photo has an EXIF thumbnail and it's big enough, extract it and
// save that JPEG as the large thumbnail without re-encoding it. We still
@@ -190,12 +185,11 @@ public abstract class BaseImageList implements IImageList {
// The fallback case is to decode the original photo to thumbnail size,
// then encode it as a JPEG. We return the thumbnail Bitmap in order to
// create the minithumb from it.
- private Bitmap createThumbnailFromUri(Cursor c, long id) {
- Uri uri = ContentUris.withAppendedId(mBaseUri, id);
+ private Bitmap createThumbnailFromUri(Uri uri) {
Bitmap bitmap = Util.makeBitmap(IImage.THUMBNAIL_TARGET_SIZE, uri,
mContentResolver);
if (bitmap != null) {
- storeThumbnail(bitmap, id);
+ storeThumbnail(bitmap, uri);
} else {
bitmap = Util.makeBitmap(IImage.MINI_THUMB_TARGET_SIZE, uri,
mContentResolver);
@@ -204,14 +198,12 @@ public abstract class BaseImageList implements IImageList {
}
public void checkThumbnail(int index) throws IOException {
- checkThumbnail(null, index, null);
+ checkThumbnail((BaseImage) getImageAt(index), null);
}
/**
* Checks to see if a mini thumbnail exists in the cache. If not, tries to
* create it and add it to the cache.
- * @param existingImage
- * @param i
* @param createdThumbnailData if this parameter is non-null, and a new
* mini-thumbnail bitmap is created, the new bitmap's data will be
* stored in createdThumbnailData[0]. Note that if the sdcard is
@@ -221,26 +213,12 @@ public abstract class BaseImageList implements IImageList {
* thumbnail even if the sdcard is full.
* @throws IOException
*/
- public long checkThumbnail(BaseImage existingImage, int i,
+ public long checkThumbnail(BaseImage existingImage,
byte[][] createdThumbnailData) throws IOException {
long magic, id;
- Cursor c = getCursor();
- if (existingImage == null) {
- // if we don't have an Image object then get the id and magic
- // from the cursor. Synchronize on the cursor object.
- synchronized (c) {
- if (!c.moveToPosition(i)) {
- return -1;
- }
- magic = c.getLong(indexMiniThumbMagic());
- id = c.getLong(indexId());
- }
- } else {
- // if we have an Image object then ask them for the magic/id
- magic = existingImage.mMiniThumbMagic;
- id = existingImage.fullSizeImageId();
- }
+ magic = existingImage.mMiniThumbMagic;
+ id = existingImage.fullSizeImageId();
if (magic != 0) {
long fileMagic = mMiniThumbFile.getMagic(id);
@@ -253,32 +231,23 @@ public abstract class BaseImageList implements IImageList {
// embedded in the EXIF data. If not, or it's not big enough,
// decompress the full size image.
Bitmap bitmap = null;
- String filePath = null;
- synchronized (c) {
- if (c.moveToPosition(i)) {
- filePath = c.getString(indexData());
- }
- }
+ String filePath = existingImage.getDataPath();
+
if (filePath != null) {
- String mimeType = c.getString(indexMimeType());
+ String mimeType = existingImage.getMimeType();
boolean isVideo = Util.isVideoMimeType(mimeType);
if (isVideo) {
bitmap = Util.createVideoThumbnail(filePath);
} else {
bitmap = createThumbnailFromEXIF(filePath, id);
if (bitmap == null) {
- bitmap = createThumbnailFromUri(c, id);
+ bitmap = createThumbnailFromUri(
+ ContentUris.withAppendedId(mBaseUri, id));
}
}
- synchronized (c) {
- int degrees = 0;
- if (c.moveToPosition(i)) {
- int column = indexOrientation();
- if (column >= 0) degrees = c.getInt(column);
- }
- if (degrees != 0) {
- bitmap = Util.rotate(bitmap, degrees);
- }
+ int degrees = existingImage.getDegreesRotated();
+ if (degrees != 0) {
+ bitmap = Util.rotate(bitmap, degrees);
}
}
@@ -286,6 +255,7 @@ public abstract class BaseImageList implements IImageList {
do {
magic = sRandom.nextLong();
} while (magic == 0);
+
if (bitmap != null) {
byte [] data = Util.miniThumbData(bitmap);
if (createdThumbnailData != null) {
@@ -294,21 +264,18 @@ public abstract class BaseImageList implements IImageList {
saveMiniThumbToFile(data, id, magic);
}
- synchronized (c) {
- c.moveToPosition(i);
- c.updateLong(indexMiniThumbMagic(), magic);
- c.commitUpdates();
- c.requery();
- c.moveToPosition(i);
-
- if (existingImage != null) {
- existingImage.mMiniThumbMagic = magic;
- }
- return magic;
- }
+ ContentValues values = new ContentValues();
+ values.put(ImageColumns.MINI_THUMB_MAGIC, magic);
+ mContentResolver.update(
+ existingImage.fullSizeImageUri(), values, null, null);
+ existingImage.mMiniThumbMagic = magic;
+ return magic;
}
- protected Uri contentUri(long id) {
+ // TODO: Change public to protected
+ public Uri contentUri(long id) {
+
+ // TODO: avoid using exception for most cases
try {
// does our uri already have an id (single image query)?
// if so just return it
@@ -322,9 +289,8 @@ public abstract class BaseImageList implements IImageList {
}
public void deactivate() {
- mCursorDeactivated = true;
try {
- mCursor.deactivate();
+ invalidateCursor();
} catch (IllegalStateException e) {
// IllegalStateException may be thrown if the cursor is stale.
Log.e(TAG, "Caught exception while deactivating cursor.", e);
@@ -333,13 +299,9 @@ public abstract class BaseImageList implements IImageList {
}
public int getCount() {
- Cursor c = getCursor();
- synchronized (c) {
- try {
- return c.getCount();
- } catch (RuntimeException ex) {
- return 0;
- }
+ Cursor cursor = getCursor();
+ synchronized (cursor) {
+ return cursor.getCount();
}
}
@@ -347,57 +309,28 @@ public abstract class BaseImageList implements IImageList {
return getCount() == 0;
}
- protected Cursor getCursor() {
+ private Cursor getCursor() {
synchronized (mCursor) {
if (mCursorDeactivated) {
- activateCursor();
+ mCursor.requery();
+ mCursorDeactivated = false;
}
return mCursor;
}
}
- protected void activateCursor() {
- requery();
- }
-
public IImage getImageAt(int i) {
- Cursor c = getCursor();
- synchronized (c) {
- boolean moved;
- try {
- moved = c.moveToPosition(i);
- } catch (RuntimeException ex) {
- return null;
- }
- if (moved) {
- try {
- long id = c.getLong(indexId());
- IImage img = mCache.get(id);
- if (img == null) {
- long miniThumbMagic = 0;
- int rotation = 0;
- if (indexMiniThumbMagic() != -1) {
- miniThumbMagic = c.getLong(indexMiniThumbMagic());
- }
- if (indexOrientation() != -1) {
- rotation = c.getInt(indexOrientation());
- }
- img = make(id, miniThumbMagic, mContentResolver, this,
- i, rotation);
- mCache.put(id, img);
- }
- return img;
- } catch (RuntimeException ex) {
- Log.e(TAG, "got this exception trying to create image: "
- + ex);
- return null;
- }
- } else {
- Log.e(TAG, "unable to moveTo to " + i + "; count is "
- + c.getCount());
- return null;
+ BaseImage result = mCache.get(i);
+ if (result == null) {
+ Cursor cursor = getCursor();
+ synchronized (cursor) {
+ result = cursor.moveToPosition(i)
+ ? loadImageFromCursor(cursor)
+ : null;
+ mCache.put(i, result);
}
}
+ return result;
}
byte [] getMiniThumbFromFile(long id, byte [] data, long magicCheck) {
@@ -414,81 +347,36 @@ public abstract class BaseImageList implements IImageList {
mMiniThumbFile.saveMiniThumbToFile(data, id, magic);
}
- protected abstract int indexId();
-
- protected abstract int indexData();
-
- protected abstract int indexMimeType();
-
- protected abstract int indexDateTaken();
-
- protected abstract int indexMiniThumbMagic();
-
- protected abstract int indexOrientation();
+ public boolean removeImage(IImage image) {
+ // TODO: need to delete the thumbnails as well
+ if (mContentResolver.delete(image.fullSizeImageUri(), null, null) > 0) {
+ ((BaseImage) image).onRemove();
+ invalidateCursor();
+ invalidateCache();
+ return true;
+ } else {
+ return false;
+ }
+ }
- protected abstract int indexTitle();
+ public boolean removeImageAt(int i) {
+ // TODO: need to delete the thumbnails as well
+ return removeImage(getImageAt(i));
+ }
- protected abstract int indexDisplayName();
+ abstract protected Cursor createCursor();
- protected IImage make(long id, long miniThumbMagic, ContentResolver cr,
- IImageList list, int index, int rotation) {
- return null;
- }
+ abstract protected BaseImage loadImageFromCursor(Cursor cursor);
- public boolean removeImage(IImage image) {
- Cursor c = getCursor();
- synchronized (c) {
- /*
- * TODO: consider putting the image in a holding area so
- * we can get it back as needed
- * TODO: need to delete the thumbnails as well
- */
- boolean moved;
- try {
- moved = c.moveToPosition(image.getRow());
- } catch (RuntimeException ex) {
- Log.e(TAG, "removeImage got exception " + ex.toString());
- return false;
- }
- if (moved) {
- Uri u = image.fullSizeImageUri();
- mContentResolver.delete(u, null, null);
- image.onRemove();
- requery();
- }
- }
- return true;
- }
+ abstract protected long getImageId(Cursor cursor);
- public void removeImageAt(int i) {
- Cursor c = getCursor();
- synchronized (c) {
- /*
- * TODO: consider putting the image in a holding area so
- * we can get it back as needed
- * TODO: need to delete the thumbnails as well
- */
- IImage image = getImageAt(i);
- boolean moved;
- try {
- moved = c.moveToPosition(i);
- } catch (RuntimeException ex) {
- Log.e(TAG, "removeImageAt " + i + " get " + ex);
- return;
- }
- if (moved) {
- Uri u = image.fullSizeImageUri();
- mContentResolver.delete(u, null, null);
- requery();
- image.onRemove();
- }
- }
+ protected void invalidateCursor() {
+ mCursor.deactivate();
+ mCursorDeactivated = true;
}
- protected void requery() {
+ protected void invalidateCache() {
mCache.clear();
- mCursor.requery();
- mCursorDeactivated = false;
}
public IImage getImageForUri(Uri uri) {
@@ -497,20 +385,26 @@ public abstract class BaseImageList implements IImageList {
try {
matchId = ContentUris.parseId(uri);
} catch (NumberFormatException ex) {
+ Log.i(TAG, "fail to get id in: " + uri, ex);
return null;
}
-
- // Go through the data and find the entry with the matching id.
- Cursor c = getCursor();
- synchronized (c) {
- int index = indexId();
- if (!c.moveToFirst()) return null;
- do {
- if (matchId == c.getLong(index)) {
- return getImageAt(c.getPosition());
+ // TODO: design a better method to get URI of specified ID
+ long startTimestamp = SystemClock.elapsedRealtime();
+ Cursor cursor = getCursor();
+ synchronized (cursor) {
+ cursor.moveToPosition(-1); // before first
+ for (int i = 0; cursor.moveToNext(); ++i) {
+ if (getImageId(cursor) == matchId) {
+ Log.v(TAG, "find object at " + i + ", it takes"
+ + (SystemClock.elapsedRealtime() - startTimestamp));
+ return loadImageFromCursor(cursor);
}
- } while (c.moveToNext());
+ }
return null;
}
}
+
+ public int getImageIndex(IImage image) {
+ return ((BaseImage) image).mIndex;
+ }
}
diff --git a/src/com/android/camera/gallery/DrmImageList.java b/src/com/android/camera/gallery/DrmImageList.java
index 383211a..2a55343 100644
--- a/src/com/android/camera/gallery/DrmImageList.java
+++ b/src/com/android/camera/gallery/DrmImageList.java
@@ -29,12 +29,17 @@ import android.provider.DrmStore;
*/
public class DrmImageList extends ImageList implements IImageList {
+ // TODO: get other field from database too ?
private static final String[] DRM_IMAGE_PROJECTION = new String[] {
- DrmStore.Audio._ID,
- DrmStore.Audio.DATA,
- DrmStore.Audio.MIME_TYPE,
+ DrmStore.Images._ID,
+ DrmStore.Images.DATA,
+ DrmStore.Images.MIME_TYPE,
};
+ private static final int INDEX_ID = 0;
+ private static final int INDEX_DATA_PATH = 1;
+ private static final int INDEX_MIME_TYPE = 2;
+
public DrmImageList(ContentResolver cr, Uri imageUri,
int sort, String bucketId) {
super(cr, imageUri, null, sort, bucketId);
@@ -52,9 +57,12 @@ public class DrmImageList extends ImageList implements IImageList {
private static class DrmImage extends Image {
- protected DrmImage(long id, ContentResolver cr,
- BaseImageList container, int cursorRow) {
- super(id, 0, cr, container, cursorRow, 0);
+ protected DrmImage(BaseImageList container, ContentResolver cr,
+ long id, int index, Uri uri, String dataPath, long miniThumbMagic,
+ String mimeType, long dateTaken, String title,
+ String displayName, int rotation) {
+ super(container, cr, id, index, uri, dataPath, miniThumbMagic,
+ mimeType, dateTaken, title, displayName, rotation);
}
@Override
@@ -84,54 +92,18 @@ public class DrmImageList extends ImageList implements IImageList {
}
@Override
- protected IImage make(long id, long miniThumbMagic, ContentResolver cr,
- IImageList list, int index, int rotation) {
- return new DrmImage(id, mContentResolver, this, index);
- }
-
-
- @Override
- protected int indexId() {
- return -1;
- }
-
- @Override
- protected int indexData() {
- return -1;
- }
-
- @Override
- protected int indexMimeType() {
- return -1;
- }
-
- @Override
- protected int indexDateTaken() {
- return -1;
- }
-
- @Override
- protected int indexMiniThumbMagic() {
- return -1;
- }
-
- @Override
- protected int indexOrientation() {
- return -1;
- }
-
- @Override
- protected int indexTitle() {
- return -1;
- }
-
- @Override
- protected int indexDisplayName() {
- return -1;
+ protected BaseImage loadImageFromCursor(Cursor cursor) {
+ long id = cursor.getLong(INDEX_ID);
+ String dataPath = cursor.getString(INDEX_DATA_PATH);
+ String mimeType = cursor.getString(INDEX_MIME_TYPE);
+ return new DrmImage(this, mContentResolver, id, cursor.getPosition(),
+ contentUri(id), dataPath, 0, mimeType, 0, "DrmImage-" + id,
+ "DrmImage-" + id, 0);
}
// TODO: Review this probably should be based on DATE_TAKEN same as images
- private String sortOrder() {
+ @Override
+ protected String sortOrder() {
String ascending =
mSort == ImageManager.SORT_ASCENDING ? " ASC" : " DESC";
return DrmStore.Images.TITLE + ascending + "," + DrmStore.Images._ID;
diff --git a/src/com/android/camera/gallery/IImage.java b/src/com/android/camera/gallery/IImage.java
index 9c47d13..17030f0 100644
--- a/src/com/android/camera/gallery/IImage.java
+++ b/src/com/android/camera/gallery/IImage.java
@@ -52,9 +52,13 @@ public interface IImage {
// Get metadata of the image
public abstract long getDateTaken();
+
public abstract String getMimeType();
+
public abstract int getWidth();
+
public abstract int getHeight();
+
public abstract String getDisplayName();
// Get property of the image
@@ -68,13 +72,7 @@ public interface IImage {
// Get the bitmap of the mini thumbnail.
public abstract Bitmap miniThumbBitmap();
- // Get the row number for this image in the database table.
- public abstract int getRow();
-
// Rotate the image
public abstract boolean rotateImageBy(int degrees);
- // This is called if the image is removed.
- public abstract void onRemove();
-
}
diff --git a/src/com/android/camera/gallery/IImageList.java b/src/com/android/camera/gallery/IImageList.java
index 26fb017..b334e67 100644
--- a/src/com/android/camera/gallery/IImageList.java
+++ b/src/com/android/camera/gallery/IImageList.java
@@ -89,7 +89,9 @@ public interface IImageList {
* Removes the image at the ith position.
* @param i the position
*/
- public abstract void removeImageAt(int i);
+ public abstract boolean removeImageAt(int i);
+
+ public int getImageIndex(IImage image);
/**
* Generate thumbnail for the image (if it has not been generated.)
diff --git a/src/com/android/camera/gallery/Image.java b/src/com/android/camera/gallery/Image.java
index 8c208e2..5c09aba 100644
--- a/src/com/android/camera/gallery/Image.java
+++ b/src/com/android/camera/gallery/Image.java
@@ -22,17 +22,20 @@ import com.android.camera.Util;
import android.content.ContentResolver;
import android.content.ContentUris;
+import android.content.ContentValues;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
+import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.Images.Thumbnails;
import android.util.Log;
import java.io.FileNotFoundException;
import java.io.IOException;
+import java.util.HashMap;
import java.util.concurrent.ExecutionException;
/**
@@ -41,45 +44,34 @@ import java.util.concurrent.ExecutionException;
public class Image extends BaseImage implements IImage {
private static final String TAG = "BaseImage";
- private int mRotation;
+ private HashMap<String, String> mExifData;
+
private ExifInterface mExif;
+ private int mRotation;
- public Image(long id, long miniThumbMagic, ContentResolver cr,
- BaseImageList container, int cursorRow, int rotation) {
- super(id, miniThumbMagic, cr, container, cursorRow);
+ public Image(BaseImageList container, ContentResolver cr,
+ long id, int index, Uri uri, String dataPath, long miniThumbMagic,
+ String mimeType, long dateTaken, String title, String displayName,
+ int rotation) {
+ super(container, cr, id, index, uri, dataPath, miniThumbMagic,
+ mimeType, dateTaken, title, displayName);
mRotation = rotation;
}
- public String getDataPath() {
- String path = null;
- Cursor c = getCursor();
- synchronized (c) {
- if (c.moveToPosition(getRow())) {
- int column = ((ImageList) getContainer()).indexData();
- if (column >= 0)
- path = c.getString(column);
- }
- }
- return path;
- }
-
@Override
protected int getDegreesRotated() {
return mRotation;
}
protected void setDegreesRotated(int degrees) {
- Cursor c = getCursor();
+ if (mRotation == degrees) return;
mRotation = degrees;
- synchronized (c) {
- if (c.moveToPosition(getRow())) {
- int column = ((ImageList) getContainer()).indexOrientation();
- if (column >= 0) {
- c.updateInt(column, degrees);
- c.commitUpdates();
- }
- }
- }
+ ContentValues values = new ContentValues();
+ values.put(ImageColumns.ORIENTATION, mRotation);
+ mContentResolver.update(mUri, values, null, null);
+
+ //TODO: Consider invalidate the cursor in container
+ // ((BaseImageList) getContainer()).invalidateCursor();
}
@Override
@@ -94,7 +86,7 @@ public class Image extends BaseImage implements IImage {
}
/**
- * Does not replace the tag if already there. Otherwise, adds to the exif
+ * Does not replace the tag if already there. Otherwise, adds to the EXIF
* tags.
*
* @param tag
@@ -111,8 +103,7 @@ public class Image extends BaseImage implements IImage {
}
/**
- * Return the value of the Exif tag as an int. Returns 0 on any type of
- * error.
+ * Returns the value of the EXIF tag as an integer.
*
* @param tag
*/
@@ -130,7 +121,7 @@ public class Image extends BaseImage implements IImage {
}
/**
- * Return the value of the Exif tag as a String. It's caller's
+ * Return the value of the EXIF tag as a String. It's caller's
* responsibility to check nullity.
*/
public String getExifTag(String tag) {
@@ -219,7 +210,7 @@ public class Image extends BaseImage implements IImage {
}
mContainer.storeThumbnail(
- thumbnail, Image.this.fullSizeImageId());
+ thumbnail, Image.this.fullSizeImageUri());
if (isCanceling()) return null;
try {
@@ -240,12 +231,7 @@ public class Image extends BaseImage implements IImage {
}
private void loadExifData() {
- Cursor c = getCursor();
- String filePath;
- synchronized (c) {
- filePath = c.getString(mContainer.indexData());
- }
- mExif = new ExifInterface(filePath);
+ mExif = new ExifInterface(mDataPath);
if (mExifData == null) {
mExifData = mExif.getAttributes();
}
@@ -301,7 +287,7 @@ public class Image extends BaseImage implements IImage {
// fresh thumbs
mMiniThumbMagic = 0;
try {
- mContainer.checkThumbnail(this, this.getRow(), null);
+ mContainer.checkThumbnail(this, null);
} catch (IOException e) {
// Ignore inability to store mini thumbnail.
}
@@ -335,7 +321,7 @@ public class Image extends BaseImage implements IImage {
if (bitmap == null) {
bitmap = fullSizeBitmap(THUMBNAIL_TARGET_SIZE, false);
// No thumbnail found... storing the new one.
- bitmap = mContainer.storeThumbnail(bitmap, fullSizeImageId());
+ bitmap = mContainer.storeThumbnail(bitmap, fullSizeImageUri());
}
if (bitmap != null) {
diff --git a/src/com/android/camera/gallery/ImageList.java b/src/com/android/camera/gallery/ImageList.java
index c39fe4d..2c96265 100644
--- a/src/com/android/camera/gallery/ImageList.java
+++ b/src/com/android/camera/gallery/ImageList.java
@@ -17,16 +17,12 @@
package com.android.camera.gallery;
import com.android.camera.ImageManager;
-import com.android.camera.Util;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
-import android.provider.BaseColumns;
import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Images.ImageColumns;
-import android.provider.MediaStore.MediaColumns;
-import android.util.Log;
+import android.provider.MediaStore.Images.Media;
import java.util.HashMap;
@@ -36,6 +32,7 @@ import java.util.HashMap;
*/
public class ImageList extends BaseImageList implements IImageList {
+ @SuppressWarnings("unused")
private static final String TAG = "ImageList";
private static final String[] ACCEPTABLE_IMAGE_TYPES =
@@ -44,129 +41,103 @@ public class ImageList extends BaseImageList implements IImageList {
public HashMap<String, String> getBucketIds() {
Uri uri = mBaseUri.buildUpon()
.appendQueryParameter("distinct", "true").build();
- Cursor c = Images.Media.query(
+ Cursor cursor = Media.query(
mContentResolver, uri,
new String[] {
- ImageColumns.BUCKET_DISPLAY_NAME,
- ImageColumns.BUCKET_ID},
- whereClause(), whereClauseArgs(), sortOrder());
-
- HashMap<String, String> hash = new HashMap<String, String>();
- if (c != null && c.moveToFirst()) {
- do {
- hash.put(c.getString(1), c.getString(0));
- } while (c.moveToNext());
+ Media.BUCKET_DISPLAY_NAME,
+ Media.BUCKET_ID},
+ whereClause(), whereClauseArgs(), null);
+ try {
+ HashMap<String, String> hash = new HashMap<String, String>();
+ while (cursor.moveToNext()) {
+ hash.put(cursor.getString(1), cursor.getString(0));
+ }
+ return hash;
+ } finally {
+ cursor.close();
}
- return hash;
}
+
/**
* ImageList constructor.
- * @param cr ContentResolver
*/
public ImageList(ContentResolver cr, Uri imageUri,
Uri thumbUri, int sort, String bucketId) {
super(cr, imageUri, sort, bucketId);
mThumbUri = thumbUri;
-
- mCursor = createCursor();
- if (mCursor == null) {
- Log.e(TAG, "unable to create image cursor for " + mBaseUri);
- throw new UnsupportedOperationException();
- }
}
private static final String WHERE_CLAUSE =
- "(" + Images.Media.MIME_TYPE + " in (?, ?, ?))";
+ "(" + Media.MIME_TYPE + " in (?, ?, ?))";
+ private static final String WHERE_CLAUSE_WITH_BUCKET_ID =
+ WHERE_CLAUSE + " AND " + Media.BUCKET_ID + " = ?";
+
protected String whereClause() {
- if (mBucketId != null) {
- return WHERE_CLAUSE + " and " + Images.Media.BUCKET_ID + " = '"
- + mBucketId + "'";
- } else {
- return WHERE_CLAUSE;
- }
+ return mBucketId == null ? WHERE_CLAUSE : WHERE_CLAUSE_WITH_BUCKET_ID;
}
protected String[] whereClauseArgs() {
+ // TODO: Since mBucketId won't change, we should keep the array.
+ if (mBucketId != null) {
+ int count = ACCEPTABLE_IMAGE_TYPES.length;
+ String[] result = new String[count + 1];
+ System.arraycopy(ACCEPTABLE_IMAGE_TYPES, 0, result, 0, count);
+ result[count] = mBucketId;
+ return result;
+ }
return ACCEPTABLE_IMAGE_TYPES;
}
+ @Override
protected Cursor createCursor() {
- Cursor c = Images.Media.query(
+ Cursor c = Media.query(
mContentResolver, mBaseUri, IMAGE_PROJECTION,
whereClause(), whereClauseArgs(), sortOrder());
return c;
}
static final String[] IMAGE_PROJECTION = new String[] {
- BaseColumns._ID,
- MediaColumns.DATA,
- ImageColumns.DATE_TAKEN,
- ImageColumns.MINI_THUMB_MAGIC,
- ImageColumns.ORIENTATION,
- ImageColumns.MIME_TYPE};
-
- private static final int INDEX_ID
- = Util.indexOf(IMAGE_PROJECTION, BaseColumns._ID);
- private static final int INDEX_DATA =
- Util.indexOf(IMAGE_PROJECTION, MediaColumns.DATA);
- private static final int INDEX_MIME_TYPE =
- Util.indexOf(IMAGE_PROJECTION, MediaColumns.MIME_TYPE);
- private static final int INDEX_DATE_TAKEN =
- Util.indexOf(IMAGE_PROJECTION, ImageColumns.DATE_TAKEN);
- private static final int INDEX_MINI_THUMB_MAGIC =
- Util.indexOf(IMAGE_PROJECTION, ImageColumns.MINI_THUMB_MAGIC);
- private static final int INDEX_ORIENTATION =
- Util.indexOf(IMAGE_PROJECTION, ImageColumns.ORIENTATION);
-
- @Override
- protected int indexId() {
- return INDEX_ID;
- }
-
- @Override
- protected int indexData() {
- return INDEX_DATA;
- }
+ Media._ID,
+ Media.DATA,
+ Media.DATE_TAKEN,
+ Media.MINI_THUMB_MAGIC,
+ Media.ORIENTATION,
+ Media.TITLE,
+ Media.MIME_TYPE};
+
+ private static final int INDEX_ID = 0;
+ private static final int INDEX_DATA_PATH = 1;
+ private static final int INDEX_DATE_TAKEN = 2;
+ private static final int INDEX_MINI_THUMB_MAGIC = 3;
+ private static final int INDEX_ORIENTATION = 4;
+ private static final int INDEX_TITLE = 5;
+ private static final int INDEX_MIME_TYPE = 6;
@Override
- protected int indexMimeType() {
- return INDEX_MIME_TYPE;
+ protected long getImageId(Cursor cursor) {
+ return cursor.getLong(INDEX_ID);
}
@Override
- protected int indexDateTaken() {
- return INDEX_DATE_TAKEN;
- }
-
- @Override
- protected int indexMiniThumbMagic() {
- return INDEX_MINI_THUMB_MAGIC;
- }
-
- @Override
- protected int indexOrientation() {
- return INDEX_ORIENTATION;
- }
-
- @Override
- protected int indexTitle() {
- return -1;
- }
-
- @Override
- protected int indexDisplayName() {
- return -1;
- }
-
- @Override
- protected IImage make(long id, long miniThumbMagic, ContentResolver cr,
- IImageList list, int index, int rotation) {
- return new Image(id, miniThumbMagic, mContentResolver, this, index,
- rotation);
+ protected BaseImage loadImageFromCursor(Cursor cursor) {
+ long id = cursor.getLong(INDEX_ID);
+ String dataPath = cursor.getString(INDEX_DATA_PATH);
+ long dateTaken = cursor.getLong(INDEX_DATE_TAKEN);
+ long miniThumbMagic = cursor.getLong(INDEX_MINI_THUMB_MAGIC);
+ int orientation = cursor.getInt(INDEX_ORIENTATION);
+ String title = cursor.getString(INDEX_TITLE);
+ String mimeType = cursor.getString(INDEX_MIME_TYPE);
+ if (title == null || title.length() == 0) {
+ title = dataPath;
+ }
+ String displayName = title;
+ return new Image(this, mContentResolver, id, cursor.getPosition(),
+ contentUri(id), dataPath, miniThumbMagic, mimeType, dateTaken,
+ title, displayName, orientation);
}
- private String sortOrder() {
+ protected String sortOrder() {
// add id to the end so that we don't ever get random sorting
// which could happen, I suppose, if the first two values were
// duplicated
diff --git a/src/com/android/camera/gallery/ImageListUber.java b/src/com/android/camera/gallery/ImageListUber.java
index 1ffd94b..d5e96c5 100644
--- a/src/com/android/camera/gallery/ImageListUber.java
+++ b/src/com/android/camera/gallery/ImageListUber.java
@@ -17,30 +17,51 @@
package com.android.camera.gallery;
import com.android.camera.ImageManager;
+import com.android.camera.Util;
import android.net.Uri;
import java.io.IOException;
-import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
import java.util.HashMap;
+import java.util.PriorityQueue;
/**
* A union of different <code>IImageList</code>.
*/
+//TODO: add unittest for this class
public class ImageListUber implements IImageList {
@SuppressWarnings("unused")
private static final String TAG = "ImageListUber";
private final IImageList [] mSubList;
- private final int mSort;
-
- // This is an array of Longs wherein each Long consists of
- // two components. The first component indicates the number of
- // consecutive entries that belong to a given sublist.
- // The second component indicates which sublist we're referring
- // to (an int which is used to index into mSubList).
- private ArrayList<Long> mSkipList = null;
+ private final PriorityQueue<MergeSlot> mQueue;
+
+ // This is an array of Longs wherein each Long consists of two components:
+ // "a number" and "an index of sublist".
+ // * The lower 32bit indicates the number of consecutive entries that
+ // belong to a given sublist.
+ //
+ // * The higher 32bit component indicates which sublist we're referring
+ // to.
+ private long[] mSkipList = new long[16];
+ private int mSkipListSize = 0;
private int [] mSkipCounts = null;
+ private int mLastListIndex = -1;
+
+ public ImageListUber(IImageList [] sublist, int sort) {
+ mSubList = sublist.clone();
+ mSkipCounts = new int[mSubList.length];
+ mQueue = new PriorityQueue<MergeSlot>(4,
+ sort == ImageManager.SORT_ASCENDING
+ ? new AscendingComparator()
+ : new DescendingComparator());
+ for (int i = 0, n = sublist.length; i < n; ++i) {
+ MergeSlot slot = new MergeSlot(sublist[i], i);
+ if (slot.next()) mQueue.add(slot);
+ }
+ }
public HashMap<String, String> getBucketIds() {
HashMap<String, String> hashMap = new HashMap<String, String>();
@@ -50,47 +71,37 @@ public class ImageListUber implements IImageList {
return hashMap;
}
- public ImageListUber(IImageList [] sublist, int sort) {
- mSubList = sublist.clone();
- mSort = sort;
- }
-
public void checkThumbnail(int index) throws IOException {
+ // The index is not refer to the index of the image but in another order
+ // sequence. Since this function is only used to check all thumbnails
+ // is created, it should be fine.
for (IImageList list : mSubList) {
int count = list.getCount();
if (count > index) {
list.checkThumbnail(index);
+ return;
}
index -= count;
}
}
public void deactivate() {
- final IImageList sublist[] = mSubList;
- final int length = sublist.length;
- int pos = -1;
- while (++pos < length) {
- IImageList sub = sublist[pos];
- sub.deactivate();
+ for (IImageList subList : mSubList) {
+ subList.deactivate();
}
}
public int getCount() {
- final IImageList sublist[] = mSubList;
- final int length = sublist.length;
int count = 0;
- for (int i = 0; i < length; i++)
- count += sublist[i].getCount();
+ for (IImageList subList : mSubList) {
+ count += subList.getCount();
+ }
return count;
}
public boolean isEmpty() {
- final IImageList sublist[] = mSubList;
- final int length = sublist.length;
- for (int i = 0; i < length; i++) {
- if (!sublist[i].isEmpty()) {
- return false;
- }
+ for (IImageList subList : mSubList) {
+ if (!subList.isEmpty()) return false;
}
return true;
}
@@ -106,20 +117,10 @@ public class ImageListUber implements IImageList {
"index " + index + " out of range max is " + getCount());
}
- // first make sure our allocations are in order
- if (mSkipCounts == null || mSubList.length > mSkipCounts.length) {
- mSkipCounts = new int[mSubList.length];
- }
-
- if (mSkipList == null) {
- mSkipList = new ArrayList<Long>();
- }
-
+ int skipCounts[] = mSkipCounts;
// zero out the mSkipCounts since that's only used for the
// duration of the function call.
- for (int i = 0; i < mSubList.length; i++) {
- mSkipCounts[i] = 0;
- }
+ Arrays.fill(skipCounts, 0);
// a counter of how many images we've skipped in
// trying to get to index. alternatively we could
@@ -129,87 +130,53 @@ public class ImageListUber implements IImageList {
// scan the existing mSkipList to see if we've computed
// enough to just return the answer
- for (int i = 0; i < mSkipList.size(); i++) {
- long v = mSkipList.get(i);
+ for (int i = 0, n = mSkipListSize; i < n; ++i) {
+ long v = mSkipList[i];
int offset = (int) (v & 0xFFFFFFFF);
int which = (int) (v >> 32);
-
if (skipCount + offset > index) {
int subindex = mSkipCounts[which] + (index - skipCount);
- IImage img = mSubList[which].getImageAt(subindex);
- return img;
+ return mSubList[which].getImageAt(subindex);
}
-
skipCount += offset;
mSkipCounts[which] += offset;
}
- // if we get here we haven't computed the answer for
- // "index" yet so keep computing. This means running
- // through the list of images and either modifying the
- // last entry or creating a new one.
- while (true) {
- // We are merging the sublists into this uber list.
- // We pick the next image by choosing the one with
- // max/min timestamp from the next image of each sublists.
- // Then we record this fact in mSkipList (which encodes
- // sublist number in a run-length encoding fashion).
- long maxTimestamp = mSort == ImageManager.SORT_ASCENDING
- ? Long.MAX_VALUE
- : Long.MIN_VALUE;
- int which = -1;
- for (int i = 0; i < mSubList.length; i++) {
- int pos = mSkipCounts[i];
- IImageList list = mSubList[i];
- if (pos < list.getCount()) {
- IImage image = list.getImageAt(pos);
- // this should never be null but sometimes the database is
- // causing problems and it is null
- if (image != null) {
- long timestamp = image.getDateTaken();
- if (mSort == ImageManager.SORT_ASCENDING
- ? (timestamp < maxTimestamp)
- : (timestamp > maxTimestamp)) {
- maxTimestamp = timestamp;
- which = i;
- }
- }
- }
- }
-
- if (which == -1) {
- return null;
- }
-
- boolean done = false;
- if (mSkipList.size() > 0) {
- int pos = mSkipList.size() - 1;
- long oldEntry = mSkipList.get(pos);
- if ((oldEntry >> 32) == which) {
- long newEntry = oldEntry + 1;
- mSkipList.set(pos, newEntry);
- done = true;
- }
- }
- if (!done) {
- long newEntry = ((long) which << 32) | 1; // initial count = 1
- mSkipList.add(newEntry);
+ for (;true; ++skipCount) {
+ MergeSlot slot = nextMergeSlot();
+ if (slot == null) return null;
+ if (skipCount == index) {
+ IImage result = slot.mImage;
+ if (slot.next()) mQueue.add(slot);
+ return result;
}
+ if (slot.next()) mQueue.add(slot);
+ }
+ }
- if (skipCount++ == index) {
- return mSubList[which].getImageAt(mSkipCounts[which]);
+ private MergeSlot nextMergeSlot() {
+ MergeSlot slot = mQueue.poll();
+ if (slot == null) return null;
+ if (slot.mListIndex == mLastListIndex) {
+ int lastIndex = mSkipListSize - 1;
+ ++ mSkipList[lastIndex];
+ } else {
+ mLastListIndex = slot.mListIndex;
+ if (mSkipList.length == mSkipListSize) {
+ long [] temp = new long[mSkipListSize * 2];
+ System.arraycopy(mSkipList, 0, temp, 0, mSkipListSize);
+ mSkipList = temp;
}
- mSkipCounts[which] += 1;
+ mSkipList[mSkipListSize++] = (((long) mLastListIndex) << 32) | 1;
}
+ return slot;
}
public IImage getImageForUri(Uri uri) {
- // TODO: perhaps we can preflight the base of the uri
- // against each sublist first
- for (int i = 0; i < mSubList.length; i++) {
- IImage img = mSubList[i].getImageForUri(uri);
- if (img != null) return img;
+ for (IImageList sublist : mSubList) {
+ IImage image = sublist.getImageForUri(uri);
+ if (image != null) return image;
}
return null;
}
@@ -220,51 +187,111 @@ public class ImageListUber implements IImageList {
* counter. This is simple because deletion can never
* cause change the order of images.
*/
- public void modifySkipCountForDeletedImage(int index) {
+ private void modifySkipCountForDeletedImage(int index) {
int skipCount = 0;
-
- for (int i = 0; i < mSkipList.size(); i++) {
- long v = mSkipList.get(i);
-
+ for (int i = 0, n = mSkipListSize; i < n; i++) {
+ long v = mSkipList[i];
int offset = (int) (v & 0xFFFFFFFF);
int which = (int) (v >> 32);
-
if (skipCount + offset > index) {
- mSkipList.set(i, v - 1);
+ mSkipList[i] = v - 1;
break;
}
-
skipCount += offset;
}
}
+ private boolean removeImage(IImage image, int index) {
+ IImageList list = image.getContainer();
+ if (list != null && list.removeImage(image)) {
+ modifySkipCountForDeletedImage(index);
+ return true;
+ }
+ return false;
+ }
+
public boolean removeImage(IImage image) {
- IImageList parent = image.getContainer();
- int pos = -1;
- int baseIndex = 0;
- while (++pos < mSubList.length) {
- IImageList sub = mSubList[pos];
- if (sub == parent) {
- if (sub.removeImage(image)) {
- modifySkipCountForDeletedImage(baseIndex);
- return true;
- } else {
- break;
+ return removeImage(image, getImageIndex(image));
+ }
+
+ public boolean removeImageAt(int index) {
+ IImage image = getImageAt(index);
+ if (image == null) return false;
+ return removeImage(image, index);
+ }
+
+ public synchronized int getImageIndex(IImage image) {
+ IImageList list = image.getContainer();
+ int listIndex = Util.indexOf(mSubList, list);
+ if (listIndex == -1) {
+ throw new IllegalArgumentException();
+ }
+ int listOffset = list.getImageIndex(image);
+
+ // Similar algorithm as getImageAt(int index)
+ int skipCount = 0;
+ for (int i = 0, n = mSkipListSize; i < n; ++i) {
+ long value = mSkipList[i];
+ int offset = (int) (value & 0xFFFFFFFF);
+ int which = (int) (value >> 32);
+ if (which == listIndex) {
+ if (listOffset < offset) {
+ return skipCount + listOffset;
}
+ listOffset -= offset;
}
- baseIndex += sub.getCount();
+ skipCount += offset;
+ }
+
+ for (;true; ++skipCount) {
+ MergeSlot slot = nextMergeSlot();
+ if (slot == null) return -1;
+ if (slot.mImage == image) {
+ if (slot.next()) mQueue.add(slot);
+ return skipCount;
+ }
+ if (slot.next()) mQueue.add(slot);
+ }
+ }
+
+ private static class DescendingComparator implements Comparator<MergeSlot> {
+
+ public int compare(MergeSlot m1, MergeSlot m2) {
+ if (m1.mDateTaken != m2.mDateTaken) {
+ return m1.mDateTaken < m2.mDateTaken ? -1 : 1;
+ }
+ return m1.mListIndex - m2.mListIndex;
}
- return false;
}
- public void removeImageAt(int index) {
- IImage img = getImageAt(index);
- if (img != null) {
- IImageList list = img.getContainer();
- if (list != null) {
- list.removeImage(img);
- modifySkipCountForDeletedImage(index);
+ private static class AscendingComparator implements Comparator<MergeSlot> {
+
+ public int compare(MergeSlot m1, MergeSlot m2) {
+ if (m1.mDateTaken != m2.mDateTaken) {
+ return m1.mDateTaken < m2.mDateTaken ? -1 : 1;
}
+ return m1.mListIndex - m2.mListIndex;
+ }
+ }
+
+ private static class MergeSlot {
+ private int mOffset = -1;
+ private final IImageList mList;
+
+ int mListIndex;
+ long mDateTaken;
+ IImage mImage;
+
+ public MergeSlot(IImageList list, int index) {
+ mList = list;
+ mListIndex = index;
+ }
+
+ public boolean next() {
+ if (mOffset >= mList.getCount() - 1) return false;
+ mImage = mList.getImageAt(++mOffset);
+ mDateTaken = mImage.getDateTaken();
+ return true;
}
}
}
diff --git a/src/com/android/camera/gallery/LruCache.java b/src/com/android/camera/gallery/LruCache.java
new file mode 100644
index 0000000..fb18c99
--- /dev/null
+++ b/src/com/android/camera/gallery/LruCache.java
@@ -0,0 +1,19 @@
+package com.android.camera.gallery;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class LruCache<K, V> extends LinkedHashMap<K, V> {
+
+ private final int mCapacity;
+
+ public LruCache(int capacity) {
+ super(16, 0.75f, true);
+ this.mCapacity = capacity;
+ }
+
+ @Override
+ protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
+ return size() > mCapacity;
+ }
+}
diff --git a/src/com/android/camera/gallery/SingleImageList.java b/src/com/android/camera/gallery/SingleImageList.java
index 026cbee..6feca73 100644
--- a/src/com/android/camera/gallery/SingleImageList.java
+++ b/src/com/android/camera/gallery/SingleImageList.java
@@ -19,6 +19,7 @@ package com.android.camera.gallery;
import com.android.camera.ImageManager;
import android.content.ContentResolver;
+import android.database.Cursor;
import android.net.Uri;
import java.util.HashMap;
@@ -27,7 +28,8 @@ import java.util.HashMap;
* An implementation of interface <code>IImageList</code> which contains only
* one image.
*/
-public class SingleImageList extends BaseImageList implements IImageList {
+// TODO: consider implements not extends
+public class SingleImageList extends BaseImageList {
@SuppressWarnings("unused")
private static final String TAG = "BaseImageList";
@@ -59,52 +61,28 @@ public class SingleImageList extends BaseImageList implements IImageList {
}
@Override
- public IImage getImageAt(int i) {
- return i == 0 ? mSingleImage : null;
- }
-
- @Override
- public IImage getImageForUri(Uri uri) {
- return uri.equals(mBaseUri) ? mSingleImage : null;
- }
-
- @Override
- protected int indexId() {
- return -1;
- }
-
- @Override
- protected int indexData() {
- return -1;
- }
-
- @Override
- protected int indexMimeType() {
- return -1;
+ protected long getImageId(Cursor cursor) {
+ throw new UnsupportedOperationException();
}
- @Override
- protected int indexDateTaken() {
- return -1;
- }
@Override
- protected int indexMiniThumbMagic() {
- return -1;
+ public IImage getImageAt(int i) {
+ return i == 0 ? mSingleImage : null;
}
@Override
- protected int indexOrientation() {
- return -1;
+ public IImage getImageForUri(Uri uri) {
+ return uri.equals(mBaseUri) ? mSingleImage : null;
}
@Override
- protected int indexTitle() {
- return -1;
+ protected Cursor createCursor() {
+ throw new UnsupportedOperationException();
}
@Override
- protected int indexDisplayName() {
- return -1;
+ protected BaseImage loadImageFromCursor(Cursor cursor) {
+ throw new UnsupportedOperationException();
}
}
diff --git a/src/com/android/camera/gallery/UriImage.java b/src/com/android/camera/gallery/UriImage.java
index dd62c39..8a8415e 100644
--- a/src/com/android/camera/gallery/UriImage.java
+++ b/src/com/android/camera/gallery/UriImage.java
@@ -221,10 +221,6 @@ class UriImage implements IImage {
return false;
}
- public void onRemove() {
- throw new UnsupportedOperationException();
- }
-
public boolean rotateImageBy(int degrees) {
return false;
}
diff --git a/src/com/android/camera/gallery/VideoList.java b/src/com/android/camera/gallery/VideoList.java
index e95aa02..9f40dc2 100644
--- a/src/com/android/camera/gallery/VideoList.java
+++ b/src/com/android/camera/gallery/VideoList.java
@@ -17,69 +17,62 @@
package com.android.camera.gallery;
import com.android.camera.ImageManager;
-import com.android.camera.Util;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore.Images;
-import android.provider.MediaStore.Video;
-import android.provider.MediaStore.Video.VideoColumns;
-import android.util.Log;
+import android.provider.MediaStore.Video.Media;
import java.util.HashMap;
/**
* A collection of all the <code>VideoObject</code> in gallery.
*/
-public class VideoList extends BaseImageList implements IImageList {
+public class VideoList extends BaseImageList {
+
+ @SuppressWarnings("unused")
private static final String TAG = "BaseImageList";
private static final String[] VIDEO_PROJECTION = new String[] {
- Video.Media._ID,
- Video.Media.DATA,
- Video.Media.DATE_TAKEN,
- Video.Media.TITLE,
- Video.Media.DISPLAY_NAME,
- Video.Media.TAGS,
- Video.Media.CATEGORY,
- Video.Media.LANGUAGE,
- Video.Media.MINI_THUMB_MAGIC,
- Video.Media.MIME_TYPE};
-
- private static final int INDEX_ID = indexOf(Video.Media._ID);
- private static final int INDEX_DATA = indexOf(Video.Media.DATA);
- private static final int INDEX_DATE_TAKEN = indexOf(Video.Media.DATE_TAKEN);
- private static final int INDEX_TITLE = indexOf(Video.Media.TITLE);
- private static final int INDEX_DISPLAY_NAME =
- indexOf(Video.Media.DISPLAY_NAME);
- private static final int INDEX_MIME_TYPE = indexOf(Video.Media.MIME_TYPE);
- private static final int INDEX_MINI_THUMB_MAGIC =
- indexOf(Video.Media.MINI_THUMB_MAGIC);
-
- private static int indexOf(String field) {
- return Util.indexOf(VIDEO_PROJECTION, field);
+ Media._ID,
+ Media.DATA,
+ Media.DATE_TAKEN,
+ Media.TITLE,
+ Media.DISPLAY_NAME,
+ Media.MINI_THUMB_MAGIC,
+ Media.MIME_TYPE};
+
+ private static final int INDEX_ID = 0;
+ private static final int INDEX_DATA_PATH = 1;
+ private static final int INDEX_DATE_TAKEN = 2;
+ private static final int INDEX_TITLE = 3;
+ private static final int INDEX_DISPLAY_NAME = 4;
+ private static final int INDEX_MIMI_THUMB_MAGIC = 5;
+ private static final int INDEX_MIME_TYPE = 6;
+
+ @Override
+ protected long getImageId(Cursor cursor) {
+ return cursor.getLong(INDEX_ID);
}
- public VideoList(ContentResolver cr, Uri uri, Uri thumbUri,
- int sort, String bucketId) {
- super(cr, uri, sort, bucketId);
+ @Override
+ protected BaseImage loadImageFromCursor(Cursor cursor) {
+ long id = cursor.getLong(INDEX_ID);
+ String dataPath = cursor.getString(INDEX_DATA_PATH);
+ long dateTaken = cursor.getLong(INDEX_DATE_TAKEN);
+ String title = cursor.getString(INDEX_TITLE);
+ String displayName = cursor.getString(INDEX_DISPLAY_NAME);
+ long miniThumbMagic = cursor.getLong(INDEX_MIMI_THUMB_MAGIC);
+ String mimeType = cursor.getString(INDEX_MIME_TYPE);
- mCursor = createCursor();
- if (mCursor == null) {
- Log.e(TAG, "unable to create video cursor for " + mBaseUri);
- throw new UnsupportedOperationException();
- }
+ return new VideoObject(this, mContentResolver,
+ id, cursor.getPosition(), contentUri(id), dataPath,
+ miniThumbMagic, mimeType, dateTaken, title, displayName);
+ }
- if (mCursor.moveToFirst()) {
- int row = 0;
- do {
- long imageId = mCursor.getLong(indexId());
- long miniThumbMagic = mCursor.getLong(indexMiniThumbMagic());
- mCache.put(imageId, new VideoObject(imageId, miniThumbMagic,
- mContentResolver, this, row++));
- } while (mCursor.moveToNext());
- }
+ public VideoList(ContentResolver cr, Uri uri, int sort, String bucketId) {
+ super(cr, uri, sort, bucketId);
}
public HashMap<String, String> getBucketIds() {
@@ -88,31 +81,32 @@ public class VideoList extends BaseImageList implements IImageList {
Cursor c = Images.Media.query(
mContentResolver, uri,
new String[] {
- VideoColumns.BUCKET_DISPLAY_NAME,
- VideoColumns.BUCKET_ID
+ Media.BUCKET_DISPLAY_NAME,
+ Media.BUCKET_ID
},
whereClause(), whereClauseArgs(), sortOrder());
- HashMap<String, String> hash = new HashMap<String, String>();
- if (c != null && c.moveToFirst()) {
- do {
+ try {
+ HashMap<String, String> hash = new HashMap<String, String>();
+ while (c.moveToNext()) {
hash.put(c.getString(1), c.getString(0));
- } while (c.moveToNext());
+ }
+ return hash;
+ } finally {
+ c.close();
}
- return hash;
}
protected String whereClause() {
- if (mBucketId != null) {
- return Images.Media.BUCKET_ID + " = '" + mBucketId + "'";
- } else {
- return null;
- }
+ return mBucketId != null
+ ? Images.Media.BUCKET_ID + " = '" + mBucketId + "'"
+ : null;
}
protected String[] whereClauseArgs() {
return null;
}
+ @Override
protected Cursor createCursor() {
Cursor c = Images.Media.query(
mContentResolver, mBaseUri, VIDEO_PROJECTION,
@@ -120,55 +114,8 @@ public class VideoList extends BaseImageList implements IImageList {
return c;
}
- @Override
- protected int indexId() {
- return INDEX_ID;
- }
-
- @Override
- protected int indexData() {
- return INDEX_DATA;
- }
-
- @Override
- protected int indexMimeType() {
- return INDEX_MIME_TYPE;
- }
-
- @Override
- protected int indexDateTaken() {
- return INDEX_DATE_TAKEN;
- }
-
- @Override
- protected int indexMiniThumbMagic() {
- return INDEX_MINI_THUMB_MAGIC;
- }
-
- @Override
- protected int indexOrientation() {
- return -1;
- }
-
- @Override
- protected int indexTitle() {
- return INDEX_TITLE;
- }
-
- @Override
- protected int indexDisplayName() {
- return -1;
- }
-
- @Override
- protected IImage make(long id, long miniThumbMagic, ContentResolver cr,
- IImageList list, int index, int rotation) {
- return new VideoObject(id, miniThumbMagic, mContentResolver, this,
- index);
- }
-
private String sortOrder() {
- return Video.Media.DATE_TAKEN +
+ return Media.DATE_TAKEN +
(mSort == ImageManager.SORT_ASCENDING ? " ASC " : " DESC");
}
} \ No newline at end of file
diff --git a/src/com/android/camera/gallery/VideoObject.java b/src/com/android/camera/gallery/VideoObject.java
index a5ed17e..5da63bf 100644
--- a/src/com/android/camera/gallery/VideoObject.java
+++ b/src/com/android/camera/gallery/VideoObject.java
@@ -19,8 +19,8 @@ package com.android.camera.gallery;
import com.android.camera.ImageManager;
import android.content.ContentResolver;
-import android.database.Cursor;
import android.graphics.Bitmap;
+import android.net.Uri;
import java.io.IOException;
import java.io.InputStream;
@@ -38,9 +38,11 @@ public class VideoObject extends BaseImage implements IImage {
* @param id the image id of the image
* @param cr the content resolver
*/
- protected VideoObject(long id, long miniThumbMagic, ContentResolver cr,
- VideoList container, int row) {
- super(id, miniThumbMagic, cr, container, row);
+ protected VideoObject(BaseImageList container, ContentResolver cr,
+ long id, int index, Uri uri, String dataPath, long miniThumbMagic,
+ String mimeType, long dateTaken, String title, String displayName) {
+ super(container, cr, id, index, uri, dataPath, miniThumbMagic,
+ mimeType, dateTaken, title, displayName);
}
@Override
@@ -60,18 +62,6 @@ public class VideoObject extends BaseImage implements IImage {
return fullSizeImageUri().toString().hashCode();
}
- public String getDataPath() {
- String path = null;
- Cursor c = getCursor();
- synchronized (c) {
- if (c.moveToPosition(getRow())) {
- int column = ((VideoList) getContainer()).indexData();
- if (column >= 0) path = c.getString(column);
- }
- }
- return path;
- }
-
@Override
public Bitmap fullSizeBitmap(int targetWidthHeight) {
return ImageManager.NO_IMAGE_BITMAP;
@@ -127,8 +117,6 @@ public class VideoObject extends BaseImage implements IImage {
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- sb.append("" + mId);
- return sb.toString();
+ return new StringBuilder("VideoObject").append(mId).toString();
}
} \ No newline at end of file