OSDN Git Service

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