• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.cooliris.media;
18 
19 import java.util.ArrayList;
20 
21 public class MediaSet {
22     public static final int TYPE_SMART = 0;
23     public static final int TYPE_FOLDER = 1;
24     public static final int TYPE_USERDEFINED = 2;
25 
26     public long mId;
27     public String mName;
28 
29     public boolean mFlagForDelete;
30 
31     public boolean mHasImages;
32     public boolean mHasVideos;
33 
34     // The type of the media set. A smart media set is an automatically
35     // generated media set. For example, the most recently
36     // viewed items media set is a media set that gets populated by the contents
37     // of a folder. A user defined media set
38     // is a set that is made by the user. This would typically correspond to
39     // media items belonging to an event.
40     public int mType;
41 
42     // The min and max date taken and added at timestamps.
43     public long mMinTimestamp = Long.MAX_VALUE;
44     public long mMaxTimestamp = 0;
45     public long mMinAddedTimestamp = Long.MAX_VALUE;
46     public long mMaxAddedTimestamp = 0;
47 
48     // The latitude and longitude of the min latitude point.
49     public double mMinLatLatitude = LocationMediaFilter.LAT_MAX;
50     public double mMinLatLongitude;
51     // The latitude and longitude of the max latitude point.
52     public double mMaxLatLatitude = LocationMediaFilter.LAT_MIN;
53     public double mMaxLatLongitude;
54     // The latitude and longitude of the min longitude point.
55     public double mMinLonLatitude;
56     public double mMinLonLongitude = LocationMediaFilter.LON_MAX;
57     // The latitude and longitude of the max longitude point.
58     public double mMaxLonLatitude;
59     public double mMaxLonLongitude = LocationMediaFilter.LON_MIN;
60 
61     // Reverse geocoding the latitude, longitude and getting an address or
62     // location.
63     public String mReverseGeocodedLocation;
64     // Set to true if at least one item in the set has a valid latitude and
65     // longitude.
66     public boolean mLatLongDetermined = false;
67     public boolean mReverseGeocodedLocationComputed = false;
68     public boolean mReverseGeocodedLocationRequestMade = false;
69 
70     public String mTitleString;
71     public String mTruncTitleString;
72     public String mNoCountTitleString;
73 
74     public String mEditUri = null;
75     public long mPicasaAlbumId = Shared.INVALID;
76     public boolean mIsLocal = true;
77 
78     public DataSource mDataSource;
79     public boolean mSyncPending = false;
80 
81     private ArrayList<MediaItem> mItems;
82     private LongSparseArray<MediaItem> mItemsLookup;
83     private LongSparseArray<MediaItem> mItemsLookupVideo;
84     public int mNumItemsLoaded = 0;
85     // mNumExpectedItems is preset to how many items are expected to be in the
86     // set as it is used to visually
87     // display the number of items in the set and we don't want this display to
88     // keep changing as items get loaded.
89     private int mNumExpectedItems = 0;
90     private boolean mNumExpectedItemsCountAccurate = false;
91     private int mCurrentLocation = 0;
92 
MediaSet()93     public MediaSet() {
94         this(null);
95     }
96 
MediaSet(DataSource dataSource)97     public MediaSet(DataSource dataSource) {
98         mItems = new ArrayList<MediaItem>(16);
99         mItemsLookup = new LongSparseArray<MediaItem>();
100         mItemsLookup.clear();
101         mItemsLookupVideo = new LongSparseArray<MediaItem>();
102         mItemsLookupVideo.clear();
103         mDataSource = dataSource;
104         // TODO(Venkat): Can we move away from this dummy item setup?
105         MediaItem item = new MediaItem();
106         item.mId = Shared.INVALID;
107         item.mParentMediaSet = this;
108         mItems.add(item);
109         mNumExpectedItems = 16;
110     }
111 
112     /**
113      * @return underlying ArrayList of MediaItems. Use only for iteration (read
114      *         operations) on the ArrayList.
115      */
getItems()116     public ArrayList<MediaItem> getItems() {
117         return mItems;
118     }
119 
setNumExpectedItems(int numExpectedItems)120     public void setNumExpectedItems(int numExpectedItems) {
121         mItems.ensureCapacity(numExpectedItems);
122         mNumExpectedItems = numExpectedItems;
123         mNumExpectedItemsCountAccurate = true;
124     }
125 
getNumExpectedItems()126     public int getNumExpectedItems() {
127         return mNumExpectedItems;
128     }
129 
setContainsValidItems()130     public boolean setContainsValidItems() {
131         if (mNumExpectedItems == 0)
132             return false;
133         return true;
134     }
135 
updateNumExpectedItems()136     public void updateNumExpectedItems() {
137         mNumExpectedItems = mNumItemsLoaded;
138         mNumExpectedItemsCountAccurate = true;
139     }
140 
getNumItems()141     public int getNumItems() {
142         return mItems.size();
143     }
144 
clear()145     public void clear() {
146         mItems.clear();
147         MediaItem item = new MediaItem();
148         item.mId = Shared.INVALID;
149         item.mParentMediaSet = this;
150         mItems.add(item);
151         mNumExpectedItems = 16;
152         refresh();
153         mItemsLookup.clear();
154         mItemsLookupVideo.clear();
155     }
156 
157     /**
158      * Generates the label for the MediaSet.
159      */
generateTitle(final boolean truncateTitle)160     public void generateTitle(final boolean truncateTitle) {
161         if (mName == null) {
162             mName = "";
163         }
164         String size = (mNumExpectedItemsCountAccurate) ? "  (" + mNumExpectedItems + ")" : "";
165         mTitleString = mName + size;
166         if (truncateTitle) {
167             int length = mName.length();
168             mTruncTitleString = (length > 16) ? mName.substring(0, 12) + "..." + mName.substring(length - 4, length) + size : mName
169                     + size;
170             mNoCountTitleString = mName;
171         } else {
172             mTruncTitleString = mTitleString;
173         }
174     }
175 
176     /**
177      * Adds a MediaItem to this set, and increments the load count.
178      * Additionally, it also recomputes the location bounds and time range of
179      * the media set.
180      */
addItem(final MediaItem itemToAdd)181     public void addItem(final MediaItem itemToAdd) {
182         // Important to not set the parentMediaSet in here as temporary
183         // MediaSet's are occasionally
184         // created and we do not want the MediaItem updated as a result of that.
185         if (itemToAdd == null) {
186             return;
187         }
188         final LongSparseArray<MediaItem> lookup = (itemToAdd.getMediaType() == MediaItem.MEDIA_TYPE_IMAGE) ? mItemsLookup
189                 : mItemsLookupVideo;
190         MediaItem lookupItem = lookup.get(itemToAdd.mId);
191         if (lookupItem != null && !lookupItem.mFilePath.equals(itemToAdd.mFilePath)) {
192             lookupItem = null;
193         }
194         final MediaItem item = (lookupItem == null) ? itemToAdd : lookupItem;
195         item.mFlagForDelete = false;
196         if (mItems.size() == 0) {
197             mItems.add(item);
198         } else if (mItems.get(0).mId == -1L) {
199             mItems.set(0, item);
200         } else {
201             if (mItems.size() > mCurrentLocation) {
202                 mItems.set(mCurrentLocation, item);
203             } else {
204                 mItems.add(mCurrentLocation, item);
205             }
206         }
207         if (item.mId != Shared.INVALID) {
208             if (lookupItem == null) {
209                 lookup.put(item.mId, item);
210             }
211             ++mNumItemsLoaded;
212             ++mCurrentLocation;
213         }
214         if (item.isDateTakenValid()) {
215             long dateTaken = item.mDateTakenInMs;
216             if (dateTaken < mMinTimestamp) {
217                 mMinTimestamp = dateTaken;
218             }
219             if (dateTaken > mMaxTimestamp) {
220                 mMaxTimestamp = dateTaken;
221             }
222         } else if (item.isDateAddedValid()) {
223             long dateAdded = item.mDateAddedInSec * 1000;
224             if (dateAdded < mMinAddedTimestamp) {
225                 mMinAddedTimestamp = dateAdded;
226             }
227             if (dateAdded > mMaxAddedTimestamp) {
228                 mMaxAddedTimestamp = dateAdded;
229             }
230         }
231 
232         // Determining the latitude longitude bounds of the set and setting the
233         // location string.
234         if (!item.isLatLongValid()) {
235             return;
236         }
237         double itemLatitude = item.mLatitude;
238         double itemLongitude = item.mLongitude;
239         if (mMinLatLatitude > itemLatitude) {
240             mMinLatLatitude = itemLatitude;
241             mMinLatLongitude = itemLongitude;
242             mLatLongDetermined = true;
243         }
244         if (mMaxLatLatitude < itemLatitude) {
245             mMaxLatLatitude = itemLatitude;
246             mMaxLatLongitude = itemLongitude;
247             mLatLongDetermined = true;
248         }
249         if (mMinLonLongitude > itemLongitude) {
250             mMinLonLatitude = itemLatitude;
251             mMinLonLongitude = itemLongitude;
252             mLatLongDetermined = true;
253         }
254         if (mMaxLonLongitude < itemLongitude) {
255             mMaxLonLatitude = itemLatitude;
256             mMaxLonLongitude = itemLongitude;
257             mLatLongDetermined = true;
258         }
259     }
260 
261     /**
262      * Removes a MediaItem if present in the MediaSet.
263      *
264      * @return true if the item was removed, false if removal failed or item was
265      *         not present in the set.
266      */
removeItem(final MediaItem itemToRemove)267     public boolean removeItem(final MediaItem itemToRemove) {
268         synchronized (mItems) {
269             if (mItems.remove(itemToRemove)) {
270                 --mNumExpectedItems;
271                 --mNumItemsLoaded;
272                 --mCurrentLocation;
273                 final LongSparseArray<MediaItem> lookup = (itemToRemove.getMediaType() == MediaItem.MEDIA_TYPE_IMAGE) ? mItemsLookup
274                         : mItemsLookupVideo;
275                 lookup.remove(itemToRemove.mId);
276                 return true;
277             }
278             return false;
279         }
280     }
281 
removeDuplicate(final MediaItem itemToRemove)282     public void removeDuplicate(final MediaItem itemToRemove) {
283         synchronized (mItems) {
284             int numItems = mItems.size();
285             boolean foundItem = false;
286             for (int i = 0; i < numItems; ++i) {
287                 final MediaItem item = mItems.get(i);
288                 if (item == itemToRemove) {
289                     if (foundItem == false) {
290                         foundItem = true;
291                     } else {
292                         mItems.remove(i);
293                         --mNumExpectedItems;
294                         --mNumItemsLoaded;
295                         --mCurrentLocation;
296                         break;
297                     }
298                 }
299             }
300         }
301     }
302 
303     /**
304      * @return true if this MediaSet contains the argument MediaItem.
305      */
lookupContainsItem(final MediaItem item)306     public boolean lookupContainsItem(final MediaItem item) {
307         final LongSparseArray<MediaItem> lookupTable = (item.getMediaType() == MediaItem.MEDIA_TYPE_IMAGE) ? mItemsLookup
308                 : mItemsLookupVideo;
309         MediaItem lookUp = lookupTable.get(item.mId);
310         if (lookUp != null && lookUp.mFilePath.equals(item.mFilePath)) {
311             return true;
312         } else {
313             return false;
314         }
315     }
316 
317     /**
318      * @return true if the title string is truncated.
319      */
isTruncated()320     public boolean isTruncated() {
321         return (mTitleString != null && !mTitleString.equals(mTruncTitleString));
322     }
323 
324     /**
325      * @return true if timestamps are available for this set.
326      */
areTimestampsAvailable()327     public boolean areTimestampsAvailable() {
328         return (mMinTimestamp < Long.MAX_VALUE && mMaxTimestamp > 0);
329     }
330 
331     /**
332      * @return true if the added timestamps are available for this set.
333      */
areAddedTimestampsAvailable()334     public boolean areAddedTimestampsAvailable() {
335         return (mMinAddedTimestamp < Long.MAX_VALUE && mMaxAddedTimestamp > 0);
336     }
337 
338     /**
339      * @return true if this set of items corresponds to Picassa items.
340      */
isPicassaSet()341     public boolean isPicassaSet() {
342         // 2 cases:-
343         // 1. This set is just a Picassa Album, and all its items are therefore
344         // from Picassa.
345         // 2. This set is a random collection of items and each item is a
346         // Picassa item.
347         if (isPicassaAlbum()) {
348             return true;
349         }
350         int numItems = mItems.size();
351         for (int i = 0; i < numItems; i++) {
352             if (!mItems.get(i).isPicassaItem()) {
353                 return false;
354             }
355         }
356         return true;
357     }
358 
359     /**
360      * @return true if this set is a Picassa album.
361      */
isPicassaAlbum()362     public boolean isPicassaAlbum() {
363         return (mPicasaAlbumId != Shared.INVALID);
364     }
365 
refresh()366     public void refresh() {
367         mNumItemsLoaded = 0;
368         mCurrentLocation = 0;
369         final ArrayList<MediaItem> items = mItems;
370         final int numItems = items.size();
371         for (int i = 0; i < numItems; ++i) {
372             MediaItem item = items.get(i);
373             item.mFlagForDelete = true;
374         }
375     }
376 
checkForDeletedItems()377     public void checkForDeletedItems() {
378         final ArrayList<MediaItem> items = mItems;
379         final ArrayList<MediaItem> itemsToDelete = new ArrayList<MediaItem>();
380         synchronized (items) {
381             final int numItems = items.size();
382             for (int i = 0; i < numItems; ++i) {
383                 MediaItem item = items.get(i);
384                 if (item.mFlagForDelete) {
385                     itemsToDelete.add(item);
386                 }
387             }
388         }
389         final int numItemsToDelete = itemsToDelete.size();
390         for (int i = 0; i < numItemsToDelete; ++i) {
391             removeItem(itemsToDelete.get(i));
392         }
393     }
394 }
395