summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorChih-Chung Chang <>2009-04-14 00:25:27 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-04-14 00:25:27 -0700
commit9d6fbf9660a0c3d289c539e0275272d31b0ef596 (patch)
tree012d448c833aec53f8650530d6f1f636217a3f37 /src
parent96f917e4ce07855341d31684c1ba51aad80d9e5a (diff)
downloadLegacyCamera-9d6fbf9660a0c3d289c539e0275272d31b0ef596.zip
LegacyCamera-9d6fbf9660a0c3d289c539e0275272d31b0ef596.tar.gz
LegacyCamera-9d6fbf9660a0c3d289c539e0275272d31b0ef596.tar.bz2
AI 146085: Extract mini-thumb handling code to a separate class.
Automated import of CL 146085
Diffstat (limited to 'src')
-rw-r--r--src/com/android/camera/gallery/BaseImage.java4
-rw-r--r--src/com/android/camera/gallery/BaseImageList.java216
-rw-r--r--src/com/android/camera/gallery/MiniThumbFile.java196
3 files changed, 216 insertions, 200 deletions
diff --git a/src/com/android/camera/gallery/BaseImage.java b/src/com/android/camera/gallery/BaseImage.java
index 85fa102..f11cc26 100644
--- a/src/com/android/camera/gallery/BaseImage.java
+++ b/src/com/android/camera/gallery/BaseImage.java
@@ -44,8 +44,8 @@ public abstract class BaseImage implements IImage {
private static final boolean VERBOSE = false;
private static final String TAG = "BaseImage";
- static final int BYTES_PER_MINTHUMB = 10000;
- private static final byte [] sMiniThumbData = new byte[BYTES_PER_MINTHUMB];
+ private static final byte [] sMiniThumbData =
+ new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
protected ContentResolver mContentResolver;
protected long mId, mMiniThumbMagic;
diff --git a/src/com/android/camera/gallery/BaseImageList.java b/src/com/android/camera/gallery/BaseImageList.java
index 0b5e33b..49b43d3 100644
--- a/src/com/android/camera/gallery/BaseImageList.java
+++ b/src/com/android/camera/gallery/BaseImageList.java
@@ -26,25 +26,20 @@ import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
-import android.os.Environment;
-import android.os.Handler;
import android.os.ParcelFileDescriptor;
import android.provider.BaseColumns;
import android.provider.MediaStore.Images;
-import android.provider.MediaStore.MediaColumns;
import android.provider.MediaStore.Images.ImageColumns;
import android.provider.MediaStore.Images.Thumbnails;
+import android.provider.MediaStore.MediaColumns;
import android.util.Log;
import com.android.camera.ExifInterface;
import com.android.camera.ImageManager;
-import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
-import java.io.RandomAccessFile;
-import java.util.ArrayList;
import java.util.HashMap;
/**
@@ -108,7 +103,7 @@ public abstract class BaseImageList implements IImageList {
protected Context mContext;
protected Uri mUri;
protected HashMap<Long, IImage> mCache = new HashMap<Long, IImage>();
- protected RandomAccessFile mMiniThumbFile;
+ protected MiniThumbFile mMiniThumbFile;
protected Uri mThumbUri;
public BaseImageList(Context ctx, ContentResolver cr, Uri uri, int sort,
@@ -119,34 +114,7 @@ public abstract class BaseImageList implements IImageList {
mBaseUri = uri;
mBucketId = bucketId;
mContentResolver = cr;
- }
-
- String randomAccessFilePath(int version) {
- String directoryName =
- Environment.getExternalStorageDirectory().toString()
- + "/DCIM/.thumbnails";
- return directoryName + "/.thumbdata" + version + "-" + mUri.hashCode();
- }
-
- RandomAccessFile miniThumbDataFile() {
- if (mMiniThumbFile == null) {
- String path = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION);
- File directory = new File(new File(path).getParent());
- if (!directory.isDirectory()) {
- if (!directory.mkdirs()) {
- Log.e(TAG, "!!!! unable to create .thumbnails directory "
- + directory.toString());
- }
- }
- File f = new File(path);
- if (VERBOSE) Log.v(TAG, "file f is " + f.toString());
- try {
- mMiniThumbFile = new RandomAccessFile(f, "rw");
- } catch (IOException ex) {
- // ignore exception
- }
- }
- return mMiniThumbFile;
+ mMiniThumbFile = new MiniThumbFile(uri);
}
/**
@@ -312,11 +280,10 @@ public abstract class BaseImageList implements IImageList {
*/
public long checkThumbnail(BaseImage existingImage, Cursor c, int i,
byte[][] createdThumbnailData) throws IOException {
- long magic, fileMagic = 0, id;
+ long magic, id;
if (BitmapManager.instance().acquireResourceLock() == false) {
return -1;
}
- Log.v(TAG, "checkThumbnail: i="+i);
try {
if (existingImage == null) {
@@ -336,35 +303,9 @@ public abstract class BaseImageList implements IImageList {
}
if (magic != 0) {
- // check the mini thumb file for the right data. Right is
- // defined as having the right magic number at the offset
- // reserved for this "id".
- RandomAccessFile r = miniThumbDataFile();
- if (r != null) {
- synchronized (r) {
- long pos = id * BaseImage.BYTES_PER_MINTHUMB;
- try {
- // check that we can read the following 9 bytes
- // (1 for the "status" and 8 for the long)
- if (r.length() >= pos + 1 + 8) {
- r.seek(pos);
- if (r.readByte() == 1) {
- fileMagic = r.readLong();
- if (fileMagic == magic && magic != 0
- && magic != id) {
- return magic;
- }
- }
- }
- } catch (IOException ex) {
- Log.v(TAG, "got exception checking file magic: "
- + ex);
- }
- }
- }
- if (VERBOSE) {
- Log.v(TAG, "didn't verify... fileMagic: " + fileMagic
- + "; magic: " + magic + "; id: " + id + "; ");
+ long fileMagic = mMiniThumbFile.getMagic(id);
+ if (fileMagic == magic && magic != 0 && magic != id) {
+ return magic;
}
}
@@ -414,7 +355,6 @@ public abstract class BaseImageList implements IImageList {
}
synchronized (c) {
- Log.v(TAG, "checkThumbnail: moveToPosition i="+i);
c.moveToPosition(i);
c.updateLong(indexMiniThumbId(), magic);
c.commitUpdates();
@@ -451,16 +391,6 @@ public abstract class BaseImageList implements IImageList {
return;
}
- String oldPath = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION - 1);
- File oldFile = new File(oldPath);
-
- if (count == 0) {
- // now check that we have the right thumbs file
- if (!oldFile.exists()) {
- return;
- }
- }
-
c = getCursor();
try {
if (VERBOSE) Log.v(TAG, "checkThumbnails found " + c.getCount());
@@ -488,11 +418,6 @@ public abstract class BaseImageList implements IImageList {
Log.v(TAG, "checkThumbnails existing after reaching count "
+ c.getCount());
}
- try {
- oldFile.delete();
- } catch (SecurityException ex) {
- // ignore
- }
}
}
@@ -531,14 +456,7 @@ public abstract class BaseImageList implements IImageList {
// IllegalStateException may be thrown if the cursor is stale.
Log.e(TAG, "Caught exception while deactivating cursor.", e);
}
- if (mMiniThumbFile != null) {
- try {
- mMiniThumbFile.close();
- mMiniThumbFile = null;
- } catch (IOException ex) {
- // ignore exception
- }
- }
+ mMiniThumbFile.deactivate();
}
public void dump(String msg) {
@@ -633,60 +551,17 @@ public abstract class BaseImageList implements IImageList {
}
byte [] getMiniThumbFromFile(long id, byte [] data, long magicCheck) {
- RandomAccessFile r = miniThumbDataFile();
- if (r == null) return null;
-
- long pos = id * BaseImage.BYTES_PER_MINTHUMB;
- synchronized (r) {
- try {
- r.seek(pos);
- if (r.readByte() == 1) {
- long magic = r.readLong();
- if (magic != magicCheck) {
- if (VERBOSE) {
- Log.v(TAG, "for id " + id + "; magic: " + magic
- + "; magicCheck: " + magicCheck
- + " (fail)");
- }
- return null;
- }
- int length = r.readInt();
- r.read(data, 0, length);
- return data;
- } else {
- return null;
- }
- } catch (IOException ex) {
- long fileLength;
- try {
- fileLength = r.length();
- } catch (IOException ex1) {
- fileLength = -1;
- }
- if (VERBOSE) {
- Log.e(TAG, "couldn't read thumbnail for " + id + "; "
- + ex.toString() + "; pos is " + pos + "; length is "
- + fileLength);
- }
- return null;
- }
- }
+ return mMiniThumbFile.getMiniThumbFromFile(id, data, magicCheck);
}
- protected int getRowFor(IImage imageObj) {
- Cursor c = getCursor();
- synchronized (c) {
- int index = 0;
- long targetId = imageObj.fullSizeImageId();
- if (c.moveToFirst()) {
- do {
- if (c.getLong(0) == targetId) {
- return index;
- }
- index += 1;
- } while (c.moveToNext());
- }
- return -1;
- }
+
+ void saveMiniThumbToFile(Bitmap bitmap, long id, long magic)
+ throws IOException {
+ mMiniThumbFile.saveMiniThumbToFile(bitmap, id, magic);
+ }
+
+ void saveMiniThumbToFile(byte[] data, long id, long magic)
+ throws IOException {
+ mMiniThumbFile.saveMiniThumbToFile(data, id, magic);
}
protected abstract int indexOrientation();
@@ -773,59 +648,4 @@ public abstract class BaseImageList implements IImageList {
mCursor.requery();
mCursorDeactivated = false;
}
-
- protected void saveMiniThumbToFile(Bitmap bitmap, long id, long magic)
- throws IOException {
- byte[] data = Util.miniThumbData(bitmap);
- saveMiniThumbToFile(data, id, magic);
- }
-
- protected void saveMiniThumbToFile(byte[] data, long id, long magic)
- throws IOException {
- RandomAccessFile r = miniThumbDataFile();
- if (r == null) return;
-
- long pos = id * BaseImage.BYTES_PER_MINTHUMB;
- long t0 = System.currentTimeMillis();
- synchronized (r) {
- try {
- long t1 = System.currentTimeMillis();
- long t2 = System.currentTimeMillis();
- if (data != null) {
- if (data.length > BaseImage.BYTES_PER_MINTHUMB) {
- if (VERBOSE) {
- Log.v(TAG, "warning: " + data.length + " > "
- + BaseImage.BYTES_PER_MINTHUMB);
- }
- return;
- }
- r.seek(pos);
- r.writeByte(0); // we have no data in this slot
-
- // if magic is 0 then leave it alone
- if (magic == 0) {
- r.skipBytes(8);
- } else {
- r.writeLong(magic);
- }
- r.writeInt(data.length);
- r.write(data);
- // f.flush();
- r.seek(pos);
- r.writeByte(1); // we have data in this slot
- long t3 = System.currentTimeMillis();
-
- if (VERBOSE) {
- Log.v(TAG, "saveMiniThumbToFile took " + (t3 - t0)
- + "; " + (t1 - t0) + " " + (t2 - t1) + " "
- + (t3 - t2));
- }
- }
- } catch (IOException ex) {
- Log.e(TAG, "couldn't save mini thumbnail data for "
- + id + "; " + ex.toString());
- throw ex;
- }
- }
- }
}
diff --git a/src/com/android/camera/gallery/MiniThumbFile.java b/src/com/android/camera/gallery/MiniThumbFile.java
new file mode 100644
index 0000000..e2c825c
--- /dev/null
+++ b/src/com/android/camera/gallery/MiniThumbFile.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2009 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.camera.gallery;
+
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+// This class handles the mini-thumb file. A mini-thumb file consists
+// of blocks, indexed by id. Each block has BYTES_PER_MINTHUMB bytes in the
+// following format:
+//
+// 1 byte status (0 = empty, 1 = mini-thumb available)
+// 8 bytes magic (a magic number to match what's in the database)
+// 4 bytes data length (LEN)
+// LEN bytes jpeg data
+// (the remaining bytes are unused)
+//
+class MiniThumbFile {
+ private static final String TAG = "MiniThumbFile";
+ private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
+ public static final int BYTES_PER_MINTHUMB = 10000;
+ private static final int HEADER_SIZE = 1 + 8 + 4;
+ private static final byte [] sMiniThumbData = new byte[BYTES_PER_MINTHUMB];
+ private Uri mUri;
+ private RandomAccessFile mMiniThumbFile;
+
+ private String randomAccessFilePath(int version) {
+ String directoryName =
+ Environment.getExternalStorageDirectory().toString()
+ + "/DCIM/.thumbnails";
+ return directoryName + "/.thumbdata" + version + "-" + mUri.hashCode();
+ }
+
+ private void removeOldFile() {
+ String oldPath = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION - 1);
+ File oldFile = new File(oldPath);
+ if (!oldFile.exists()) {
+ try {
+ oldFile.delete();
+ } catch (SecurityException ex) {
+ // ignore
+ }
+ }
+ }
+
+ private RandomAccessFile miniThumbDataFile() {
+ if (mMiniThumbFile == null) {
+ removeOldFile();
+ String path = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION);
+ File directory = new File(path).getParentFile();
+ if (!directory.isDirectory()) {
+ if (!directory.mkdirs()) {
+ Log.e(TAG, "Unable to create .thumbnails directory "
+ + directory.toString());
+ }
+ }
+ File f = new File(path);
+ try {
+ mMiniThumbFile = new RandomAccessFile(f, "rw");
+ } catch (IOException ex) {
+ // ignore exception
+ }
+ }
+ return mMiniThumbFile;
+ }
+
+ public MiniThumbFile(Uri uri) {
+ mUri = uri;
+ }
+
+ public void deactivate() {
+ if (mMiniThumbFile != null) {
+ try {
+ mMiniThumbFile.close();
+ mMiniThumbFile = null;
+ } catch (IOException ex) {
+ // ignore exception
+ }
+ }
+ }
+
+ // Get the magic number for the specified id in the mini-thumb file.
+ // Returns 0 if the magic is not available.
+ public long getMagic(long id) {
+ // check the mini thumb file for the right data. Right is
+ // defined as having the right magic number at the offset
+ // reserved for this "id".
+ RandomAccessFile r = miniThumbDataFile();
+ if (r != null) {
+ synchronized (r) {
+ long pos = id * BYTES_PER_MINTHUMB;
+ try {
+ // check that we can read the following 9 bytes
+ // (1 for the "status" and 8 for the long)
+ if (r.length() >= pos + 1 + 8) {
+ r.seek(pos);
+ if (r.readByte() == 1) {
+ long fileMagic = r.readLong();
+ return fileMagic;
+ }
+ }
+ } catch (IOException ex) {
+ Log.v(TAG, "Got exception checking file magic: ", ex);
+ }
+ }
+ }
+ return 0;
+ }
+
+ public void saveMiniThumbToFile(Bitmap bitmap, long id, long magic)
+ throws IOException {
+ byte[] data = Util.miniThumbData(bitmap);
+ saveMiniThumbToFile(data, id, magic);
+ }
+
+ public void saveMiniThumbToFile(byte[] data, long id, long magic)
+ throws IOException {
+ RandomAccessFile r = miniThumbDataFile();
+ if (r == null) return;
+
+ long pos = id * BYTES_PER_MINTHUMB;
+ long t0 = System.currentTimeMillis();
+ synchronized (r) {
+ try {
+ if (data != null) {
+ if (data.length > BYTES_PER_MINTHUMB - HEADER_SIZE) {
+ // not enough space to store it.
+ return;
+ }
+ r.seek(pos);
+ r.writeByte(0); // we have no data in this slot
+
+ // if magic is 0 then leave it alone
+ if (magic == 0) {
+ r.skipBytes(8);
+ } else {
+ r.writeLong(magic);
+ }
+ r.writeInt(data.length);
+ r.write(data);
+ r.seek(pos);
+ r.writeByte(1); // we have data in this slot
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "couldn't save mini thumbnail data for "
+ + id + "; ", ex);
+ throw ex;
+ }
+ }
+ }
+
+ byte [] getMiniThumbFromFile(long id, byte [] data, long magicCheck) {
+ RandomAccessFile r = miniThumbDataFile();
+ if (r == null) return null;
+
+ long pos = id * BYTES_PER_MINTHUMB;
+ synchronized (r) {
+ try {
+ r.seek(pos);
+ if (r.readByte() == 1) {
+ long magic = r.readLong();
+ if (magic != magicCheck) {
+ return null;
+ }
+ int length = r.readInt();
+ r.read(data, 0, length);
+ return data;
+ } else {
+ return null;
+ }
+ } catch (IOException ex) {
+ return null;
+ }
+ }
+ }
+}