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