• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.gallery3d.data;
18 
19 import android.content.ContentResolver;
20 import android.content.res.Resources;
21 import android.database.Cursor;
22 import android.net.Uri;
23 import android.provider.MediaStore;
24 import android.provider.MediaStore.Images;
25 import android.provider.MediaStore.Images.ImageColumns;
26 import android.provider.MediaStore.Video;
27 import android.provider.MediaStore.Video.VideoColumns;
28 
29 import com.android.gallery3d.R;
30 import com.android.gallery3d.app.GalleryApp;
31 import com.android.gallery3d.common.Utils;
32 import com.android.gallery3d.util.GalleryUtils;
33 import com.android.gallery3d.util.MediaSetUtils;
34 
35 import java.util.ArrayList;
36 
37 // LocalAlbumSet lists all media items in one bucket on local storage.
38 // The media items need to be all images or all videos, but not both.
39 public class LocalAlbum extends MediaSet {
40     private static final String TAG = "LocalAlbum";
41     private static final String[] COUNT_PROJECTION = { "count(*)" };
42 
43     private static final int INVALID_COUNT = -1;
44     private final String mWhereClause;
45     private final String mOrderClause;
46     private final Uri mBaseUri;
47     private final String[] mProjection;
48 
49     private final GalleryApp mApplication;
50     private final ContentResolver mResolver;
51     private final int mBucketId;
52     private final String mName;
53     private final boolean mIsImage;
54     private final ChangeNotifier mNotifier;
55     private final Path mItemPath;
56     private int mCachedCount = INVALID_COUNT;
57 
LocalAlbum(Path path, GalleryApp application, int bucketId, boolean isImage, String name)58     public LocalAlbum(Path path, GalleryApp application, int bucketId,
59             boolean isImage, String name) {
60         super(path, nextVersionNumber());
61         mApplication = application;
62         mResolver = application.getContentResolver();
63         mBucketId = bucketId;
64         mName = getLocalizedName(application.getResources(), bucketId, name);
65         mIsImage = isImage;
66 
67         if (isImage) {
68             mWhereClause = ImageColumns.BUCKET_ID + " = ?";
69             mOrderClause = ImageColumns.DATE_TAKEN + " DESC, "
70                     + ImageColumns._ID + " DESC";
71             mBaseUri = Images.Media.EXTERNAL_CONTENT_URI;
72             mProjection = LocalImage.PROJECTION;
73             mItemPath = LocalImage.ITEM_PATH;
74         } else {
75             mWhereClause = VideoColumns.BUCKET_ID + " = ?";
76             mOrderClause = VideoColumns.DATE_TAKEN + " DESC, "
77                     + VideoColumns._ID + " DESC";
78             mBaseUri = Video.Media.EXTERNAL_CONTENT_URI;
79             mProjection = LocalVideo.PROJECTION;
80             mItemPath = LocalVideo.ITEM_PATH;
81         }
82 
83         mNotifier = new ChangeNotifier(this, mBaseUri, application);
84     }
85 
LocalAlbum(Path path, GalleryApp application, int bucketId, boolean isImage)86     public LocalAlbum(Path path, GalleryApp application, int bucketId,
87             boolean isImage) {
88         this(path, application, bucketId, isImage,
89                 LocalAlbumSet.getBucketName(application.getContentResolver(),
90                 bucketId));
91     }
92 
93     @Override
getContentUri()94     public Uri getContentUri() {
95         if (mIsImage) {
96             return MediaStore.Images.Media.EXTERNAL_CONTENT_URI.buildUpon()
97                     .appendQueryParameter(LocalSource.KEY_BUCKET_ID,
98                             String.valueOf(mBucketId)).build();
99         } else {
100             return MediaStore.Video.Media.EXTERNAL_CONTENT_URI.buildUpon()
101                     .appendQueryParameter(LocalSource.KEY_BUCKET_ID,
102                             String.valueOf(mBucketId)).build();
103         }
104     }
105 
106     @Override
getMediaItem(int start, int count)107     public ArrayList<MediaItem> getMediaItem(int start, int count) {
108         DataManager dataManager = mApplication.getDataManager();
109         Uri uri = mBaseUri.buildUpon()
110                 .appendQueryParameter("limit", start + "," + count).build();
111         ArrayList<MediaItem> list = new ArrayList<MediaItem>();
112         GalleryUtils.assertNotInRenderThread();
113         Cursor cursor = mResolver.query(
114                 uri, mProjection, mWhereClause,
115                 new String[]{String.valueOf(mBucketId)},
116                 mOrderClause);
117         if (cursor == null) {
118             Log.w(TAG, "query fail: " + uri);
119             return list;
120         }
121 
122         try {
123             while (cursor.moveToNext()) {
124                 int id = cursor.getInt(0);  // _id must be in the first column
125                 Path childPath = mItemPath.getChild(id);
126                 MediaItem item = loadOrUpdateItem(childPath, cursor,
127                         dataManager, mApplication, mIsImage);
128                 list.add(item);
129             }
130         } finally {
131             cursor.close();
132         }
133         return list;
134     }
135 
loadOrUpdateItem(Path path, Cursor cursor, DataManager dataManager, GalleryApp app, boolean isImage)136     private static MediaItem loadOrUpdateItem(Path path, Cursor cursor,
137             DataManager dataManager, GalleryApp app, boolean isImage) {
138         LocalMediaItem item = (LocalMediaItem) dataManager.peekMediaObject(path);
139         if (item == null) {
140             if (isImage) {
141                 item = new LocalImage(path, app, cursor);
142             } else {
143                 item = new LocalVideo(path, app, cursor);
144             }
145         } else {
146             item.updateContent(cursor);
147         }
148         return item;
149     }
150 
151     // The pids array are sorted by the (path) id.
getMediaItemById( GalleryApp application, boolean isImage, ArrayList<Integer> ids)152     public static MediaItem[] getMediaItemById(
153             GalleryApp application, boolean isImage, ArrayList<Integer> ids) {
154         // get the lower and upper bound of (path) id
155         MediaItem[] result = new MediaItem[ids.size()];
156         if (ids.isEmpty()) return result;
157         int idLow = ids.get(0);
158         int idHigh = ids.get(ids.size() - 1);
159 
160         // prepare the query parameters
161         Uri baseUri;
162         String[] projection;
163         Path itemPath;
164         if (isImage) {
165             baseUri = Images.Media.EXTERNAL_CONTENT_URI;
166             projection = LocalImage.PROJECTION;
167             itemPath = LocalImage.ITEM_PATH;
168         } else {
169             baseUri = Video.Media.EXTERNAL_CONTENT_URI;
170             projection = LocalVideo.PROJECTION;
171             itemPath = LocalVideo.ITEM_PATH;
172         }
173 
174         ContentResolver resolver = application.getContentResolver();
175         DataManager dataManager = application.getDataManager();
176         Cursor cursor = resolver.query(baseUri, projection, "_id BETWEEN ? AND ?",
177                 new String[]{String.valueOf(idLow), String.valueOf(idHigh)},
178                 "_id");
179         if (cursor == null) {
180             Log.w(TAG, "query fail" + baseUri);
181             return result;
182         }
183         try {
184             int n = ids.size();
185             int i = 0;
186 
187             while (i < n && cursor.moveToNext()) {
188                 int id = cursor.getInt(0);  // _id must be in the first column
189 
190                 // Match id with the one on the ids list.
191                 if (ids.get(i) > id) {
192                     continue;
193                 }
194 
195                 while (ids.get(i) < id) {
196                     if (++i >= n) {
197                         return result;
198                     }
199                 }
200 
201                 Path childPath = itemPath.getChild(id);
202                 MediaItem item = loadOrUpdateItem(childPath, cursor, dataManager,
203                         application, isImage);
204                 result[i] = item;
205                 ++i;
206             }
207             return result;
208         } finally {
209             cursor.close();
210         }
211     }
212 
getItemCursor(ContentResolver resolver, Uri uri, String[] projection, int id)213     public static Cursor getItemCursor(ContentResolver resolver, Uri uri,
214             String[] projection, int id) {
215         return resolver.query(uri, projection, "_id=?",
216                 new String[]{String.valueOf(id)}, null);
217     }
218 
219     @Override
getMediaItemCount()220     public int getMediaItemCount() {
221         if (mCachedCount == INVALID_COUNT) {
222             Cursor cursor = mResolver.query(
223                     mBaseUri, COUNT_PROJECTION, mWhereClause,
224                     new String[]{String.valueOf(mBucketId)}, null);
225             if (cursor == null) {
226                 Log.w(TAG, "query fail");
227                 return 0;
228             }
229             try {
230                 Utils.assertTrue(cursor.moveToNext());
231                 mCachedCount = cursor.getInt(0);
232             } finally {
233                 cursor.close();
234             }
235         }
236         return mCachedCount;
237     }
238 
239     @Override
getName()240     public String getName() {
241         return mName;
242     }
243 
244     @Override
reload()245     public long reload() {
246         if (mNotifier.isDirty()) {
247             mDataVersion = nextVersionNumber();
248             mCachedCount = INVALID_COUNT;
249         }
250         return mDataVersion;
251     }
252 
253     @Override
getSupportedOperations()254     public int getSupportedOperations() {
255         return SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_INFO;
256     }
257 
258     @Override
delete()259     public void delete() {
260         GalleryUtils.assertNotInRenderThread();
261         mResolver.delete(mBaseUri, mWhereClause,
262                 new String[]{String.valueOf(mBucketId)});
263         mApplication.getDataManager().broadcastLocalDeletion();
264     }
265 
266     @Override
isLeafAlbum()267     public boolean isLeafAlbum() {
268         return true;
269     }
270 
getLocalizedName(Resources res, int bucketId, String name)271     private static String getLocalizedName(Resources res, int bucketId,
272             String name) {
273         if (bucketId == MediaSetUtils.CAMERA_BUCKET_ID) {
274             return res.getString(R.string.folder_camera);
275         } else if (bucketId == MediaSetUtils.DOWNLOAD_BUCKET_ID) {
276             return res.getString(R.string.folder_download);
277         } else if (bucketId == MediaSetUtils.IMPORTED_BUCKET_ID) {
278             return res.getString(R.string.folder_imported);
279         } else if (bucketId == MediaSetUtils.SNAPSHOT_BUCKET_ID) {
280             return res.getString(R.string.folder_screenshot);
281         } else {
282             return name;
283         }
284     }
285 }
286