OSDN Git Service

2c92295b5d08f51c9628b031b76112cdb7738190
[android-x86/packages-apps-Gallery2.git] / src / com / cooliris / media / LocalDataSource.java
1 package com.cooliris.media;
2
3 import java.io.File;
4 import java.net.URI;
5 import java.util.ArrayList;
6
7 import android.content.ContentResolver;
8 import android.content.ContentUris;
9 import android.content.ContentValues;
10 import android.content.Context;
11 import android.database.ContentObserver;
12 import android.database.Cursor;
13 import android.media.ExifInterface;
14 import android.net.Uri;
15 import android.os.Environment;
16 import android.os.Handler;
17 import android.provider.MediaStore.Images;
18 import android.provider.MediaStore.Video;
19 import android.util.Log;
20
21 import com.cooliris.cache.CacheService;
22
23 public final class LocalDataSource implements DataSource {
24     private static final String TAG = "LocalDataSource";
25
26     public static final DiskCache sThumbnailCache = new DiskCache("local-image-thumbs");
27     public static final DiskCache sThumbnailCacheVideo = new DiskCache("local-video-thumbs");
28
29     public static final String CAMERA_STRING = "Camera";
30     public static final String DOWNLOAD_STRING = "download";
31     public static final String CAMERA_BUCKET_NAME = Environment.getExternalStorageDirectory().toString() + "/DCIM/" + CAMERA_STRING;
32     public static final String DOWNLOAD_BUCKET_NAME = Environment.getExternalStorageDirectory().toString() + "/" + DOWNLOAD_STRING;
33     public static final int CAMERA_BUCKET_ID = getBucketId(CAMERA_BUCKET_NAME);
34     public static final int DOWNLOAD_BUCKET_ID = getBucketId(DOWNLOAD_BUCKET_NAME);
35
36     public static boolean sObserverActive = false;
37     private boolean mDisableImages;
38     private boolean mDisableVideos;
39
40     /**
41      * Matches code in MediaProvider.computeBucketValues. Should be a common
42      * function.
43      */
44     public static int getBucketId(String path) {
45         return (path.toLowerCase().hashCode());
46     }
47
48     private Context mContext;
49     private ContentObserver mObserver;
50
51     public LocalDataSource(Context context) {
52         mContext = context;
53     }
54
55     public void setMimeFilter(boolean disableImages, boolean disableVideos) {
56         mDisableImages = disableImages;
57         mDisableVideos = disableVideos;
58     }
59
60     public void loadMediaSets(final MediaFeed feed) {
61         if (mContext == null) {
62             return;
63         }
64         stopListeners();
65         CacheService.loadMediaSets(feed, this, !mDisableImages, !mDisableVideos);
66         Handler handler = ((Gallery) mContext).getHandler();
67         ContentObserver observer = new ContentObserver(handler) {
68             public void onChange(boolean selfChange) {
69                 final boolean isPaused = ((Gallery) mContext).isPaused();
70                 if (isPaused) {
71                     MediaSet mediaSet = feed.getCurrentSet();
72                     if (mediaSet != null) {
73                         CacheService.markDirtyImmediate(mediaSet.mId);
74                         refreshUI(feed, mediaSet.mId);
75                     }
76                 }
77                 CacheService.senseDirty(mContext, new CacheService.Observer() {
78                     public void onChange(long[] ids) {
79                         if (!isPaused)
80                             return;
81                         if (ids != null) {
82                             int numLongs = ids.length;
83                             for (int i = 0; i < numLongs; ++i) {
84                                 refreshUI(feed, ids[i]);
85                             }
86                         }
87                     }
88                 });
89             }
90         };
91
92         // Start listening.
93         Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
94         Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
95         ContentResolver cr = mContext.getContentResolver();
96         mObserver = observer;
97         cr.registerContentObserver(uriImages, true, observer);
98         cr.registerContentObserver(uriVideos, true, observer);
99         sObserverActive = true;
100     }
101
102     public void shutdown() {
103         stopListeners();
104     }
105
106     private void stopListeners() {
107         ContentResolver cr = mContext.getContentResolver();
108         if (mObserver != null) {
109             cr.unregisterContentObserver(mObserver);
110             cr.unregisterContentObserver(mObserver);
111         }
112         sObserverActive = false;
113     }
114
115     protected void refreshUI(MediaFeed feed, long setIdToUse) {
116         if (setIdToUse == Shared.INVALID) {
117             return;
118         }
119         if (feed.getMediaSet(setIdToUse) == null) {
120             MediaSet mediaSet = feed.addMediaSet(setIdToUse, this);
121             if (setIdToUse == CAMERA_BUCKET_ID) {
122                 mediaSet.mName = CAMERA_STRING;
123             } else if (setIdToUse == DOWNLOAD_BUCKET_ID) {
124                 mediaSet.mName = DOWNLOAD_STRING;
125             }
126             mediaSet.generateTitle(true);
127         } else {
128             MediaSet mediaSet = feed.replaceMediaSet(setIdToUse, this);
129             Log.i(TAG, "Replacing mediaset " + mediaSet.mName + " id " + setIdToUse + " current Id " + mediaSet.mId);
130             if (setIdToUse == CAMERA_BUCKET_ID) {
131                 mediaSet.mName = CAMERA_STRING;
132             } else if (setIdToUse == DOWNLOAD_BUCKET_ID) {
133                 mediaSet.mName = DOWNLOAD_STRING;
134             }
135             mediaSet.generateTitle(true);
136         }
137     }
138
139     public void loadItemsForSet(final MediaFeed feed, final MediaSet parentSet, int rangeStart, int rangeEnd) {
140         // Quick load from the cache.
141         if (mContext == null || parentSet == null) {
142             return;
143         }
144         loadMediaItemsIntoMediaFeed(feed, parentSet, rangeStart, rangeEnd);
145     }
146
147     private void loadMediaItemsIntoMediaFeed(final MediaFeed mediaFeed, final MediaSet set, int rangeStart, int rangeEnd) {
148         if (rangeEnd - rangeStart < 0) {
149             return;
150         }
151         CacheService.loadMediaItemsIntoMediaFeed(mediaFeed, set, rangeStart, rangeEnd, !mDisableImages, !mDisableVideos);
152         if (set.mId == CAMERA_BUCKET_ID) {
153             mediaFeed.moveSetToFront(set);
154         }
155     }
156
157     public boolean performOperation(final int operation, final ArrayList<MediaBucket> mediaBuckets, final Object data) {
158         int numBuckets = mediaBuckets.size();
159         ContentResolver cr = mContext.getContentResolver();
160         switch (operation) {
161         case MediaFeed.OPERATION_DELETE:
162             for (int i = 0; i < numBuckets; ++i) {
163                 MediaBucket bucket = mediaBuckets.get(i);
164                 MediaSet set = bucket.mediaSet;
165                 ArrayList<MediaItem> items = bucket.mediaItems;
166                 if (set != null && items == null) {
167                     // Remove the entire bucket.
168                     final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
169                     final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
170                     final String whereImages = Images.ImageColumns.BUCKET_ID + "=" + Long.toString(set.mId);
171                     final String whereVideos = Video.VideoColumns.BUCKET_ID + "=" + Long.toString(set.mId);
172                     cr.delete(uriImages, whereImages, null);
173                     cr.delete(uriVideos, whereVideos, null);
174                     CacheService.markDirty(mContext);
175                 }
176                 if (set != null && items != null) {
177                     // We need to remove these items from the set.
178                     int numItems = items.size();
179                     try {
180                         for (int j = 0; j < numItems; ++j) {
181                             MediaItem item = items.get(j);
182                             cr.delete(Uri.parse(item.mContentUri), null, null);
183                         }
184                     } catch (Exception e) {
185                         // If the database operation failed for any reason.
186                         ;
187                     }
188                     set.updateNumExpectedItems();
189                     set.generateTitle(true);
190                     CacheService.markDirty(mContext, set.mId);
191                 }
192             }
193             break;
194         case MediaFeed.OPERATION_ROTATE:
195             for (int i = 0; i < numBuckets; ++i) {
196                 MediaBucket bucket = mediaBuckets.get(i);
197                 ArrayList<MediaItem> items = bucket.mediaItems;
198                 if (items == null) {
199                     continue;
200                 }
201                 float angleToRotate = ((Float) data).floatValue();
202                 if (angleToRotate == 0) {
203                     return true;
204                 }
205                 int numItems = items.size();
206                 for (int j = 0; j < numItems; ++j) {
207                     rotateItem(items.get(j), angleToRotate);
208                 }
209             }
210             break;
211         }
212         return true;
213     }
214
215     private void rotateItem(final MediaItem item, float angleToRotate) {
216         ContentResolver cr = mContext.getContentResolver();
217         try {
218             int currentOrientation = (int) item.mRotation;
219             angleToRotate += currentOrientation;
220             float rotation = Shared.normalizePositive(angleToRotate);
221             String rotationString = Integer.toString((int) rotation);
222
223             // Update the database entry.
224             ContentValues values = new ContentValues();
225             values.put(Images.ImageColumns.ORIENTATION, rotationString);
226             try {
227                 cr.update(Uri.parse(item.mContentUri), values, null, null);
228             } catch (Exception e) {
229                 // If the database operation fails for any reason.
230                 ;
231             }
232
233             // Update the file EXIF information.
234             Uri uri = Uri.parse(item.mContentUri);
235             String uriScheme = uri.getScheme();
236             if (uriScheme.equals("file")) {
237                 ExifInterface exif = new ExifInterface(uri.getPath());
238                 exif.setAttribute(ExifInterface.TAG_ORIENTATION, Integer.toString(Shared.degreesToExifOrientation(rotation)));
239                 exif.saveAttributes();
240             }
241
242             // Invalidate the cache entry.
243             CacheService.markDirty(mContext, item.mParentMediaSet.mId);
244
245             // Update the object representation of the item.
246             item.mRotation = rotation;
247         } catch (Exception e) {
248             // System.out.println("Apparently not a JPEG");
249         }
250     }
251
252     public DiskCache getThumbnailCache() {
253         return sThumbnailCache;
254     }
255
256     public static MediaItem createMediaItemFromUri(Context context, Uri target) {
257         MediaItem item = null;
258         long id = ContentUris.parseId(target);
259         ContentResolver cr = context.getContentResolver();
260         String whereClause = Images.ImageColumns._ID + "=" + Long.toString(id);
261         try {
262             Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
263             if (cursor != null) {
264                 if (cursor.moveToFirst()) {
265                     item = new MediaItem();
266                     CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
267                 }
268                 cursor.close();
269                 cursor = null;
270             }
271         } catch (Exception e) {
272             // If the database operation failed for any reason.
273             ;
274         }
275         return item;
276     }
277
278     public static MediaItem createMediaItemFromFileUri(Context context, String fileUri) {
279         MediaItem item = null;
280         String filepath = new File(URI.create(fileUri)).toString();
281         ContentResolver cr = context.getContentResolver();
282         long bucketId = SingleDataSource.parseBucketIdFromFileUri(fileUri);
283         String whereClause = Images.ImageColumns.BUCKET_ID + "=" + bucketId + " AND " + Images.ImageColumns.DATA + "='" + filepath
284                 + "'";
285         try {
286             Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
287             if (cursor != null) {
288                 if (cursor.moveToFirst()) {
289                     item = new MediaItem();
290                     CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
291                 }
292                 cursor.close();
293                 cursor = null;
294             }
295         } catch (Exception e) {
296             // If the database operation failed for any reason.
297             ;
298         }
299         return item;
300     }
301 }