summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--media/java/android/media/MiniThumbFile.java163
1 files changed, 160 insertions, 3 deletions
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 63b149c..9825857 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -45,8 +45,14 @@ import java.util.Hashtable;
*/
public class MiniThumbFile {
private static final String TAG = "MiniThumbFile";
- private static final int MINI_THUMB_DATA_FILE_VERSION = 3;
+ private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
public static final int BYTES_PER_MINTHUMB = 10000;
+
+ private static final int BYTES_PER_MINTHUMB_INDEX = 8;
+ private FileChannel mIndexChannel;
+ private RandomAccessFile mMiniThumbIndexFile;
+ private final boolean debug = false;;
+
private static final int HEADER_SIZE = 1 + 8 + 4;
private Uri mUri;
private RandomAccessFile mMiniThumbFile;
@@ -98,6 +104,57 @@ public class MiniThumbFile {
}
}
+ private String randomAccessIndexFilePath(int version) {
+ String directoryName =
+ Environment.getExternalStorageDirectory().toString()
+ + "/DCIM/.thumbnails";
+ return directoryName + "/.thumbindex" + version + "-" + mUri.hashCode();
+ }
+
+ private void removeOldIndexFile() {
+ String oldPath = randomAccessIndexFilePath(MINI_THUMB_DATA_FILE_VERSION - 1);
+ File oldFile = new File(oldPath);
+ if (oldFile.exists()) {
+ try {
+ oldFile.delete();
+ } catch (SecurityException ex) {
+ // ignore
+ }
+ }
+ }
+
+ private RandomAccessFile miniThumbIndexFile() {
+ if (mMiniThumbIndexFile == null) {
+ removeOldIndexFile();
+ String path = randomAccessIndexFilePath(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 {
+ mMiniThumbIndexFile = new RandomAccessFile(f, "rw");
+ } catch (IOException ex) {
+ // Open as read-only so we can at least read the existing
+ // thumbnails.
+ try {
+ mMiniThumbIndexFile = new RandomAccessFile(f, "r");
+ } catch (IOException ex2) {
+ // ignore exception
+ Log.e(TAG, "miniThumbIndexFile open r exception: " + f);
+ }
+ }
+ if (mMiniThumbIndexFile != null) {
+ mIndexChannel = mMiniThumbIndexFile.getChannel();
+ }
+ }
+ return mMiniThumbIndexFile;
+ }
+
private RandomAccessFile miniThumbDataFile() {
if (mMiniThumbFile == null) {
removeOldFile();
@@ -128,6 +185,8 @@ public class MiniThumbFile {
return mMiniThumbFile;
}
+
+
public MiniThumbFile(Uri uri) {
mUri = uri;
mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
@@ -144,6 +203,94 @@ public class MiniThumbFile {
}
}
+ /**
+ * Get the index of thumbnail, which is the real saving location.
+ * @param id the raw id in Mediaprovider database.
+ * @param create when you want to create a new thumbnail, set to true; when generally query
+ * thumbnail saved index, set to false.
+ */
+ private long getIndex(long id, boolean create){
+ RandomAccessFile r = miniThumbIndexFile();
+ ByteBuffer buf = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB_INDEX);
+
+ if (r != null) {
+ long pos = 0;
+ //first 8 bytes are for saving next create thumbnail block number!
+ //so if create set, then begin from 0, others begin from real index
+ // (id+1)*BYTES_PER_MINTHUMB_INDEX.
+ if (!create) {
+ pos = (id + 1) * BYTES_PER_MINTHUMB_INDEX;
+ }
+
+ FileLock lock = null;
+ try {
+ buf.clear();
+ buf.limit(BYTES_PER_MINTHUMB_INDEX);
+
+ lock = mIndexChannel.lock(pos, BYTES_PER_MINTHUMB_INDEX, false);
+ //check that we can read the following 8 bytes
+ //which is the index position of thumbnail.
+
+ int read = mIndexChannel.read(buf, pos);
+
+ if (read == BYTES_PER_MINTHUMB_INDEX) {
+ buf.position(0);
+ if (create) {
+ //first, write next index.
+ long now = buf.getLong();
+ buf.clear();
+ buf.position(0);
+ buf.putLong(++now);
+ buf.flip();
+ int write = mIndexChannel.write(buf, pos);
+
+ //second, write this id's index
+ if(BYTES_PER_MINTHUMB_INDEX == write) {
+ if (lock != null) lock.release();
+ pos = (id + 1) * BYTES_PER_MINTHUMB_INDEX;
+ lock = mIndexChannel.lock(pos, BYTES_PER_MINTHUMB_INDEX, false);
+ buf.flip();
+ write = mIndexChannel.write(buf, pos);
+ if(debug) Log.d(TAG, "getIndex with create. index: " + now +
+ "corresponding id: " + id + ", index is: " + pos);
+ }
+ return now;
+ } else {
+ long p = buf.getLong();
+ if(debug) Log.d(TAG, "getIndex with no create. index: " + p);
+ return p;
+ }
+ } else if(-1 == read) {
+ //If the index file is empty, initialize first index to 0.
+ if(0 == r.length()){
+ buf.clear();
+ buf.position(0);
+ buf.putLong(0);
+ buf.flip();
+ int write = mIndexChannel.write(buf, 0);
+ if(debug) Log.d(TAG, "initialize first index");
+ if(BYTES_PER_MINTHUMB_INDEX == write) return 0;
+ }
+ }
+ } catch (IOException ex) {
+ Log.e(TAG, "Got exception checking file index: ", ex);
+ } catch (RuntimeException ex) {
+ // Other NIO related exception like disk full, read only channel..etc
+ Log.e(TAG, "Got exception when reading index, id = " + id +
+ ", disk full or mount read-only? " + ex.getClass());
+ } finally {
+ try {
+ if (lock != null) lock.release();
+ }
+ catch (IOException ex) {
+ // ignore it.
+ Log.e(TAG, "release lock: ", ex);
+ }
+ }
+ }
+ return 0;
+ }
+
// Get the magic number for the specified id in the mini-thumb file.
// Returns 0 if the magic is not available.
public synchronized long getMagic(long id) {
@@ -151,8 +298,14 @@ public class MiniThumbFile {
// defined as having the right magic number at the offset
// reserved for this "id".
RandomAccessFile r = miniThumbDataFile();
+
if (r != null) {
- long pos = id * BYTES_PER_MINTHUMB;
+
+ long pos = getIndex(id, false);
+ if(pos < 0) return 0;
+
+ pos *= BYTES_PER_MINTHUMB;
+
FileLock lock = null;
try {
mBuffer.clear();
@@ -190,7 +343,11 @@ public class MiniThumbFile {
RandomAccessFile r = miniThumbDataFile();
if (r == null) return;
- long pos = id * BYTES_PER_MINTHUMB;
+
+ long pos = getIndex(id, true);
+ if(pos < 0) return;
+
+ pos *= BYTES_PER_MINTHUMB;
FileLock lock = null;
try {
if (data != null) {