190df352389eda7c964e6a43a0b752d27f16e02a7Owen Linpackage com.android.gallery3d.data; 290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 390df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.annotation.TargetApi; 490df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.content.ContentResolver; 590df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.database.Cursor; 690df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.net.Uri; 790df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.provider.MediaStore.Files; 890df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.provider.MediaStore.Files.FileColumns; 990df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.provider.MediaStore.Images; 1090df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.provider.MediaStore.Images.ImageColumns; 1190df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.provider.MediaStore.Video; 1290df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport android.util.Log; 1390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 1490df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport com.android.gallery3d.common.ApiHelper; 1590df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport com.android.gallery3d.common.Utils; 1690df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport com.android.gallery3d.util.ThreadPool.JobContext; 1790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 1890df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport java.util.ArrayList; 1990df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport java.util.Arrays; 2090df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport java.util.Comparator; 2190df352389eda7c964e6a43a0b752d27f16e02a7Owen Linimport java.util.HashMap; 2290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 2390df352389eda7c964e6a43a0b752d27f16e02a7Owen Linclass BucketHelper { 2490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 2590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final String TAG = "BucketHelper"; 2690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final String EXTERNAL_MEDIA = "external"; 2790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 2890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // BUCKET_DISPLAY_NAME is a string like "Camera" which is the directory 2990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // name of where an image or video is in. BUCKET_ID is a hash of the path 3090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // name of that directory (see computeBucketValues() in MediaProvider for 3190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // details). MEDIA_TYPE is video, image, audio, etc. 3290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // 3390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // The "albums" are not explicitly recorded in the database, but each image 3490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // or video has the two columns (BUCKET_ID, MEDIA_TYPE). We define an 3590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // "album" to be the collection of images/videos which have the same value 3690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // for the two columns. 3790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // 3890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // The goal of the query (used in loadSubMediaSetsFromFilesTable()) is to 3990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // find all albums, that is, all unique values for (BUCKET_ID, MEDIA_TYPE). 4090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // In the meantime sort them by the timestamp of the latest image/video in 4190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // each of the album. 4290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // 4390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // The order of columns below is important: it must match to the index in 4490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // MediaStore. 4590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final String[] PROJECTION_BUCKET = { 4690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin ImageColumns.BUCKET_ID, 4790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin FileColumns.MEDIA_TYPE, 4890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin ImageColumns.BUCKET_DISPLAY_NAME}; 4990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 5090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // The indices should match the above projections. 5190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final int INDEX_BUCKET_ID = 0; 5290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final int INDEX_MEDIA_TYPE = 1; 5390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final int INDEX_BUCKET_NAME = 2; 5490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 5590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // We want to order the albums by reverse chronological order. We abuse the 5690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // "WHERE" parameter to insert a "GROUP BY" clause into the SQL statement. 5790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // The template for "WHERE" parameter is like: 5890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // SELECT ... FROM ... WHERE (%s) 5990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // and we make it look like: 6090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // SELECT ... FROM ... WHERE (1) GROUP BY 1,(2) 6190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // The "(1)" means true. The "1,(2)" means the first two columns specified 6290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // after SELECT. Note that because there is a ")" in the template, we use 6390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // "(2" to match it. 6490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final String BUCKET_GROUP_BY = "1) GROUP BY 1,(2"; 6590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 6690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final String BUCKET_ORDER_BY = "MAX(datetaken) DESC"; 6790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 6890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // Before HoneyComb there is no Files table. Thus, we need to query the 6990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // bucket info from the Images and Video tables and then merge them 7090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // together. 7190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // 7290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // A bucket can exist in both tables. In this case, we need to find the 7390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // latest timestamp from the two tables and sort ourselves. So we add the 7490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // MAX(date_taken) to the projection and remove the media_type since we 7590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // already know the media type from the table we query from. 7690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final String[] PROJECTION_BUCKET_IN_ONE_TABLE = { 7790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin ImageColumns.BUCKET_ID, 78042a8366f79693ec3ac572afd25d877f48949a63Wu-cheng Li "MAX(datetaken)", 7990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin ImageColumns.BUCKET_DISPLAY_NAME}; 8090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 8190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // We keep the INDEX_BUCKET_ID and INDEX_BUCKET_NAME the same as 8290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // PROJECTION_BUCKET so we can reuse the values defined before. 8390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final int INDEX_DATE_TAKEN = 1; 8490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 8590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // When query from the Images or Video tables, we only need to group by BUCKET_ID. 8690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static final String BUCKET_GROUP_BY_IN_ONE_TABLE = "1) GROUP BY (1"; 8790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 8890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public static BucketEntry[] loadBucketEntries( 8990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin JobContext jc, ContentResolver resolver, int type) { 9090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (ApiHelper.HAS_MEDIA_PROVIDER_FILES_TABLE) { 9190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return loadBucketEntriesFromFilesTable(jc, resolver, type); 9290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } else { 9390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return loadBucketEntriesFromImagesAndVideoTable(jc, resolver, type); 9490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 9590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 9690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 9790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static void updateBucketEntriesFromTable(JobContext jc, 9890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin ContentResolver resolver, Uri tableUri, HashMap<Integer, BucketEntry> buckets) { 9990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Cursor cursor = resolver.query(tableUri, PROJECTION_BUCKET_IN_ONE_TABLE, 10090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin BUCKET_GROUP_BY_IN_ONE_TABLE, null, null); 10190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (cursor == null) { 10290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Log.w(TAG, "cannot open media database: " + tableUri); 10390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return; 10490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 10590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin try { 10690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin while (cursor.moveToNext()) { 10790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin int bucketId = cursor.getInt(INDEX_BUCKET_ID); 10890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin int dateTaken = cursor.getInt(INDEX_DATE_TAKEN); 10990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin BucketEntry entry = buckets.get(bucketId); 11090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (entry == null) { 11190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin entry = new BucketEntry(bucketId, cursor.getString(INDEX_BUCKET_NAME)); 11290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin buckets.put(bucketId, entry); 11390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin entry.dateTaken = dateTaken; 11490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } else { 11590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin entry.dateTaken = Math.max(entry.dateTaken, dateTaken); 11690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 11790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 11890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } finally { 11990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Utils.closeSilently(cursor); 12090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 12190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 12290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 12390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static BucketEntry[] loadBucketEntriesFromImagesAndVideoTable( 12490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin JobContext jc, ContentResolver resolver, int type) { 12590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin HashMap<Integer, BucketEntry> buckets = new HashMap<Integer, BucketEntry>(64); 12690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if ((type & MediaObject.MEDIA_TYPE_IMAGE) != 0) { 12790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin updateBucketEntriesFromTable( 12890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin jc, resolver, Images.Media.EXTERNAL_CONTENT_URI, buckets); 12990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 13090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if ((type & MediaObject.MEDIA_TYPE_VIDEO) != 0) { 13190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin updateBucketEntriesFromTable( 13290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin jc, resolver, Video.Media.EXTERNAL_CONTENT_URI, buckets); 13390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 13490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin BucketEntry[] entries = buckets.values().toArray(new BucketEntry[buckets.size()]); 13590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Arrays.sort(entries, new Comparator<BucketEntry>() { 13690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin @Override 13790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public int compare(BucketEntry a, BucketEntry b) { 13890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin // sorted by dateTaken in descending order 13990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return b.dateTaken - a.dateTaken; 14090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 14190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin }); 14290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return entries; 14390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 14490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 14590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static BucketEntry[] loadBucketEntriesFromFilesTable( 14690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin JobContext jc, ContentResolver resolver, int type) { 14790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Uri uri = getFilesContentUri(); 14890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 14990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Cursor cursor = resolver.query(uri, 15090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin PROJECTION_BUCKET, BUCKET_GROUP_BY, 15190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin null, BUCKET_ORDER_BY); 15290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (cursor == null) { 15390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Log.w(TAG, "cannot open local database: " + uri); 15490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return new BucketEntry[0]; 15590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 15690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin ArrayList<BucketEntry> buffer = new ArrayList<BucketEntry>(); 15790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin int typeBits = 0; 15890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if ((type & MediaObject.MEDIA_TYPE_IMAGE) != 0) { 15990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin typeBits |= (1 << FileColumns.MEDIA_TYPE_IMAGE); 16090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 16190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if ((type & MediaObject.MEDIA_TYPE_VIDEO) != 0) { 16290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin typeBits |= (1 << FileColumns.MEDIA_TYPE_VIDEO); 16390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 16490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin try { 16590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin while (cursor.moveToNext()) { 16690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if ((typeBits & (1 << cursor.getInt(INDEX_MEDIA_TYPE))) != 0) { 16790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin BucketEntry entry = new BucketEntry( 16890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin cursor.getInt(INDEX_BUCKET_ID), 16990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin cursor.getString(INDEX_BUCKET_NAME)); 17090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (!buffer.contains(entry)) { 17190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin buffer.add(entry); 17290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 17390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 17490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (jc.isCancelled()) return null; 17590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 17690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } finally { 17790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Utils.closeSilently(cursor); 17890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 17990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return buffer.toArray(new BucketEntry[buffer.size()]); 18090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 18190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 18290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static String getBucketNameInTable( 18390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin ContentResolver resolver, Uri tableUri, int bucketId) { 18490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin String selectionArgs[] = new String[] {String.valueOf(bucketId)}; 18590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Uri uri = tableUri.buildUpon() 18690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin .appendQueryParameter("limit", "1") 18790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin .build(); 18890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Cursor cursor = resolver.query(uri, PROJECTION_BUCKET_IN_ONE_TABLE, 18990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin "bucket_id = ?", selectionArgs, null); 19090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin try { 19190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (cursor != null && cursor.moveToNext()) { 19290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return cursor.getString(INDEX_BUCKET_NAME); 19390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 19490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } finally { 19590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin Utils.closeSilently(cursor); 19690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 19790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return null; 19890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 19990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 20090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) 20190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin private static Uri getFilesContentUri() { 20290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return Files.getContentUri(EXTERNAL_MEDIA); 20390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 20490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 20590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public static String getBucketName(ContentResolver resolver, int bucketId) { 20690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (ApiHelper.HAS_MEDIA_PROVIDER_FILES_TABLE) { 20790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin String result = getBucketNameInTable(resolver, getFilesContentUri(), bucketId); 20890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return result == null ? "" : result; 20990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } else { 21090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin String result = getBucketNameInTable( 21190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin resolver, Images.Media.EXTERNAL_CONTENT_URI, bucketId); 21290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (result != null) return result; 21390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin result = getBucketNameInTable( 21490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin resolver, Video.Media.EXTERNAL_CONTENT_URI, bucketId); 21590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return result == null ? "" : result; 21690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 21790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 21890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 21990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public static class BucketEntry { 22090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public String bucketName; 22190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public int bucketId; 22290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public int dateTaken; 22390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 22490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public BucketEntry(int id, String name) { 22590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin bucketId = id; 22690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin bucketName = Utils.ensureNotNull(name); 22790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 22890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 22990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin @Override 23090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public int hashCode() { 23190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return bucketId; 23290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 23390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin 23490df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin @Override 23590df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin public boolean equals(Object object) { 23690df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin if (!(object instanceof BucketEntry)) return false; 23790df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin BucketEntry entry = (BucketEntry) object; 23890df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin return bucketId == entry.bucketId; 23990df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 24090df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin } 24190df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin} 242