Loading core/java/android/provider/MediaStore.java +2 −2 Original line number Diff line number Diff line Loading @@ -672,8 +672,8 @@ public final class MediaStore { // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo); // If the magic is non-zero, we simply return thumbnail if it does exist. // querying MediaProvider and simply return thumbnail. MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI); MiniThumbFile thumbFile = MiniThumbFile.instance( isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI); Cursor c = null; try { long magic = thumbFile.getMagic(origId); Loading media/java/android/media/MediaScanner.java +0 −63 Original line number Diff line number Diff line Loading @@ -310,7 +310,6 @@ public class MediaScanner private Uri mAudioUri; private Uri mVideoUri; private Uri mImagesUri; private Uri mThumbsUri; private Uri mPlaylistsUri; private Uri mFilesUri; private Uri mFilesUriNoNotify; Loading Loading @@ -1199,64 +1198,6 @@ public class MediaScanner } } private boolean inScanDirectory(String path, String[] directories) { for (int i = 0; i < directories.length; i++) { String directory = directories[i]; if (path.startsWith(directory)) { return true; } } return false; } private void pruneDeadThumbnailFiles() { HashSet<String> existingFiles = new HashSet<String>(); String directory = "/sdcard/DCIM/.thumbnails"; String [] files = (new File(directory)).list(); Cursor c = null; if (files == null) files = new String[0]; for (int i = 0; i < files.length; i++) { String fullPathString = directory + "/" + files[i]; existingFiles.add(fullPathString); } try { c = mMediaProvider.query( mPackageName, mThumbsUri, new String [] { "_data" }, null, null, null, null); Log.v(TAG, "pruneDeadThumbnailFiles... " + c); if (c != null && c.moveToFirst()) { do { String fullPathString = c.getString(0); existingFiles.remove(fullPathString); } while (c.moveToNext()); } for (String fileToDelete : existingFiles) { if (false) Log.v(TAG, "fileToDelete is " + fileToDelete); try { (new File(fileToDelete)).delete(); } catch (SecurityException ex) { } } Log.v(TAG, "/pruneDeadThumbnailFiles... " + c); } catch (RemoteException e) { // We will soon be killed... } finally { if (c != null) { c.close(); } } } static class MediaBulkDeleter { StringBuilder whereClause = new StringBuilder(); ArrayList<String> whereArgs = new ArrayList<String>(100); Loading Loading @@ -1302,9 +1243,6 @@ public class MediaScanner processPlayLists(); } if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external"))) pruneDeadThumbnailFiles(); // allow GC to clean up mPlayLists = null; mMediaProvider = null; Loading @@ -1324,7 +1262,6 @@ public class MediaScanner mAudioUri = Audio.Media.getContentUri(volumeName); mVideoUri = Video.Media.getContentUri(volumeName); mImagesUri = Images.Media.getContentUri(volumeName); mThumbsUri = Images.Thumbnails.getContentUri(volumeName); mFilesUri = Files.getContentUri(volumeName); mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build(); Loading media/java/android/media/MiniThumbFile.java +52 −2 Original line number Diff line number Diff line Loading @@ -44,13 +44,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 HEADER_SIZE = 1 + 8 + 4; private Uri mUri; private RandomAccessFile mMiniThumbFile; private FileChannel mChannel; private ByteBuffer mBuffer; private ByteBuffer mEmptyBuffer; private static final Hashtable<String, MiniThumbFile> sThumbFiles = new Hashtable<String, MiniThumbFile>(); Loading Loading @@ -127,9 +128,10 @@ public class MiniThumbFile { return mMiniThumbFile; } public MiniThumbFile(Uri uri) { private MiniThumbFile(Uri uri) { mUri = uri; mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); } public synchronized void deactivate() { Loading Loading @@ -184,6 +186,54 @@ public class MiniThumbFile { return 0; } public synchronized void eraseMiniThumb(long id) { RandomAccessFile r = miniThumbDataFile(); if (r != null) { long pos = id * BYTES_PER_MINTHUMB; FileLock lock = null; try { mBuffer.clear(); mBuffer.limit(1 + 8); lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false); // check that we can read the following 9 bytes // (1 for the "status" and 8 for the long) if (mChannel.read(mBuffer, pos) == 9) { mBuffer.position(0); if (mBuffer.get() == 1) { long currentMagic = mBuffer.getLong(); if (currentMagic == 0) { // there is no thumbnail stored here Log.i(TAG, "no thumbnail for id " + id); return; } // zero out the thumbnail slot // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic // + " at offset " + pos); mChannel.write(mEmptyBuffer, pos); } } else { // Log.v(TAG, "No slot"); } } catch (IOException ex) { Log.v(TAG, "Got exception checking file magic: ", ex); } catch (RuntimeException ex) { // Other NIO related exception like disk full, read only channel..etc Log.e(TAG, "Got exception when reading magic, id = " + id + ", disk full or mount read-only? " + ex.getClass()); } finally { try { if (lock != null) lock.release(); } catch (IOException ex) { // ignore it. } } } else { // Log.v(TAG, "No data file"); } } public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic) throws IOException { RandomAccessFile r = miniThumbDataFile(); Loading Loading
core/java/android/provider/MediaStore.java +2 −2 Original line number Diff line number Diff line Loading @@ -672,8 +672,8 @@ public final class MediaStore { // Log.v(TAG, "getThumbnail: origId="+origId+", kind="+kind+", isVideo="+isVideo); // If the magic is non-zero, we simply return thumbnail if it does exist. // querying MediaProvider and simply return thumbnail. MiniThumbFile thumbFile = new MiniThumbFile(isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI); MiniThumbFile thumbFile = MiniThumbFile.instance( isVideo ? Video.Media.EXTERNAL_CONTENT_URI : Images.Media.EXTERNAL_CONTENT_URI); Cursor c = null; try { long magic = thumbFile.getMagic(origId); Loading
media/java/android/media/MediaScanner.java +0 −63 Original line number Diff line number Diff line Loading @@ -310,7 +310,6 @@ public class MediaScanner private Uri mAudioUri; private Uri mVideoUri; private Uri mImagesUri; private Uri mThumbsUri; private Uri mPlaylistsUri; private Uri mFilesUri; private Uri mFilesUriNoNotify; Loading Loading @@ -1199,64 +1198,6 @@ public class MediaScanner } } private boolean inScanDirectory(String path, String[] directories) { for (int i = 0; i < directories.length; i++) { String directory = directories[i]; if (path.startsWith(directory)) { return true; } } return false; } private void pruneDeadThumbnailFiles() { HashSet<String> existingFiles = new HashSet<String>(); String directory = "/sdcard/DCIM/.thumbnails"; String [] files = (new File(directory)).list(); Cursor c = null; if (files == null) files = new String[0]; for (int i = 0; i < files.length; i++) { String fullPathString = directory + "/" + files[i]; existingFiles.add(fullPathString); } try { c = mMediaProvider.query( mPackageName, mThumbsUri, new String [] { "_data" }, null, null, null, null); Log.v(TAG, "pruneDeadThumbnailFiles... " + c); if (c != null && c.moveToFirst()) { do { String fullPathString = c.getString(0); existingFiles.remove(fullPathString); } while (c.moveToNext()); } for (String fileToDelete : existingFiles) { if (false) Log.v(TAG, "fileToDelete is " + fileToDelete); try { (new File(fileToDelete)).delete(); } catch (SecurityException ex) { } } Log.v(TAG, "/pruneDeadThumbnailFiles... " + c); } catch (RemoteException e) { // We will soon be killed... } finally { if (c != null) { c.close(); } } } static class MediaBulkDeleter { StringBuilder whereClause = new StringBuilder(); ArrayList<String> whereArgs = new ArrayList<String>(100); Loading Loading @@ -1302,9 +1243,6 @@ public class MediaScanner processPlayLists(); } if (mOriginalCount == 0 && mImagesUri.equals(Images.Media.getContentUri("external"))) pruneDeadThumbnailFiles(); // allow GC to clean up mPlayLists = null; mMediaProvider = null; Loading @@ -1324,7 +1262,6 @@ public class MediaScanner mAudioUri = Audio.Media.getContentUri(volumeName); mVideoUri = Video.Media.getContentUri(volumeName); mImagesUri = Images.Media.getContentUri(volumeName); mThumbsUri = Images.Thumbnails.getContentUri(volumeName); mFilesUri = Files.getContentUri(volumeName); mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build(); Loading
media/java/android/media/MiniThumbFile.java +52 −2 Original line number Diff line number Diff line Loading @@ -44,13 +44,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 HEADER_SIZE = 1 + 8 + 4; private Uri mUri; private RandomAccessFile mMiniThumbFile; private FileChannel mChannel; private ByteBuffer mBuffer; private ByteBuffer mEmptyBuffer; private static final Hashtable<String, MiniThumbFile> sThumbFiles = new Hashtable<String, MiniThumbFile>(); Loading Loading @@ -127,9 +128,10 @@ public class MiniThumbFile { return mMiniThumbFile; } public MiniThumbFile(Uri uri) { private MiniThumbFile(Uri uri) { mUri = uri; mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); } public synchronized void deactivate() { Loading Loading @@ -184,6 +186,54 @@ public class MiniThumbFile { return 0; } public synchronized void eraseMiniThumb(long id) { RandomAccessFile r = miniThumbDataFile(); if (r != null) { long pos = id * BYTES_PER_MINTHUMB; FileLock lock = null; try { mBuffer.clear(); mBuffer.limit(1 + 8); lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false); // check that we can read the following 9 bytes // (1 for the "status" and 8 for the long) if (mChannel.read(mBuffer, pos) == 9) { mBuffer.position(0); if (mBuffer.get() == 1) { long currentMagic = mBuffer.getLong(); if (currentMagic == 0) { // there is no thumbnail stored here Log.i(TAG, "no thumbnail for id " + id); return; } // zero out the thumbnail slot // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic // + " at offset " + pos); mChannel.write(mEmptyBuffer, pos); } } else { // Log.v(TAG, "No slot"); } } catch (IOException ex) { Log.v(TAG, "Got exception checking file magic: ", ex); } catch (RuntimeException ex) { // Other NIO related exception like disk full, read only channel..etc Log.e(TAG, "Got exception when reading magic, id = " + id + ", disk full or mount read-only? " + ex.getClass()); } finally { try { if (lock != null) lock.release(); } catch (IOException ex) { // ignore it. } } } else { // Log.v(TAG, "No data file"); } } public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic) throws IOException { RandomAccessFile r = miniThumbDataFile(); Loading