OSDN Git Service

e3b9f8728c85b073832d717a958aeb99eb582291
[android-x86/packages-apps-Gallery2.git] / src / com / cooliris / media / PicasaDataSource.java
1 package com.cooliris.media;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5
6 import android.accounts.Account;
7 import android.content.ContentProviderClient;
8 import android.content.ContentResolver;
9 import android.content.Context;
10 import android.database.ContentObserver;
11 import android.database.Cursor;
12 import android.net.Uri;
13 import android.os.Handler;
14 import android.os.RemoteException;
15 import android.util.Log;
16
17 import com.cooliris.picasa.AlbumEntry;
18 import com.cooliris.picasa.Entry;
19 import com.cooliris.picasa.EntrySchema;
20 import com.cooliris.picasa.PicasaApi;
21 import com.cooliris.picasa.PicasaContentProvider;
22 import com.cooliris.picasa.PicasaService;
23
24 public final class PicasaDataSource implements DataSource {
25     private static final String TAG = "PicasaDataSource";
26     public static final DiskCache sThumbnailCache = new DiskCache("picasa-thumbs");
27     private static final String DEFAULT_BUCKET_SORT_ORDER = AlbumEntry.Columns.USER + ", " + AlbumEntry.Columns.DATE_PUBLISHED
28             + " DESC";
29
30     private ContentProviderClient mProviderClient;
31     private final Context mContext;
32     private ContentObserver mAlbumObserver;
33
34     public PicasaDataSource(final Context context) {
35         mContext = context;
36     }
37     
38     public static final HashMap<String, Boolean> getAccountStatus(final Context context) {
39         final Account[] accounts = PicasaApi.getAccounts(context);
40         int numAccounts = accounts.length;
41         HashMap<String, Boolean> accountsEnabled = new HashMap<String, Boolean>(numAccounts);
42         for (int i = 0; i < numAccounts; ++i) {
43             Account account = accounts[i];
44             boolean isEnabled = ContentResolver.getSyncAutomatically(account, PicasaContentProvider.AUTHORITY);
45             String username = account.name;
46             if (username.contains("@gmail.") || username.contains("@googlemail.")) {
47                 // Strip the domain from GMail accounts for canonicalization. TODO: is there an official way?
48                 username = username.substring(0, username.indexOf('@'));
49             }
50             accountsEnabled.put(username, new Boolean(isEnabled));
51         }
52         return accountsEnabled;
53     }
54
55     public void loadMediaSets(final MediaFeed feed) {
56         // We do this here and not in the constructor to speed application loading time since this method is called in a background thread
57         if (mProviderClient == null) {
58             mProviderClient = mContext.getContentResolver().acquireContentProviderClient(PicasaContentProvider.AUTHORITY);
59         }
60         // Force permission dialog to be displayed if necessary. TODO: remove this after signed by Google.
61         PicasaApi.getAccounts(mContext);
62
63         // Ensure that users are up to date. TODO: also listen for accounts changed broadcast.
64         PicasaService.requestSync(mContext, PicasaService.TYPE_USERS_ALBUMS, 0);
65         final Handler handler = ((Gallery) mContext).getHandler();
66         final ContentObserver albumObserver = new ContentObserver(handler) {
67             public void onChange(boolean selfChange) {
68                 loadMediaSetsIntoFeed(feed, true);
69             }
70         };
71         mAlbumObserver = albumObserver;
72         loadMediaSetsIntoFeed(feed, true);
73
74         // Start listening.
75         ContentResolver cr = mContext.getContentResolver();
76         cr.registerContentObserver(PicasaContentProvider.ALBUMS_URI, false, mAlbumObserver);
77         cr.registerContentObserver(PicasaContentProvider.PHOTOS_URI, false, mAlbumObserver);
78     }
79
80     public void shutdown() {
81         if (mAlbumObserver != null) {
82             ContentResolver cr = mContext.getContentResolver();
83             cr.unregisterContentObserver(mAlbumObserver);
84         }
85     }
86
87     public void loadItemsForSet(final MediaFeed feed, final MediaSet parentSet, int rangeStart, int rangeEnd) {
88         if (parentSet == null) {
89             return;
90         } else {
91             // Return a list of items within an album.
92             addItemsToFeed(feed, parentSet, rangeStart, rangeEnd);
93         }
94     }
95
96     protected void loadMediaSetsIntoFeed(final MediaFeed feed, boolean sync) {
97         final HashMap<String, Boolean> accountsEnabled = getAccountStatus(mContext);
98         final ContentProviderClient client = mProviderClient;
99         if (client == null)
100             return;
101         try {
102             final EntrySchema albumSchema = AlbumEntry.SCHEMA;
103             final Cursor cursor = client.query(PicasaContentProvider.ALBUMS_URI, albumSchema.getProjection(), null, null,
104                     DEFAULT_BUCKET_SORT_ORDER);
105             final AlbumEntry album = new AlbumEntry();
106             MediaSet mediaSet;
107             if (cursor.moveToFirst()) {
108                 final int numAlbums = cursor.getCount();
109                 final ArrayList<MediaSet> picasaSets = new ArrayList<MediaSet>(numAlbums);
110                 do {
111                     albumSchema.cursorToObject(cursor, album);
112                     final Boolean accountEnabledObj = accountsEnabled.get(album.user);
113                     final boolean accountEnabled = (accountEnabledObj == null) ? false : accountEnabledObj.booleanValue();
114                     if (accountEnabled) {
115                         mediaSet = feed.getMediaSet(album.id);
116                         if (mediaSet == null) {
117                             mediaSet = feed.addMediaSet(album.id, this);
118                             mediaSet.mName = album.title;
119                             mediaSet.mEditUri = album.editUri;
120                             mediaSet.generateTitle(true);
121                         } else {
122                             mediaSet.setNumExpectedItems(album.numPhotos);
123                         }
124                         mediaSet.mPicasaAlbumId = album.id;
125                         mediaSet.mSyncPending = album.photosDirty;
126                         picasaSets.add(mediaSet);
127                     }
128                 } while (cursor.moveToNext());
129             }
130             cursor.close();
131         } catch (RemoteException e) {
132             Log.e(TAG, "Error occurred loading albums");
133         }
134     }
135
136     private void addItemsToFeed(MediaFeed feed, MediaSet set, int start, int end) {
137         final ContentProviderClient client = mProviderClient;
138         Cursor cursor = null;
139         try {
140             // Query photos in the album.
141             final EntrySchema photosSchema = PhotoProjection.SCHEMA;
142             final String whereInAlbum = "album_id = " + Long.toString(set.mId);
143             cursor = client.query(PicasaContentProvider.PHOTOS_URI, photosSchema.getProjection(), whereInAlbum, null, null);
144             final PhotoProjection photo = new PhotoProjection();
145             int count = cursor.getCount();
146             if (count < end) {
147                 end = count;
148             }
149             set.setNumExpectedItems(count);
150             set.generateTitle(true);
151             // Move to the next unread item.
152             final int newIndex = start + 1;
153             if (newIndex > count || !cursor.move(newIndex)) {
154                 end = 0;
155                 cursor.close();
156                 set.updateNumExpectedItems();
157                 set.generateTitle(true);
158                 return;
159             }
160             if (set.mNumItemsLoaded == 0) {
161                 photosSchema.cursorToObject(cursor, photo);
162                 set.mMinTimestamp = photo.dateTaken;
163                 cursor.moveToLast();
164                 photosSchema.cursorToObject(cursor, photo);
165                 set.mMinTimestamp = photo.dateTaken;
166                 cursor.moveToFirst();
167             }
168             for (int i = 0; i < end; ++i) {
169                 photosSchema.cursorToObject(cursor, photo);
170                 final MediaItem item = new MediaItem();
171                 item.mId = photo.id;
172                 item.mEditUri = photo.editUri;
173                 item.mMimeType = photo.contentType;
174                 item.mDateTakenInMs = photo.dateTaken;
175                 item.mLatitude = photo.latitude;
176                 item.mLongitude = photo.longitude;
177                 item.mThumbnailUri = photo.thumbnailUrl;
178                 item.mScreennailUri = photo.screennailUrl;
179                 item.mContentUri = photo.contentUrl;
180                 item.mCaption = photo.title;
181                 item.mWeblink = photo.htmlPageUrl;
182                 item.mDescription = photo.summary;
183                 item.mFilePath = item.mContentUri;
184                 feed.addItemToMediaSet(item, set);
185                 if (!cursor.moveToNext()) {
186                     break;
187                 }
188             }
189         } catch (Exception e) {
190             Log.e(TAG, "Error occurred loading photos for album " + set.mId);
191         } finally {
192             if (cursor != null) {
193                 cursor.close();
194             }
195         }
196     }
197
198     public boolean performOperation(final int operation, final ArrayList<MediaBucket> mediaBuckets, final Object data) {
199         try {
200             if (operation == MediaFeed.OPERATION_DELETE) {
201                 ContentProviderClient client = mProviderClient;
202                 for (int i = 0, numBuckets = mediaBuckets.size(); i != numBuckets; ++i) {
203                     MediaBucket bucket = mediaBuckets.get(i);
204                     ArrayList<MediaItem> items = bucket.mediaItems;
205                     if (items == null) {
206                         // Delete an album.
207                         String albumUri = PicasaContentProvider.ALBUMS_URI + "/" + bucket.mediaSet.mId;
208                         client.delete(Uri.parse(albumUri), null, null);
209                     } else {
210                         // Delete a set of photos.
211                         for (int j = 0, numItems = items.size(); j != numItems; ++j) {
212                             MediaItem item = items.get(j);
213                             if (item != null) {
214                                 String itemUri = PicasaContentProvider.PHOTOS_URI + "/" + item.mId;
215                                 client.delete(Uri.parse(itemUri), null, null);
216                             }
217                         }
218                     }
219                 }
220             }
221             return true;
222         } catch (RemoteException e) {
223             return false;
224         }
225     }
226
227     public DiskCache getThumbnailCache() {
228         return sThumbnailCache;
229     }
230
231     /**
232      * The projection of PhotoEntry needed by the data source.
233      */
234     private static final class PhotoProjection extends Entry {
235         public static final EntrySchema SCHEMA = new EntrySchema(PhotoProjection.class);
236         @Column("edit_uri")
237         public String editUri;
238         @Column("title")
239         public String title;
240         @Column("summary")
241         public String summary;
242         @Column("date_taken")
243         public long dateTaken;
244         @Column("latitude")
245         public double latitude;
246         @Column("longitude")
247         public double longitude;
248         @Column("thumbnail_url")
249         public String thumbnailUrl;
250         @Column("screennail_url")
251         public String screennailUrl;
252         @Column("content_url")
253         public String contentUrl;
254         @Column("content_type")
255         public String contentType;
256         @Column("html_page_url")
257         public String htmlPageUrl;
258     }
259 }