1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/*
2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project
3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License.
6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at
7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin *
10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software
11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and
14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License.
15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */
16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.data;
18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.content.ContentResolver;
206caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Changimport android.content.res.Resources;
21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.database.Cursor;
22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.net.Uri;
23fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liuimport android.os.Environment;
2484c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chenimport android.provider.MediaStore;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.provider.MediaStore.Images;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.provider.MediaStore.Images.ImageColumns;
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.provider.MediaStore.Video;
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.provider.MediaStore.Video.VideoColumns;
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
302b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.R;
312b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.app.GalleryApp;
322b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.Utils;
33fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liuimport com.android.gallery3d.util.BucketNames;
342b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.GalleryUtils;
352b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.util.MediaSetUtils;
362b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
37fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liuimport java.io.File;
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList;
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// LocalAlbumSet lists all media items in one bucket on local storage.
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// The media items need to be all images or all videos, but not both.
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class LocalAlbum extends MediaSet {
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "LocalAlbum";
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String[] COUNT_PROJECTION = { "count(*)" };
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int INVALID_COUNT = -1;
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final String mWhereClause;
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final String mOrderClause;
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final Uri mBaseUri;
50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final String[] mProjection;
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final GalleryApp mApplication;
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final ContentResolver mResolver;
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final int mBucketId;
556caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang    private final String mName;
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final boolean mIsImage;
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final ChangeNotifier mNotifier;
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final Path mItemPath;
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mCachedCount = INVALID_COUNT;
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public LocalAlbum(Path path, GalleryApp application, int bucketId,
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean isImage, String name) {
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        super(path, nextVersionNumber());
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mApplication = application;
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mResolver = application.getContentResolver();
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mBucketId = bucketId;
67ef1e404cfa1227e309786675a6026dec842b5ab1Bobby Georgescu        mName = name;
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mIsImage = isImage;
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (isImage) {
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mWhereClause = ImageColumns.BUCKET_ID + " = ?";
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mOrderClause = ImageColumns.DATE_TAKEN + " DESC, "
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    + ImageColumns._ID + " DESC";
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mBaseUri = Images.Media.EXTERNAL_CONTENT_URI;
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mProjection = LocalImage.PROJECTION;
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mItemPath = LocalImage.ITEM_PATH;
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mWhereClause = VideoColumns.BUCKET_ID + " = ?";
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mOrderClause = VideoColumns.DATE_TAKEN + " DESC, "
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    + VideoColumns._ID + " DESC";
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mBaseUri = Video.Media.EXTERNAL_CONTENT_URI;
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mProjection = LocalVideo.PROJECTION;
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mItemPath = LocalVideo.ITEM_PATH;
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mNotifier = new ChangeNotifier(this, mBaseUri, application);
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public LocalAlbum(Path path, GalleryApp application, int bucketId,
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            boolean isImage) {
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        this(path, application, bucketId, isImage,
9290df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin                BucketHelper.getBucketName(
9390df352389eda7c964e6a43a0b752d27f16e02a7Owen Lin                application.getContentResolver(), bucketId));
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
977eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu    public boolean isCameraRoll() {
987eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu        return mBucketId == MediaSetUtils.CAMERA_BUCKET_ID;
997eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu    }
1007eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu
1017eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu    @Override
10284c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen    public Uri getContentUri() {
10384c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen        if (mIsImage) {
10484c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen            return MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
10584c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen                    .appendQueryParameter(LocalSource.KEY_BUCKET_ID,
10684c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen                            String.valueOf(mBucketId)).build();
10784c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen        } else {
10884c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen            return MediaStore.Video.Media.EXTERNAL_CONTENT_URI.buildUpon()
10984c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen                    .appendQueryParameter(LocalSource.KEY_BUCKET_ID,
11084c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen                            String.valueOf(mBucketId)).build();
11184c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen        }
11284c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen    }
11384c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen
11484c220f10a643927c8a2126de8a755d8d7f7ec9eRay Chen    @Override
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public ArrayList<MediaItem> getMediaItem(int start, int count) {
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        DataManager dataManager = mApplication.getDataManager();
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Uri uri = mBaseUri.buildUpon()
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                .appendQueryParameter("limit", start + "," + count).build();
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ArrayList<MediaItem> list = new ArrayList<MediaItem>();
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GalleryUtils.assertNotInRenderThread();
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Cursor cursor = mResolver.query(
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                uri, mProjection, mWhereClause,
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                new String[]{String.valueOf(mBucketId)},
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mOrderClause);
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (cursor == null) {
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, "query fail: " + uri);
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return list;
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            while (cursor.moveToNext()) {
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                int id = cursor.getInt(0);  // _id must be in the first column
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Path childPath = mItemPath.getChild(id);
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                MediaItem item = loadOrUpdateItem(childPath, cursor,
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        dataManager, mApplication, mIsImage);
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                list.add(item);
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            cursor.close();
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return list;
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static MediaItem loadOrUpdateItem(Path path, Cursor cursor,
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            DataManager dataManager, GalleryApp app, boolean isImage) {
146676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin        synchronized (DataManager.LOCK) {
147676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin            LocalMediaItem item = (LocalMediaItem) dataManager.peekMediaObject(path);
148676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin            if (item == null) {
149676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                if (isImage) {
150676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                    item = new LocalImage(path, app, cursor);
151676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                } else {
152676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                    item = new LocalVideo(path, app, cursor);
153676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                }
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } else {
155676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin                item.updateContent(cursor);
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
157676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin            return item;
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // The pids array are sorted by the (path) id.
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static MediaItem[] getMediaItemById(
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            GalleryApp application, boolean isImage, ArrayList<Integer> ids) {
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // get the lower and upper bound of (path) id
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        MediaItem[] result = new MediaItem[ids.size()];
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (ids.isEmpty()) return result;
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int idLow = ids.get(0);
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int idHigh = ids.get(ids.size() - 1);
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // prepare the query parameters
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Uri baseUri;
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String[] projection;
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Path itemPath;
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (isImage) {
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            baseUri = Images.Media.EXTERNAL_CONTENT_URI;
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            projection = LocalImage.PROJECTION;
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            itemPath = LocalImage.ITEM_PATH;
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            baseUri = Video.Media.EXTERNAL_CONTENT_URI;
180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            projection = LocalVideo.PROJECTION;
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            itemPath = LocalVideo.ITEM_PATH;
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        ContentResolver resolver = application.getContentResolver();
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        DataManager dataManager = application.getDataManager();
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Cursor cursor = resolver.query(baseUri, projection, "_id BETWEEN ? AND ?",
187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                new String[]{String.valueOf(idLow), String.valueOf(idHigh)},
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                "_id");
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (cursor == null) {
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, "query fail" + baseUri);
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return result;
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        try {
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int n = ids.size();
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int i = 0;
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            while (i < n && cursor.moveToNext()) {
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                int id = cursor.getInt(0);  // _id must be in the first column
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                // Match id with the one on the ids list.
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (ids.get(i) > id) {
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    continue;
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                while (ids.get(i) < id) {
206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    if (++i >= n) {
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        return result;
208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    }
209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Path childPath = itemPath.getChild(id);
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                MediaItem item = loadOrUpdateItem(childPath, cursor, dataManager,
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                        application, isImage);
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                result[i] = item;
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ++i;
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return result;
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } finally {
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            cursor.close();
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static Cursor getItemCursor(ContentResolver resolver, Uri uri,
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            String[] projection, int id) {
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return resolver.query(uri, projection, "_id=?",
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                new String[]{String.valueOf(id)}, null);
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getMediaItemCount() {
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mCachedCount == INVALID_COUNT) {
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Cursor cursor = mResolver.query(
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    mBaseUri, COUNT_PROJECTION, mWhereClause,
234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    new String[]{String.valueOf(mBucketId)}, null);
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (cursor == null) {
236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Log.w(TAG, "query fail");
237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                return 0;
238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            try {
240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Utils.assertTrue(cursor.moveToNext());
241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mCachedCount = cursor.getInt(0);
242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            } finally {
243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                cursor.close();
244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mCachedCount;
247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public String getName() {
251ef1e404cfa1227e309786675a6026dec842b5ab1Bobby Georgescu        return getLocalizedName(mApplication.getResources(), mBucketId, mName);
252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
255705dc819661cb8c8e839a04577b0641bd6caad53John Reck    public long reload() {
256705dc819661cb8c8e839a04577b0641bd6caad53John Reck        if (mNotifier.isDirty()) {
257705dc819661cb8c8e839a04577b0641bd6caad53John Reck            mDataVersion = nextVersionNumber();
258705dc819661cb8c8e839a04577b0641bd6caad53John Reck            mCachedCount = INVALID_COUNT;
259705dc819661cb8c8e839a04577b0641bd6caad53John Reck        }
260705dc819661cb8c8e839a04577b0641bd6caad53John Reck        return mDataVersion;
261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int getSupportedOperations() {
265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_INFO;
266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void delete() {
270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        GalleryUtils.assertNotInRenderThread();
271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mResolver.delete(mBaseUri, mWhereClause,
272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                new String[]{String.valueOf(mBucketId)});
273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @Override
276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public boolean isLeafAlbum() {
277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return true;
278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
2796caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang
2800addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu    public static String getLocalizedName(Resources res, int bucketId,
2816caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang            String name) {
2826caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang        if (bucketId == MediaSetUtils.CAMERA_BUCKET_ID) {
2836caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang            return res.getString(R.string.folder_camera);
2846caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang        } else if (bucketId == MediaSetUtils.DOWNLOAD_BUCKET_ID) {
2856caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang            return res.getString(R.string.folder_download);
2866caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang        } else if (bucketId == MediaSetUtils.IMPORTED_BUCKET_ID) {
2876caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang            return res.getString(R.string.folder_imported);
2886caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang        } else if (bucketId == MediaSetUtils.SNAPSHOT_BUCKET_ID) {
2896caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang            return res.getString(R.string.folder_screenshot);
2900addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu        } else if (bucketId == MediaSetUtils.EDITED_ONLINE_PHOTOS_BUCKET_ID) {
2910addfc7f6342184a67cdd8b5cc3872c6a5c87e55Doris Liu            return res.getString(R.string.folder_edited_online_photos);
2926caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang        } else {
2936caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang            return name;
2946caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang        }
2956caf221c4888f8632e8eb5b60b145bfca3557b3aChih-Chung Chang    }
296fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu
297fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu    // Relative path is the absolute path minus external storage path
298fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu    public static String getRelativePath(int bucketId) {
299fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        String relativePath = "/";
300fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        if (bucketId == MediaSetUtils.CAMERA_BUCKET_ID) {
301fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            relativePath += BucketNames.CAMERA;
302fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        } else if (bucketId == MediaSetUtils.DOWNLOAD_BUCKET_ID) {
303fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            relativePath += BucketNames.DOWNLOAD;
304fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        } else if (bucketId == MediaSetUtils.IMPORTED_BUCKET_ID) {
305fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            relativePath += BucketNames.IMPORTED;
306fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        } else if (bucketId == MediaSetUtils.SNAPSHOT_BUCKET_ID) {
307fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            relativePath += BucketNames.SCREENSHOTS;
308fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        } else if (bucketId == MediaSetUtils.EDITED_ONLINE_PHOTOS_BUCKET_ID) {
309fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            relativePath += BucketNames.EDITED_ONLINE_PHOTOS;
310fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        } else {
311fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            // If the first few cases didn't hit the matching path, do a
312fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            // thorough search in the local directories.
313fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            File extStorage = Environment.getExternalStorageDirectory();
314fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            String path = GalleryUtils.searchDirForPath(extStorage, bucketId);
315fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            if (path == null) {
316fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu                Log.w(TAG, "Relative path for bucket id: " + bucketId + " is not found.");
317fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu                relativePath = null;
318fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            } else {
319fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu                relativePath = path.substring(extStorage.getAbsolutePath().length());
320fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu            }
321fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        }
322fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu        return relativePath;
323fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu    }
324fcf54601d45bfcef2fbeb911c46ff394e84d7011Doris Liu
325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
326