OSDN Git Service

e6b89ac6b9e821c8b9b9c459cf16fb4e0946a6fb
[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 function.
42      */
43     public static int getBucketId(String path) {
44         return (path.toLowerCase().hashCode());
45     }
46
47     private Context mContext;
48         private ContentObserver mObserver;
49
50     public LocalDataSource(Context context) {
51         mContext = context;
52     }
53
54     public void setMimeFilter(boolean disableImages, boolean disableVideos) {
55         mDisableImages = disableImages;
56         mDisableVideos = disableVideos;
57     }
58
59     public void loadMediaSets(final MediaFeed feed) {
60         if (mContext == null) {
61             return;
62         }
63         stopListeners();
64         CacheService.loadMediaSets(feed, this, !mDisableImages, !mDisableVideos);
65         Handler handler = ((Gallery) mContext).getHandler();
66         ContentObserver observer = new ContentObserver(handler) {
67             public void onChange(boolean selfChange) {
68                 CacheService.senseDirty(mContext, new CacheService.Observer() {
69                         public void onChange(long[] ids) {
70                                 if (ids != null) {
71                                         int numLongs = ids.length;
72                                         for (int i = 0; i < numLongs; ++i) {
73                                                 refreshUI(feed, ids[i]);
74                                         }
75                                 }
76                         }
77                 });
78             }
79         };
80         
81         // Start listening.
82         Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
83         Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
84         ContentResolver cr = mContext.getContentResolver();
85         mObserver = observer;
86         cr.registerContentObserver(uriImages, false, observer);
87         cr.registerContentObserver(uriVideos, false, observer);
88         sObserverActive = true;
89     }
90
91     public void shutdown() {
92         if (ImageManager.isMediaScannerScanning(mContext.getContentResolver())) {
93             stopListeners();
94         }
95     }
96     
97     private void stopListeners() {
98         ContentResolver cr = mContext.getContentResolver();
99         if (mObserver != null) {
100             cr.unregisterContentObserver(mObserver);
101         }
102         sObserverActive = false;
103     }
104     
105     protected void refreshUI(MediaFeed feed, long setIdToUse) {
106         if (setIdToUse == Shared.INVALID) {
107             return;
108         }
109         Log.i(TAG, "Refreshing local data source");
110         if (feed.getMediaSet(setIdToUse) == null) {
111             MediaSet mediaSet = feed.addMediaSet(setIdToUse, this);
112             if (setIdToUse == CAMERA_BUCKET_ID) {
113                 mediaSet.mName = CAMERA_STRING;
114             } else if (setIdToUse == DOWNLOAD_BUCKET_ID) {
115                 mediaSet.mName = DOWNLOAD_STRING;
116             }
117             mediaSet.generateTitle(true);
118         } else {
119             MediaSet mediaSet = feed.replaceMediaSet(setIdToUse, this);
120             if (setIdToUse == CAMERA_BUCKET_ID) {
121                 mediaSet.mName = CAMERA_STRING;
122             } else if (setIdToUse == DOWNLOAD_BUCKET_ID) {
123                 mediaSet.mName = DOWNLOAD_STRING;
124             }
125             mediaSet.generateTitle(true);
126         }
127     }
128
129     public void loadItemsForSet(final MediaFeed feed, final MediaSet parentSet, int rangeStart, int rangeEnd) {
130         // Quick load from the cache.
131         if (mContext == null || parentSet == null) {
132             return;
133         }
134         loadMediaItemsIntoMediaFeed(feed, parentSet, rangeStart, rangeEnd);
135     }
136
137     private void loadMediaItemsIntoMediaFeed(final MediaFeed mediaFeed, final MediaSet set, int rangeStart, int rangeEnd) {
138         if (rangeEnd - rangeStart < 0) {
139             return;
140         }
141         CacheService.loadMediaItemsIntoMediaFeed(mediaFeed, set, rangeStart, rangeEnd, !mDisableImages, !mDisableVideos);
142         if (set.mId == CAMERA_BUCKET_ID) {
143             mediaFeed.moveSetToFront(set);
144         }
145     }
146
147     public boolean performOperation(final int operation, final ArrayList<MediaBucket> mediaBuckets, final Object data) {
148         int numBuckets = mediaBuckets.size();
149         ContentResolver cr = mContext.getContentResolver();
150         switch (operation) {
151         case MediaFeed.OPERATION_DELETE:
152             for (int i = 0; i < numBuckets; ++i) {
153                 MediaBucket bucket = mediaBuckets.get(i);
154                 MediaSet set = bucket.mediaSet;
155                 ArrayList<MediaItem> items = bucket.mediaItems;
156                 if (set != null && items == null) {
157                     // Remove the entire bucket.
158                     final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
159                     final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
160                     final String whereImages = Images.ImageColumns.BUCKET_ID + "=" + Long.toString(set.mId);
161                     final String whereVideos = Video.VideoColumns.BUCKET_ID + "=" + Long.toString(set.mId);
162                     cr.delete(uriImages, whereImages, null);
163                     cr.delete(uriVideos, whereVideos, null);
164                     CacheService.markDirty(mContext);
165                 }
166                 if (set != null && items != null) {
167                     // We need to remove these items from the set.
168                     int numItems = items.size();
169                     for (int j = 0; j < numItems; ++j) {
170                         MediaItem item = items.get(j);
171                         cr.delete(Uri.parse(item.mContentUri), null, null);
172                     }
173                     set.updateNumExpectedItems();
174                     set.generateTitle(true);
175                     CacheService.markDirty(mContext, set.mId);
176                 }
177             }
178             break;
179         case MediaFeed.OPERATION_ROTATE:
180             for (int i = 0; i < numBuckets; ++i) {
181                 MediaBucket bucket = mediaBuckets.get(i);
182                 ArrayList<MediaItem> items = bucket.mediaItems;
183                 if (items == null) {
184                     continue;
185                 }
186                 float angleToRotate = ((Float) data).floatValue();
187                 if (angleToRotate == 0) {
188                     return true;
189                 }
190                 int numItems = items.size();
191                 for (int j = 0; j < numItems; ++j) {
192                     rotateItem(items.get(j), angleToRotate);
193                 }
194             }
195             break;
196         }
197         return true;
198     }
199
200     private void rotateItem(final MediaItem item, float angleToRotate) {
201         ContentResolver cr = mContext.getContentResolver();
202         try {
203             int currentOrientation = (int) item.mRotation;
204             angleToRotate += currentOrientation;
205             float rotation = Shared.normalizePositive(angleToRotate);
206             String rotationString = Integer.toString((int) rotation);
207
208             // Update the database entry.
209             ContentValues values = new ContentValues();
210             values.put(Images.ImageColumns.ORIENTATION, rotationString);
211             cr.update(Uri.parse(item.mContentUri), values, null, null);
212
213             // Update the file EXIF information.
214             Uri uri = Uri.parse(item.mContentUri);
215             String uriScheme = uri.getScheme();
216             if (uriScheme.equals("file")) {
217                 ExifInterface exif = new ExifInterface(uri.getPath());
218                 exif.setAttribute(ExifInterface.TAG_ORIENTATION, Integer.toString(Shared.degreesToExifOrientation(rotation)));
219                 exif.saveAttributes();
220             }
221
222             // Invalidate the cache entry.
223             CacheService.markDirty(mContext, item.mParentMediaSet.mId);
224
225             // Update the object representation of the item.
226             item.mRotation = rotation;
227         } catch (Exception e) {
228             // System.out.println("Apparently not a JPEG");
229         }
230     }
231
232     public DiskCache getThumbnailCache() {
233         return sThumbnailCache;
234     }
235
236     public static MediaItem createMediaItemFromUri(Context context, Uri target) {
237         MediaItem item = null;
238         long id = ContentUris.parseId(target);
239         ContentResolver cr = context.getContentResolver();
240         String whereClause = Images.ImageColumns._ID + "=" + Long.toString(id);
241         Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
242         if (cursor != null) {
243             if (cursor.moveToFirst()) {
244                 item = new MediaItem();
245                 CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
246             }
247             cursor.close();
248             cursor = null;
249         }
250         return item;
251     }
252
253     public static MediaItem createMediaItemFromFileUri(Context context, String fileUri) {
254         MediaItem item = null;
255         String filepath = new File(URI.create(fileUri)).toString();
256         ContentResolver cr = context.getContentResolver();
257         long bucketId = SingleDataSource.parseBucketIdFromFileUri(fileUri);
258         String whereClause = Images.ImageColumns.BUCKET_ID + "=" + bucketId + " AND " + Images.ImageColumns.DATA + "='" + filepath
259                 + "'";
260         Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
261         if (cursor != null) {
262             if (cursor.moveToFirst()) {
263                 item = new MediaItem();
264                 CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
265             }
266             cursor.close();
267             cursor = null;
268         }
269         return item;
270     }
271 }