MiniThumbFile.java revision ef093cd6c4ab4d3c8a1c8be5ed7147d5f06d7027
100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen/* 200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * Copyright (C) 2009 The Android Open Source Project 300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * Licensed under the Apache License, Version 2.0 (the "License"); 500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * you may not use this file except in compliance with the License. 600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * You may obtain a copy of the License at 700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * http://www.apache.org/licenses/LICENSE-2.0 900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 1000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * Unless required by applicable law or agreed to in writing, software 1100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * distributed under the License is distributed on an "AS IS" BASIS, 1200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * See the License for the specific language governing permissions and 1400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * limitations under the License. 1500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen */ 1600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 1700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenpackage android.media; 1800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 1900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport android.graphics.Bitmap; 2000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport android.media.ThumbnailUtil; 2100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport android.net.Uri; 2200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport android.os.Environment; 2300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport android.util.Log; 2400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 2500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport java.io.File; 2600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport java.io.IOException; 2700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport java.io.RandomAccessFile; 28ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chenimport java.nio.ByteBuffer; 2900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport java.nio.channels.FileChannel; 3000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport java.nio.channels.FileLock; 3100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenimport java.util.Hashtable; 3200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 3300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen/** 3400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * This class handles the mini-thumb file. A mini-thumb file consists 3500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * of blocks, indexed by id. Each block has BYTES_PER_MINTHUMB bytes in the 3600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * following format: 3700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 3800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 1 byte status (0 = empty, 1 = mini-thumb available) 3900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 8 bytes magic (a magic number to match what's in the database) 4000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 4 bytes data length (LEN) 4100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * LEN bytes jpeg data 4200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * (the remaining bytes are unused) 4300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 4400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * @hide This file is shared between MediaStore and MediaProvider and should remained internal use 4500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * only. 4600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen */ 4700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chenpublic class MiniThumbFile { 4800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private static final String TAG = "MiniThumbFile"; 4900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private static final int MINI_THUMB_DATA_FILE_VERSION = 3; 5000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen public static final int BYTES_PER_MINTHUMB = 10000; 5100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private static final int HEADER_SIZE = 1 + 8 + 4; 5200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private Uri mUri; 5300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private RandomAccessFile mMiniThumbFile; 5400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private FileChannel mChannel; 55ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen private ByteBuffer mBuffer; 5600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private static Hashtable<String, MiniThumbFile> sThumbFiles = 5700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen new Hashtable<String, MiniThumbFile>(); 5800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 5900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen /** 6000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * We store different types of thumbnails in different files. To remain backward compatibility, 6100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * we should hashcode of content://media/external/images/media remains the same. 6200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen */ 6300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen public static synchronized void reset() { 64ef093cd6c4ab4d3c8a1c8be5ed7147d5f06d7027Ray Chen for (MiniThumbFile file : sThumbFiles.values()) { 65ef093cd6c4ab4d3c8a1c8be5ed7147d5f06d7027Ray Chen file.deactivate(); 66ef093cd6c4ab4d3c8a1c8be5ed7147d5f06d7027Ray Chen } 6700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen sThumbFiles.clear(); 6800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 6900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 7000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen public static synchronized MiniThumbFile instance(Uri uri) { 7100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen String type = uri.getPathSegments().get(1); 7200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen MiniThumbFile file = sThumbFiles.get(type); 7300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Log.v(TAG, "get minithumbfile for type: "+type); 7400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (file == null) { 7500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen file = new MiniThumbFile( 7600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen Uri.parse("content://media/external/" + type + "/media")); 7700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen sThumbFiles.put(type, file); 7800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 7900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 8000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen return file; 8100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 8200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 8300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private String randomAccessFilePath(int version) { 8400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen String directoryName = 8500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen Environment.getExternalStorageDirectory().toString() 8600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen + "/DCIM/.thumbnails"; 8700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen return directoryName + "/.thumbdata" + version + "-" + mUri.hashCode(); 8800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 8900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 9000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private void removeOldFile() { 9100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen String oldPath = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION - 1); 9200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen File oldFile = new File(oldPath); 9300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (oldFile.exists()) { 9400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 9500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen oldFile.delete(); 9600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (SecurityException ex) { 9700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // ignore 9800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 9900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 10000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 10100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 10200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen private RandomAccessFile miniThumbDataFile() { 10300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (mMiniThumbFile == null) { 10400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen removeOldFile(); 10500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen String path = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION); 10600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen File directory = new File(path).getParentFile(); 10700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (!directory.isDirectory()) { 10800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (!directory.mkdirs()) { 10900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen Log.e(TAG, "Unable to create .thumbnails directory " 11000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen + directory.toString()); 11100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 11200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 11300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen File f = new File(path); 11400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 11500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen mMiniThumbFile = new RandomAccessFile(f, "rw"); 11600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (IOException ex) { 11700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Open as read-only so we can at least read the existing 11800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // thumbnails. 11900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 12000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen mMiniThumbFile = new RandomAccessFile(f, "r"); 12100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (IOException ex2) { 12200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // ignore exception 12300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 12400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 125f5722b3f22e016a8f21c628776cd0746ef164c19Chih-Chung Chang if (mMiniThumbFile != null) { 126f5722b3f22e016a8f21c628776cd0746ef164c19Chih-Chung Chang mChannel = mMiniThumbFile.getChannel(); 127f5722b3f22e016a8f21c628776cd0746ef164c19Chih-Chung Chang } 12800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 12900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen return mMiniThumbFile; 13000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 13100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 13200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen public MiniThumbFile(Uri uri) { 13300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen mUri = uri; 134ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB); 13500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 13600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 13700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen public synchronized void deactivate() { 13800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (mMiniThumbFile != null) { 13900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 14000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen mMiniThumbFile.close(); 14100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen mMiniThumbFile = null; 14200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (IOException ex) { 14300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // ignore exception 14400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 14500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 14600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 14700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 14800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Get the magic number for the specified id in the mini-thumb file. 14900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Returns 0 if the magic is not available. 150ef093cd6c4ab4d3c8a1c8be5ed7147d5f06d7027Ray Chen public synchronized long getMagic(long id) { 15100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // check the mini thumb file for the right data. Right is 15200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // defined as having the right magic number at the offset 15300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // reserved for this "id". 15400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen RandomAccessFile r = miniThumbDataFile(); 15500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (r != null) { 15600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen long pos = id * BYTES_PER_MINTHUMB; 15700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen FileLock lock = null; 15800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 159ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.clear(); 160ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.limit(1 + 8); 161ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen 162ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen lock = mChannel.lock(pos, 1 + 8, true); 16300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // check that we can read the following 9 bytes 16400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // (1 for the "status" and 8 for the long) 165ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen if (mChannel.read(mBuffer, pos) == 9) { 166ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.position(0); 167ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen if (mBuffer.get() == 1) { 168ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen return mBuffer.getLong(); 16900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 17000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 17100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (IOException ex) { 17200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen Log.v(TAG, "Got exception checking file magic: ", ex); 17300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (RuntimeException ex) { 17400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Other NIO related exception like disk full, read only channel..etc 17500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen Log.e(TAG, "Got exception when reading magic, id = " + id + 17600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen ", disk full or mount read-only? " + ex.getClass()); 17700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } finally { 17800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 17900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (lock != null) lock.release(); 18000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 18100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen catch (IOException ex) { 18200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // ignore it. 18300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 18400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 18500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 18600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen return 0; 18700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 18800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 189ef093cd6c4ab4d3c8a1c8be5ed7147d5f06d7027Ray Chen public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic) 19000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen throws IOException { 19100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen RandomAccessFile r = miniThumbDataFile(); 19200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (r == null) return; 19300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 19400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen long pos = id * BYTES_PER_MINTHUMB; 19500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen FileLock lock = null; 19600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 19700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (data != null) { 19800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (data.length > BYTES_PER_MINTHUMB - HEADER_SIZE) { 19900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // not enough space to store it. 20000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen return; 20100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 202ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.clear(); 203ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.put((byte) 1); 204ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.putLong(magic); 205ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.putInt(data.length); 206ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.put(data); 207ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.flip(); 20800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 209ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false); 210ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mChannel.write(mBuffer, pos); 21100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 21200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (IOException ex) { 21300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen Log.e(TAG, "couldn't save mini thumbnail data for " 21400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen + id + "; ", ex); 21500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen throw ex; 21600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (RuntimeException ex) { 21700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Other NIO related exception like disk full, read only channel..etc 21800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen Log.e(TAG, "couldn't save mini thumbnail data for " 21900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen + id + "; disk full or mount read-only? " + ex.getClass()); 22000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } finally { 22100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 22200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (lock != null) lock.release(); 22300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 22400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen catch (IOException ex) { 22500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // ignore it. 22600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 22700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 22800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 22900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 23000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen /** 23100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * Gallery app can use this method to retrieve mini-thumbnail. Full size 23200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * images share the same IDs with their corresponding thumbnails. 23300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * 23400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * @param id the ID of the image (same of full size image). 23500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen * @param data the buffer to store mini-thumbnail. 23600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen */ 237ef093cd6c4ab4d3c8a1c8be5ed7147d5f06d7027Ray Chen public synchronized byte [] getMiniThumbFromFile(long id, byte [] data) { 23800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen RandomAccessFile r = miniThumbDataFile(); 23900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (r == null) return null; 24000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen 24100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen long pos = id * BYTES_PER_MINTHUMB; 24200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen FileLock lock = null; 24300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 244ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.clear(); 245ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, true); 246ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen int size = mChannel.read(mBuffer, pos); 247ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen if (size > 1 + 8 + 4) { // flag, magic, length 248ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.position(0); 249ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen byte flag = mBuffer.get(); 250ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen long magic = mBuffer.getLong(); 251ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen int length = mBuffer.getInt(); 252ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen 253ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen if (size >= 1 + 8 + 4 + length && data.length >= length) { 254ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen mBuffer.get(data, 0, length); 255ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen return data; 256ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen } 25700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 25800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (IOException ex) { 259ecc97cc9491f40c507e372a30bcd58a9e08066a8Ray Chen Log.w(TAG, "got exception when reading thumbnail id=" + id + ", exception: " + ex); 26000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } catch (RuntimeException ex) { 26100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // Other NIO related exception like disk full, read only channel..etc 26200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen Log.e(TAG, "Got exception when reading thumbnail, id = " + id + 26300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen ", disk full or mount read-only? " + ex.getClass()); 26400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } finally { 26500c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen try { 26600c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen if (lock != null) lock.release(); 26700c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 26800c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen catch (IOException ex) { 26900c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen // ignore it. 27000c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 27100c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 27200c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen return null; 27300c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen } 27400c575a3fccb9d3065e913f1b8fcf93e18d44eafRay Chen} 275