OSDN Git Service

646f3f16a2f991734b741108949127ae5226a8db
[android-x86/packages-apps-Gallery2.git] / src / com / cooliris / media / SingleDataSource.java
1 package com.cooliris.media;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import android.content.ContentResolver;
9 import android.content.ContentUris;
10 import android.content.Context;
11 import android.database.Cursor;
12 import android.media.ExifInterface;
13 import android.net.Uri;
14 import android.os.Environment;
15 import android.provider.MediaStore;
16 import android.provider.MediaStore.Images;
17 import android.provider.MediaStore.Video;
18 import android.util.Log;
19
20 import com.cooliris.cache.CacheService;
21
22 // TODO: Merge SingleDataSource and LocalDataSource into one type if possible
23
24 public class SingleDataSource implements DataSource {
25     private static final String TAG = "SingleDataSource";
26     public final String mUri;
27     public final String mBucketId;
28     public boolean mDone;
29     public final boolean mSlideshow;
30     public final boolean mSingleUri;
31     public final boolean mAllItems;
32     public final DiskCache mDiskCache;
33     private Context mContext;
34
35     public SingleDataSource(final Context context, final String uri, final boolean slideshow) {
36         this.mUri = uri;
37         mContext = context;
38         String bucketId = Uri.parse(uri).getQueryParameter("bucketId");
39         if (bucketId != null && bucketId.length() > 0) {
40             mBucketId = bucketId;
41         } else {
42             mBucketId = null;
43         }
44         if (mBucketId == null) {
45             if (uri.equals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())) {
46                 mAllItems = true;
47             } else {
48                 mAllItems = false;
49             }
50         } else {
51             mAllItems = false;
52         }
53         this.mSlideshow = slideshow;
54         mSingleUri = isSingleImageMode(uri) && mBucketId == null;
55         mDone = false;
56         mDiskCache = mUri.startsWith(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString()) || mUri.startsWith("file://") ? LocalDataSource.sThumbnailCache
57                 : null;
58     }
59
60     public void shutdown() {
61
62     }
63     
64     public boolean isSingleImage() {
65         return mSingleUri;
66     }
67
68     private static boolean isSingleImageMode(String uriString) {
69         return !uriString.equals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())
70                 && !uriString.equals(MediaStore.Images.Media.INTERNAL_CONTENT_URI.toString());
71     }
72
73     public DiskCache getThumbnailCache() {
74         return mDiskCache;
75     }
76
77     public void loadItemsForSet(MediaFeed feed, MediaSet parentSet, int rangeStart, int rangeEnd) {
78         if (parentSet.mNumItemsLoaded > 0 && mDone) {
79             return;
80         }
81         if (mSingleUri && !mDone) {
82             MediaItem item = new MediaItem();
83             item.mId = 0;
84             item.mFilePath = "";
85             item.setMediaType((isImage(mUri)) ? MediaItem.MEDIA_TYPE_IMAGE : MediaItem.MEDIA_TYPE_VIDEO);
86             if (mUri.startsWith(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())) {
87                 MediaItem newItem = LocalDataSource.createMediaItemFromUri(mContext, Uri.parse(mUri));
88                 if (newItem != null) {
89                     item = newItem;
90                     String fileUri = new File(item.mFilePath).toURI().toString();
91                     parentSet.mName = Utils.getBucketNameFromUri(Uri.parse(fileUri));
92                     parentSet.mId = parseBucketIdFromFileUri(fileUri);
93                     parentSet.generateTitle(true);
94                 }
95             } else if (mUri.startsWith("file://")) {
96                 MediaItem newItem = null;
97                 int numRetries = 3;
98                 do {
99                     newItem = LocalDataSource.createMediaItemFromFileUri(mContext, mUri);
100                     if (newItem == null) {
101                         --numRetries;
102                         try {
103                             Thread.sleep(300);
104                         } catch (InterruptedException e) {
105                             ;
106                         }
107                     }
108                 } while (newItem == null && numRetries >= 0);
109                 if (newItem != null) {
110                     item = newItem;
111                 } else {
112                     item.mContentUri = mUri;
113                     item.mThumbnailUri = mUri;
114                     item.mScreennailUri = mUri;
115                     feed.setSingleImageMode(true);
116                 }
117             } else {
118                 item.mContentUri = mUri;
119                 item.mThumbnailUri = mUri;
120                 item.mScreennailUri = mUri;
121                 feed.setSingleImageMode(true);
122             }
123             if (item != null) {
124                 feed.addItemToMediaSet(item, parentSet);
125                 // Parse EXIF orientation if a local file.
126                 if (mUri.startsWith("file://")) {
127                     try {
128                         ExifInterface exif = new ExifInterface(Uri.parse(mUri).getPath());
129                         item.mRotation = Shared.exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
130                                 ExifInterface.ORIENTATION_NORMAL));
131                     } catch (IOException e) {
132                         Log.i(TAG, "Error reading Exif information, probably not a jpeg.");
133                     }
134                 }
135                 // Try and get the date taken for this item.
136                 long dateTaken = CacheService.fetchDateTaken(item);
137                 if (dateTaken != -1L) {
138                     item.mDateTakenInMs = dateTaken;
139                 }
140                 CacheService.loadMediaItemsIntoMediaFeed(feed, parentSet, rangeStart, rangeEnd, true, false);
141                 ArrayList<MediaItem> items = parentSet.getItems();
142                 int numItems = items.size();
143                 for (int i = 1; i < numItems; ++i) {
144                     MediaItem thisItem = items.get(i);
145                     String filePath = Uri.fromFile(new File(thisItem.mFilePath)).toString();
146                     if (item.mId == thisItem.mId || ((item.mContentUri != null && thisItem.mContentUri != null) && (item.mContentUri.equals(thisItem.mContentUri)
147                             || item.mContentUri.equals(filePath)))) {
148                         items.remove(thisItem);
149                         --parentSet.mNumItemsLoaded;
150                         break;
151                     }
152                 }
153             }
154             parentSet.updateNumExpectedItems();
155             parentSet.generateTitle(true);
156         } else if (mUri.equals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())) {
157             final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
158             final ContentResolver cr = mContext.getContentResolver();
159             String where = null;
160             Cursor cursor = cr.query(uriImages, CacheService.PROJECTION_IMAGES, where, null, null);
161             if (cursor != null && cursor.moveToFirst()) {
162                 parentSet.setNumExpectedItems(cursor.getCount());
163                 do {
164                     if (Thread.interrupted()) {
165                         return;
166                     }
167                     final MediaItem item = new MediaItem();
168                     CacheService.populateMediaItemFromCursor(item, cr, cursor, CacheService.BASE_CONTENT_STRING_IMAGES);
169                     feed.addItemToMediaSet(item, parentSet);
170                 } while (cursor.moveToNext());
171                 if (cursor != null) {
172                     cursor.close();
173                     cursor = null;
174                 }
175                 parentSet.updateNumExpectedItems();
176                 parentSet.generateTitle(true);
177             }
178         } else {
179             CacheService.loadMediaItemsIntoMediaFeed(feed, parentSet, rangeStart, rangeEnd, true, true);
180         }
181         mDone = true;
182     }
183
184     public static long parseBucketIdFromFileUri(String uriString) {
185         // This is a local folder.
186         final Uri uri = Uri.parse(uriString);
187         final List<String> paths = uri.getPathSegments();
188         final int numPaths = paths.size() - 1;
189         StringBuffer pathBuilder = new StringBuffer(Environment.getExternalStorageDirectory().toString());
190         if (numPaths > 1)
191             pathBuilder.append("/");
192         for (int i = 0; i < numPaths; ++i) {
193             String path = paths.get(i);
194             if (!"file".equals(path) && !"sdcard".equals(path)) {
195                 pathBuilder.append(path);
196                 if (i != numPaths - 1) {
197                     pathBuilder.append("/");
198                 }
199             }
200         }
201         return LocalDataSource.getBucketId(pathBuilder.toString());
202     }
203
204     private static boolean isImage(String uriString) {
205         return !uriString.startsWith(MediaStore.Video.Media.EXTERNAL_CONTENT_URI.toString());
206     }
207
208     private static long parseIdFromContentUri(String uri) {
209         try {
210             long id = ContentUris.parseId(Uri.parse(uri));
211             return id;
212         } catch (Exception e) {
213             return 0;
214         }
215     }
216
217     public void loadMediaSets(MediaFeed feed) {
218         MediaSet set = null; // Dummy set.
219         boolean loadOtherSets = true;
220         if (mSingleUri) {
221             String name = Utils.getBucketNameFromUri(Uri.parse(mUri));
222             long id = getBucketId(mUri);
223             set = feed.addMediaSet(id, this);
224             set.mName = name;
225             set.setNumExpectedItems(2);
226             set.generateTitle(true);
227             set.mPicasaAlbumId = Shared.INVALID;
228             if (this.getThumbnailCache() != LocalDataSource.sThumbnailCache) {
229                 loadOtherSets = false;
230             }
231         } else if (mBucketId == null) {
232             // All the buckets.
233             set = feed.addMediaSet(0, this); // Create dummy set.
234             set.mName = Utils.getBucketNameFromUri(Uri.parse(mUri));
235             set.mId = LocalDataSource.getBucketId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString() + "/" + set.mName);
236             set.setNumExpectedItems(1);
237             set.generateTitle(true);
238             set.mPicasaAlbumId = Shared.INVALID;
239         } else {
240             CacheService.loadMediaSet(feed, this, Long.parseLong(mBucketId));
241             ArrayList<MediaSet> sets = feed.getMediaSets();
242             if (sets.size() > 0)
243                 set = sets.get(0);
244         }
245         // We also load the other MediaSets
246         if (!mAllItems && set != null && loadOtherSets) {
247             if (!CacheService.isPresentInCache(set.mId)) {
248                 CacheService.markDirty(mContext);
249             }
250             CacheService.loadMediaSets(feed, this, true, false);
251         }
252     }
253
254     private long getBucketId(String uriString) {
255         if (uriString.startsWith("content://.")) {
256             return parseIdFromContentUri(uriString);
257         } else {
258             return parseBucketIdFromFileUri(uriString);
259         }
260     }
261
262     public boolean performOperation(int operation, ArrayList<MediaBucket> mediaBuckets, Object data) {
263         int numBuckets = mediaBuckets.size();
264         ContentResolver cr = mContext.getContentResolver();
265         switch (operation) {
266         case MediaFeed.OPERATION_DELETE:
267             // TODO: Refactor this against LocalDataSource.performOperation.
268             for (int i = 0; i < numBuckets; ++i) {
269                 MediaBucket bucket = mediaBuckets.get(i);
270                 MediaSet set = bucket.mediaSet;
271                 ArrayList<MediaItem> items = bucket.mediaItems;
272                 if (set != null && items == null) {
273                     // TODO bulk delete
274                     // remove the entire bucket
275                     final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
276                     final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
277                     final String whereImages = Images.ImageColumns.BUCKET_ID + "=" + Long.toString(set.mId);
278                     final String whereVideos = Video.VideoColumns.BUCKET_ID + "=" + Long.toString(set.mId);
279                     cr.delete(uriImages, whereImages, null);
280                     cr.delete(uriVideos, whereVideos, null);
281                     CacheService.markDirty(mContext);
282                 }
283                 if (set != null && items != null) {
284                     // We need to remove these items from the set.
285                     int numItems = items.size();
286                     for (int j = 0; j < numItems; ++j) {
287                         MediaItem item = items.get(j);
288                         cr.delete(Uri.parse(item.mContentUri), null, null);
289                     }
290                     set.updateNumExpectedItems();
291                     set.generateTitle(true);
292                     CacheService.markDirty(mContext, set.mId);
293                 }
294             }
295             break;
296         case MediaFeed.OPERATION_ROTATE:
297             for (int i = 0; i < numBuckets; ++i) {
298                 MediaBucket bucket = mediaBuckets.get(i);
299                 ArrayList<MediaItem> items = bucket.mediaItems;
300                 if (items == null) {
301                     continue;
302                 }
303                 float angleToRotate = ((Float) data).floatValue();
304                 if (angleToRotate == 0) {
305                     return true;
306                 }
307                 int numItems = items.size();
308                 for (int j = 0; j < numItems; ++j) {
309                     rotateItem(items.get(j), angleToRotate);
310                 }
311             }
312             break;
313         }
314         return true;
315     }
316
317     private void rotateItem(final MediaItem item, float angleToRotate) {
318         try {
319             int currentOrientation = (int) item.mRotation;
320             angleToRotate += currentOrientation;
321             float rotation = Shared.normalizePositive(angleToRotate);
322
323             // Update the file EXIF information.
324             Uri uri = Uri.parse(item.mContentUri);
325             String uriScheme = uri.getScheme();
326             if (uriScheme.equals("file")) {
327                 ExifInterface exif = new ExifInterface(uri.getPath());
328                 exif.setAttribute(ExifInterface.TAG_ORIENTATION, Integer.toString(Shared.degreesToExifOrientation(rotation)));
329                 exif.saveAttributes();
330             }
331
332             // Update the object representation of the item.
333             item.mRotation = rotation;
334         } catch (Exception e) {
335         }
336     }
337
338 }