packages/apps/Gallery2
修订版 | d8a6d17db8aaef2ea06c78fe643f06601d8aec5d (tree) |
---|---|
时间 | 2009-12-01 05:11:59 |
作者 | Dave Sparks <davidsparks@andr...> |
Commiter | Dave Sparks |
Updates to 3D Gallery.
@@ -139,7 +139,8 @@ | ||
139 | 139 | <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget_info" /> |
140 | 140 | </receiver> |
141 | 141 | |
142 | - <!-- We configure a widget by asking to pick a photo, then crop it, and store the config internally --> | |
142 | + <!-- We configure a widget by asking to pick a photo, then crop it, and store the config internally | |
143 | +--> | |
143 | 144 | <activity android:name="PhotoAppWidgetConfigure"> |
144 | 145 | <intent-filter> |
145 | 146 | <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" /> |
@@ -148,7 +149,8 @@ | ||
148 | 149 | |
149 | 150 | <!-- We also allow direct binding where the caller provides a bitmap and |
150 | 151 | appWidgetId to bind. We require the permission because this changes our |
151 | - internal database without user confirmation. --> | |
152 | + internal database without user confirmation. | |
153 | +--> | |
152 | 154 | <activity android:name="PhotoAppWidgetBind" android:exported="true" |
153 | 155 | android:theme="@android:style/Theme.NoDisplay" |
154 | 156 | android:permission="android.permission.BIND_APPWIDGET" /> |
@@ -10,11 +10,11 @@ import android.net.Uri; | ||
10 | 10 | import android.util.Log; |
11 | 11 | |
12 | 12 | public class BootReceiver extends BroadcastReceiver { |
13 | - private final String TAG = "BootReceiver"; | |
13 | + private static final String TAG = "BootReceiver"; | |
14 | 14 | |
15 | 15 | @Override |
16 | 16 | public void onReceive(Context context, Intent intent) { |
17 | - String action = intent.getAction(); | |
17 | + final String action = intent.getAction(); | |
18 | 18 | Log.i(TAG, "Got intent with action " + action); |
19 | 19 | if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) { |
20 | 20 | CacheService.markDirty(context); |
@@ -23,8 +23,8 @@ public class BootReceiver extends BroadcastReceiver { | ||
23 | 23 | // Do nothing, wait for the mediascanner to be done after mounting. |
24 | 24 | ; |
25 | 25 | } else if (action.equals(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)) { |
26 | - Uri fileUri = intent.getData(); | |
27 | - long bucketId = SingleDataSource.parseBucketIdFromFileUri(fileUri.toString()); | |
26 | + final Uri fileUri = intent.getData(); | |
27 | + final long bucketId = SingleDataSource.parseBucketIdFromFileUri(fileUri.toString()); | |
28 | 28 | if (!CacheService.isPresentInCache(bucketId)) { |
29 | 29 | CacheService.markDirty(context); |
30 | 30 | } |
@@ -40,6 +40,7 @@ import android.util.Log; | ||
40 | 40 | |
41 | 41 | import com.cooliris.media.DataSource; |
42 | 42 | import com.cooliris.media.DiskCache; |
43 | +import com.cooliris.media.Gallery; | |
43 | 44 | import com.cooliris.media.LocalDataSource; |
44 | 45 | import com.cooliris.media.LongSparseArray; |
45 | 46 | import com.cooliris.media.MediaFeed; |
@@ -52,10 +53,12 @@ import com.cooliris.media.UriTexture; | ||
52 | 53 | import com.cooliris.media.Utils; |
53 | 54 | |
54 | 55 | public final class CacheService extends IntentService { |
55 | - private static final String TAG = "CacheService"; | |
56 | 56 | public static final String ACTION_CACHE = "com.cooliris.cache.action.CACHE"; |
57 | 57 | public static final DiskCache sAlbumCache = new DiskCache("local-album-cache"); |
58 | 58 | |
59 | + private static final String TAG = "CacheService"; | |
60 | + private static ImageList sList = null; | |
61 | + | |
59 | 62 | // Wait 2 seconds to start the thumbnailer so that the application can load without any overheads. |
60 | 63 | private static final int THUMBNAILER_WAIT_IN_MS = 2000; |
61 | 64 | private static final int DEFAULT_THUMBNAIL_WIDTH = 128; |
@@ -81,8 +84,9 @@ public final class CacheService extends IntentService { | ||
81 | 84 | public static final int THUMBNAIL_ID_INDEX = 0; |
82 | 85 | public static final int THUMBNAIL_DATE_MODIFIED_INDEX = 1; |
83 | 86 | public static final int THUMBNAIL_DATA_INDEX = 2; |
87 | + public static final int THUMBNAIL_ORIENTATION_INDEX = 2; | |
84 | 88 | public static final String[] THUMBNAIL_PROJECTION = new String[] { Images.ImageColumns._ID, Images.ImageColumns.DATE_MODIFIED, |
85 | - Images.ImageColumns.DATA }; | |
89 | + Images.ImageColumns.DATA, Images.ImageColumns.ORIENTATION }; | |
86 | 90 | |
87 | 91 | // Must preserve order between these indices and the order of the terms in INITIAL_PROJECTION_IMAGES and |
88 | 92 | // INITIAL_PROJECTION_VIDEOS. |
@@ -121,26 +125,27 @@ public final class CacheService extends IntentService { | ||
121 | 125 | |
122 | 126 | private static final DateFormat mDateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss"); |
123 | 127 | private static final DateFormat mAltDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); |
128 | + private static final byte[] sDummyData = new byte[] { 1 }; | |
124 | 129 | private static boolean QUEUE_DIRTY_SET; |
125 | 130 | private static boolean QUEUE_DIRTY_ALL; |
126 | 131 | |
127 | - public static String getCachePath(String subFolderName) { | |
132 | + public static final String getCachePath(final String subFolderName) { | |
128 | 133 | return Environment.getExternalStorageDirectory() + "/Android/data/com.cooliris.media/cache/" + subFolderName; |
129 | 134 | } |
130 | 135 | |
131 | - public static void startCache(final Context context, boolean checkthumbnails) { | |
132 | - Locale locale = getLocaleForAlbumCache(); | |
133 | - Locale defaultLocale = Locale.getDefault(); | |
136 | + public static final void startCache(final Context context, final boolean checkthumbnails) { | |
137 | + final Locale locale = getLocaleForAlbumCache(); | |
138 | + final Locale defaultLocale = Locale.getDefault(); | |
134 | 139 | if (locale == null || !locale.equals(defaultLocale)) { |
135 | 140 | sAlbumCache.deleteAll(); |
136 | - putLocaleForAlbumCache(Locale.getDefault()); | |
141 | + putLocaleForAlbumCache(defaultLocale); | |
137 | 142 | } |
138 | 143 | final Intent intent = new Intent(ACTION_CACHE, null, context, CacheService.class); |
139 | 144 | intent.putExtra("checkthumbnails", checkthumbnails); |
140 | 145 | context.startService(intent); |
141 | 146 | } |
142 | 147 | |
143 | - public static boolean isCacheReady(final boolean onlyMediaSets) { | |
148 | + public static final boolean isCacheReady(final boolean onlyMediaSets) { | |
144 | 149 | if (onlyMediaSets) { |
145 | 150 | return (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null && sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0) == null); |
146 | 151 | } else { |
@@ -149,17 +154,17 @@ public final class CacheService extends IntentService { | ||
149 | 154 | } |
150 | 155 | } |
151 | 156 | |
152 | - public static boolean isCacheReady(long setId) { | |
153 | - boolean isReady = (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null | |
157 | + public static final boolean isCacheReady(final long setId) { | |
158 | + final boolean isReady = (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null | |
154 | 159 | && sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0) == null && sAlbumCache.get(ALBUM_CACHE_INCOMPLETE_INDEX, 0) == null); |
155 | 160 | if (!isReady) { |
156 | 161 | return isReady; |
157 | 162 | } |
158 | 163 | // Also, we need to check if this setId is dirty. |
159 | - byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0); | |
164 | + final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0); | |
160 | 165 | if (existingData != null && existingData.length > 0) { |
161 | - long[] ids = toLongArray(existingData); | |
162 | - int numIds = ids.length; | |
166 | + final long[] ids = toLongArray(existingData); | |
167 | + final int numIds = ids.length; | |
163 | 168 | for (int i = 0; i < numIds; ++i) { |
164 | 169 | if (ids[i] == setId) { |
165 | 170 | return false; |
@@ -169,13 +174,13 @@ public final class CacheService extends IntentService { | ||
169 | 174 | return true; |
170 | 175 | } |
171 | 176 | |
172 | - public static boolean isPresentInCache(long setId) { | |
177 | + public static final boolean isPresentInCache(final long setId) { | |
173 | 178 | return sAlbumCache.get(setId, 0) != null; |
174 | 179 | } |
175 | 180 | |
176 | - public final static void markDirty(final Context context) { | |
177 | - byte[] data = new byte[] { 1 }; | |
178 | - sAlbumCache.put(ALBUM_CACHE_DIRTY_INDEX, data); | |
181 | + public static final void markDirty(final Context context) { | |
182 | + sList = null; | |
183 | + sAlbumCache.put(ALBUM_CACHE_DIRTY_INDEX, sDummyData); | |
179 | 184 | if (CACHE_THREAD.get() == null) { |
180 | 185 | restartThread(CACHE_THREAD, "CacheRefresh", new Runnable() { |
181 | 186 | public void run() { |
@@ -187,12 +192,13 @@ public final class CacheService extends IntentService { | ||
187 | 192 | } |
188 | 193 | } |
189 | 194 | |
190 | - public final static void markDirtyImmediate(long id) { | |
195 | + public static final void markDirtyImmediate(final long id) { | |
196 | + sList = null; | |
191 | 197 | byte[] data = longToByteArray(id); |
192 | - byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0); | |
198 | + final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0); | |
193 | 199 | if (existingData != null && existingData.length > 0) { |
194 | - long[] ids = toLongArray(existingData); | |
195 | - int numIds = ids.length; | |
200 | + final long[] ids = toLongArray(existingData); | |
201 | + final int numIds = ids.length; | |
196 | 202 | for (int i = 0; i < numIds; ++i) { |
197 | 203 | if (ids[i] == id) { |
198 | 204 | return; |
@@ -204,7 +210,7 @@ public final class CacheService extends IntentService { | ||
204 | 210 | sAlbumCache.put(ALBUM_CACHE_DIRTY_BUCKET_INDEX, data); |
205 | 211 | } |
206 | 212 | |
207 | - public final static void markDirty(final Context context, long id) { | |
213 | + public static final void markDirty(final Context context, final long id) { | |
208 | 214 | markDirtyImmediate(id); |
209 | 215 | if (CACHE_THREAD.get() == null) { |
210 | 216 | restartThread(CACHE_THREAD, "CacheRefreshDirtySets", new Runnable() { |
@@ -217,10 +223,10 @@ public final class CacheService extends IntentService { | ||
217 | 223 | } |
218 | 224 | } |
219 | 225 | |
220 | - public static boolean setHasItems(ContentResolver cr, long setId) { | |
226 | + public static final boolean setHasItems(final ContentResolver cr, final long setId) { | |
221 | 227 | final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI; |
222 | 228 | final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI; |
223 | - StringBuffer whereString = new StringBuffer(Images.ImageColumns.BUCKET_ID + "=" + setId); | |
229 | + final StringBuffer whereString = new StringBuffer(Images.ImageColumns.BUCKET_ID + "=" + setId); | |
224 | 230 | final Cursor cursorImages = cr.query(uriImages, BUCKET_PROJECTION_IMAGES, whereString.toString(), null, null); |
225 | 231 | if (cursorImages != null && cursorImages.getCount() > 0) { |
226 | 232 | cursorImages.close(); |
@@ -234,7 +240,7 @@ public final class CacheService extends IntentService { | ||
234 | 240 | return false; |
235 | 241 | } |
236 | 242 | |
237 | - public static void loadMediaSets(final MediaFeed feed, final DataSource source, final boolean includeImages, | |
243 | + public static final void loadMediaSets(final MediaFeed feed, final DataSource source, final boolean includeImages, | |
238 | 244 | final boolean includeVideos) { |
239 | 245 | int timeElapsed = 0; |
240 | 246 | while (!isCacheReady(true) && timeElapsed < 10000) { |
@@ -245,7 +251,7 @@ public final class CacheService extends IntentService { | ||
245 | 251 | } |
246 | 252 | timeElapsed += 300; |
247 | 253 | } |
248 | - byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0); | |
254 | + final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0); | |
249 | 255 | if (albumData != null && albumData.length > 0) { |
250 | 256 | final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256)); |
251 | 257 | try { |
@@ -278,7 +284,7 @@ public final class CacheService extends IntentService { | ||
278 | 284 | } |
279 | 285 | } |
280 | 286 | |
281 | - public static void loadMediaSet(final MediaFeed feed, final DataSource source, final long bucketId) { | |
287 | + public static final void loadMediaSet(final MediaFeed feed, final DataSource source, final long bucketId) { | |
282 | 288 | int timeElapsed = 0; |
283 | 289 | while (!isCacheReady(false) && timeElapsed < 10000) { |
284 | 290 | try { |
@@ -288,13 +294,13 @@ public final class CacheService extends IntentService { | ||
288 | 294 | } |
289 | 295 | timeElapsed += 300; |
290 | 296 | } |
291 | - byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0); | |
297 | + final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0); | |
292 | 298 | if (albumData != null && albumData.length > 0) { |
293 | 299 | DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256)); |
294 | 300 | try { |
295 | - int numAlbums = dis.readInt(); | |
301 | + final int numAlbums = dis.readInt(); | |
296 | 302 | for (int i = 0; i < numAlbums; ++i) { |
297 | - long setId = dis.readLong(); | |
303 | + final long setId = dis.readLong(); | |
298 | 304 | MediaSet mediaSet = null; |
299 | 305 | if (setId == bucketId) { |
300 | 306 | mediaSet = feed.getMediaSet(setId); |
@@ -321,7 +327,7 @@ public final class CacheService extends IntentService { | ||
321 | 327 | } |
322 | 328 | } |
323 | 329 | |
324 | - public static void loadMediaItemsIntoMediaFeed(final MediaFeed feed, final MediaSet set, final int rangeStart, | |
330 | + public static final void loadMediaItemsIntoMediaFeed(final MediaFeed feed, final MediaSet set, final int rangeStart, | |
325 | 331 | final int rangeEnd, final boolean includeImages, final boolean includeVideos) { |
326 | 332 | int timeElapsed = 0; |
327 | 333 | byte[] albumData = null; |
@@ -337,13 +343,13 @@ public final class CacheService extends IntentService { | ||
337 | 343 | if (albumData != null && set.mNumItemsLoaded < set.getNumExpectedItems()) { |
338 | 344 | final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256)); |
339 | 345 | try { |
340 | - int numItems = dis.readInt(); | |
346 | + final int numItems = dis.readInt(); | |
341 | 347 | Log.i(TAG, "Loading Set Id " + set.mId + " with " + numItems + " items."); |
342 | 348 | set.setNumExpectedItems(numItems); |
343 | 349 | set.mMinTimestamp = dis.readLong(); |
344 | 350 | set.mMaxTimestamp = dis.readLong(); |
345 | 351 | for (int i = 0; i < numItems; ++i) { |
346 | - MediaItem item = new MediaItem(); | |
352 | + final MediaItem item = new MediaItem(); | |
347 | 353 | // Must preserve order with method that writes to cache. |
348 | 354 | item.mId = dis.readLong(); |
349 | 355 | item.mCaption = Utils.readUTF(dis); |
@@ -380,61 +386,65 @@ public final class CacheService extends IntentService { | ||
380 | 386 | set.generateTitle(true); |
381 | 387 | } |
382 | 388 | |
383 | - public static void populateVideoItemFromCursor(MediaItem item, ContentResolver cr, Cursor cursor, String baseUri) { | |
389 | + public static final void populateVideoItemFromCursor(final MediaItem item, final ContentResolver cr, final Cursor cursor, | |
390 | + final String baseUri) { | |
384 | 391 | item.setMediaType(MediaItem.MEDIA_TYPE_VIDEO); |
385 | 392 | populateMediaItemFromCursor(item, cr, cursor, baseUri); |
386 | 393 | } |
387 | 394 | |
388 | - public static void populateMediaItemFromCursor(MediaItem item, ContentResolver cr, Cursor cursor, String baseUri) { | |
395 | + public static final void populateMediaItemFromCursor(final MediaItem item, final ContentResolver cr, final Cursor cursor, | |
396 | + final String baseUri) { | |
389 | 397 | item.mId = cursor.getLong(CacheService.MEDIA_ID_INDEX); |
390 | - item.mCaption = cursor.getString(CacheService.MEDIA_CAPTION_INDEX); | |
398 | + //item.mCaption = cursor.getString(CacheService.MEDIA_CAPTION_INDEX); | |
391 | 399 | item.mMimeType = cursor.getString(CacheService.MEDIA_MIME_TYPE_INDEX); |
392 | 400 | item.mLatitude = cursor.getDouble(CacheService.MEDIA_LATITUDE_INDEX); |
393 | 401 | item.mLongitude = cursor.getDouble(CacheService.MEDIA_LONGITUDE_INDEX); |
394 | 402 | item.mDateTakenInMs = cursor.getLong(CacheService.MEDIA_DATE_TAKEN_INDEX); |
395 | 403 | item.mDateAddedInSec = cursor.getLong(CacheService.MEDIA_DATE_ADDED_INDEX); |
396 | 404 | item.mDateModifiedInSec = cursor.getLong(CacheService.MEDIA_DATE_MODIFIED_INDEX); |
405 | + if (item.mDateTakenInMs == item.mDateModifiedInSec) { | |
406 | + item.mDateTakenInMs = item.mDateModifiedInSec * 1000; | |
407 | + } | |
397 | 408 | item.mFilePath = cursor.getString(CacheService.MEDIA_DATA_INDEX); |
398 | - | |
399 | - int itemMediaType = item.getMediaType(); | |
409 | + if (baseUri != null) | |
410 | + item.mContentUri = baseUri + item.mId; | |
411 | + final int itemMediaType = item.getMediaType(); | |
400 | 412 | // Check to see if a new date taken is available. |
401 | - long dateTaken = fetchDateTaken(item); | |
402 | - if (dateTaken != -1L) { | |
413 | + final long dateTaken = fetchDateTaken(item); | |
414 | + if (dateTaken != -1L && item.mContentUri != null) { | |
403 | 415 | item.mDateTakenInMs = dateTaken; |
404 | - ContentValues values = new ContentValues(); | |
416 | + final ContentValues values = new ContentValues(); | |
405 | 417 | if (itemMediaType == MediaItem.MEDIA_TYPE_VIDEO) { |
406 | 418 | values.put(Video.VideoColumns.DATE_TAKEN, item.mDateTakenInMs); |
407 | 419 | } else { |
408 | 420 | values.put(Images.ImageColumns.DATE_TAKEN, item.mDateTakenInMs); |
409 | 421 | } |
410 | - if (item.mContentUri != null) { | |
411 | - cr.update(Uri.parse(item.mContentUri), values, null, null); | |
412 | - } | |
422 | + cr.update(Uri.parse(item.mContentUri), values, null, null); | |
413 | 423 | } |
414 | 424 | |
415 | - int orientationDurationValue = cursor.getInt(CacheService.MEDIA_ORIENTATION_OR_DURATION_INDEX); | |
425 | + final int orientationDurationValue = cursor.getInt(CacheService.MEDIA_ORIENTATION_OR_DURATION_INDEX); | |
416 | 426 | if (itemMediaType == MediaItem.MEDIA_TYPE_IMAGE) { |
417 | 427 | item.mRotation = orientationDurationValue; |
418 | 428 | } else { |
419 | 429 | item.mDurationInSec = orientationDurationValue; |
420 | 430 | } |
421 | - item.mContentUri = baseUri + item.mId; | |
422 | 431 | } |
423 | 432 | |
424 | 433 | // Returns -1 if we failed to examine EXIF information or EXIF parsing failed. |
425 | - public static long fetchDateTaken(MediaItem item) { | |
434 | + public static final long fetchDateTaken(final MediaItem item) { | |
426 | 435 | if (!item.isDateTakenValid() && !item.mTriedRetrievingExifDateTaken |
427 | 436 | && (item.mFilePath.endsWith(".jpg") || item.mFilePath.endsWith(".jpeg"))) { |
428 | 437 | try { |
429 | - ExifInterface exif = new ExifInterface(item.mFilePath); | |
430 | - String dateTakenStr = exif.getAttribute(ExifInterface.TAG_DATETIME); | |
438 | + Log.i(TAG, "Parsing date taken from exif"); | |
439 | + final ExifInterface exif = new ExifInterface(item.mFilePath); | |
440 | + final String dateTakenStr = exif.getAttribute(ExifInterface.TAG_DATETIME); | |
431 | 441 | if (dateTakenStr != null) { |
432 | 442 | try { |
433 | - Date dateTaken = mDateFormat.parse(dateTakenStr); | |
443 | + final Date dateTaken = mDateFormat.parse(dateTakenStr); | |
434 | 444 | return dateTaken.getTime(); |
435 | 445 | } catch (ParseException pe) { |
436 | 446 | try { |
437 | - Date dateTaken = mAltDateFormat.parse(dateTakenStr); | |
447 | + final Date dateTaken = mAltDateFormat.parse(dateTakenStr); | |
438 | 448 | return dateTaken.getTime(); |
439 | 449 | } catch (ParseException pe2) { |
440 | 450 | Log.i(TAG, "Unable to parse date out of string - " + dateTakenStr); |
@@ -451,73 +461,92 @@ public final class CacheService extends IntentService { | ||
451 | 461 | return -1L; |
452 | 462 | } |
453 | 463 | |
454 | - public static byte[] queryThumbnail(final Context context, final long thumbId, final long origId, final boolean isVideo, | |
464 | + public static final byte[] queryThumbnail(final Context context, final long thumbId, final long origId, final boolean isVideo, | |
455 | 465 | final long timestamp) { |
456 | 466 | final DiskCache thumbnailCache = (isVideo) ? LocalDataSource.sThumbnailCacheVideo : LocalDataSource.sThumbnailCache; |
457 | 467 | return queryThumbnail(context, thumbId, origId, isVideo, thumbnailCache, timestamp); |
458 | 468 | } |
459 | 469 | |
460 | - private static byte[] queryThumbnail(final Context context, final long thumbId, final long origId, final boolean isVideo, | |
461 | - final DiskCache thumbnailCache, final long timestamp) { | |
462 | - Thread thumbnailThread = THUMBNAIL_THREAD.getAndSet(null); | |
463 | - if (thumbnailThread != null) { | |
464 | - thumbnailThread.interrupt(); | |
465 | - } | |
466 | - byte[] bitmap = thumbnailCache.get(thumbId, timestamp); | |
467 | - if (bitmap == null) { | |
468 | - Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); | |
469 | - long time = SystemClock.uptimeMillis(); | |
470 | - bitmap = buildThumbnailForId(context, thumbnailCache, thumbId, origId, isVideo, DEFAULT_THUMBNAIL_WIDTH, | |
471 | - DEFAULT_THUMBNAIL_HEIGHT); | |
472 | - Log.i(TAG, "Built thumbnail and screennail for " + origId + " in " + (SystemClock.uptimeMillis() - time)); | |
473 | - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); | |
474 | - } | |
475 | - return bitmap; | |
476 | - } | |
477 | - | |
478 | - private static void buildThumbnails(final Context context) { | |
479 | - Log.i(TAG, "Preparing DiskCache for all thumbnails."); | |
470 | + public static final ImageList getImageList(final Context context) { | |
471 | + if (sList != null) | |
472 | + return sList; | |
473 | + ImageList list = new ImageList(); | |
480 | 474 | final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI; |
481 | 475 | final ContentResolver cr = context.getContentResolver(); |
482 | 476 | final Cursor cursorImages = cr.query(uriImages, THUMBNAIL_PROJECTION, null, null, null); |
483 | - final DiskCache thumbnailCache = LocalDataSource.sThumbnailCache; | |
484 | - | |
485 | 477 | if (cursorImages != null && cursorImages.moveToFirst()) { |
486 | 478 | final int size = cursorImages.getCount(); |
487 | 479 | final long[] ids = new long[size]; |
488 | 480 | final long[] thumbnailIds = new long[size]; |
489 | 481 | final long[] timestamp = new long[size]; |
482 | + final int[] orientation = new int[size]; | |
490 | 483 | int ctr = 0; |
491 | 484 | do { |
492 | 485 | if (Thread.interrupted()) { |
493 | - return; | |
494 | - } | |
495 | - synchronized (thumbnailCache) { | |
496 | - ids[ctr] = cursorImages.getLong(THUMBNAIL_ID_INDEX); | |
497 | - timestamp[ctr] = cursorImages.getLong(THUMBNAIL_DATE_MODIFIED_INDEX); | |
498 | - thumbnailIds[ctr] = Utils.Crc64Long(cursorImages.getString(THUMBNAIL_DATA_INDEX)); | |
499 | - ++ctr; | |
486 | + break; | |
500 | 487 | } |
488 | + ids[ctr] = cursorImages.getLong(THUMBNAIL_ID_INDEX); | |
489 | + timestamp[ctr] = cursorImages.getLong(THUMBNAIL_DATE_MODIFIED_INDEX); | |
490 | + thumbnailIds[ctr] = Utils.Crc64Long(cursorImages.getString(THUMBNAIL_DATA_INDEX)); | |
491 | + orientation[ctr] = cursorImages.getInt(THUMBNAIL_ORIENTATION_INDEX); | |
492 | + ++ctr; | |
501 | 493 | } while (cursorImages.moveToNext()); |
502 | 494 | cursorImages.close(); |
495 | + list.ids = ids; | |
496 | + list.thumbids = thumbnailIds; | |
497 | + list.timestamp = timestamp; | |
498 | + list.orientation = orientation; | |
499 | + } | |
500 | + if (sList == null) { | |
501 | + sList = list; | |
502 | + } | |
503 | + return list; | |
504 | + } | |
503 | 505 | |
504 | - for (int i = 0; i < size; ++i) { | |
505 | - if (Thread.interrupted()) { | |
506 | - return; | |
507 | - } | |
508 | - final long id = ids[i]; | |
509 | - final long timeModifiedInSec = timestamp[i]; | |
510 | - final long thumbnailId = thumbnailIds[i]; | |
511 | - if (!thumbnailCache.isDataAvailable(thumbnailId, timeModifiedInSec * 1000)) { | |
512 | - buildThumbnailForId(context, thumbnailCache, thumbnailId, id, false, DEFAULT_THUMBNAIL_WIDTH, | |
513 | - DEFAULT_THUMBNAIL_HEIGHT); | |
514 | - } | |
506 | + private static final byte[] queryThumbnail(final Context context, final long thumbId, final long origId, final boolean isVideo, | |
507 | + final DiskCache thumbnailCache, final long timestamp) { | |
508 | + if (!((Gallery) context).isPaused()) { | |
509 | + final Thread thumbnailThread = THUMBNAIL_THREAD.getAndSet(null); | |
510 | + if (thumbnailThread != null) { | |
511 | + thumbnailThread.interrupt(); | |
512 | + } | |
513 | + } | |
514 | + byte[] bitmap = thumbnailCache.get(thumbId, timestamp); | |
515 | + if (bitmap == null) { | |
516 | + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); | |
517 | + final long time = SystemClock.uptimeMillis(); | |
518 | + bitmap = buildThumbnailForId(context, thumbnailCache, thumbId, origId, isVideo, DEFAULT_THUMBNAIL_WIDTH, | |
519 | + DEFAULT_THUMBNAIL_HEIGHT); | |
520 | + Log.i(TAG, "Built thumbnail and screennail for " + origId + " in " + (SystemClock.uptimeMillis() - time)); | |
521 | + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); | |
522 | + } | |
523 | + return bitmap; | |
524 | + } | |
525 | + | |
526 | + private static final void buildThumbnails(final Context context) { | |
527 | + Log.i(TAG, "Preparing DiskCache for all thumbnails."); | |
528 | + ImageList list = getImageList(context); | |
529 | + final int size = (list.ids == null) ? 0 : list.ids.length; | |
530 | + final long[] ids = list.ids; | |
531 | + final long[] timestamp = list.timestamp; | |
532 | + final long[] thumbnailIds = list.thumbids; | |
533 | + final DiskCache thumbnailCache = LocalDataSource.sThumbnailCache; | |
534 | + for (int i = 0; i < size; ++i) { | |
535 | + if (Thread.interrupted()) { | |
536 | + return; | |
537 | + } | |
538 | + final long id = ids[i]; | |
539 | + final long timeModifiedInSec = timestamp[i]; | |
540 | + final long thumbnailId = thumbnailIds[i]; | |
541 | + if (!thumbnailCache.isDataAvailable(thumbnailId, timeModifiedInSec * 1000)) { | |
542 | + buildThumbnailForId(context, thumbnailCache, thumbnailId, id, false, DEFAULT_THUMBNAIL_WIDTH, | |
543 | + DEFAULT_THUMBNAIL_HEIGHT); | |
515 | 544 | } |
516 | 545 | } |
517 | 546 | Log.i(TAG, "DiskCache ready for all thumbnails."); |
518 | 547 | } |
519 | 548 | |
520 | - private static byte[] buildThumbnailForId(final Context context, final DiskCache thumbnailCache, final long thumbId, | |
549 | + private static final byte[] buildThumbnailForId(final Context context, final DiskCache thumbnailCache, final long thumbId, | |
521 | 550 | final long origId, final boolean isVideo, final int thumbnailWidth, final int thumbnailHeight) { |
522 | 551 | if (origId == Shared.INVALID) { |
523 | 552 | return null; |
@@ -537,7 +566,21 @@ public final class CacheService extends IntentService { | ||
537 | 566 | return null; |
538 | 567 | } |
539 | 568 | } else { |
540 | - // TODO: We need to generate video thumbnails if it is not eclair | |
569 | + Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); | |
570 | + new Thread() { | |
571 | + public void run() { | |
572 | + try { | |
573 | + Thread.sleep(5000); | |
574 | + } catch (InterruptedException e) { | |
575 | + ; | |
576 | + } | |
577 | + try { | |
578 | + MediaStore.Video.Thumbnails.cancelThumbnailRequest(context.getContentResolver(), origId); | |
579 | + } catch (Exception e) { | |
580 | + ; | |
581 | + } | |
582 | + } | |
583 | + }.start(); | |
541 | 584 | bitmap = MediaStore.Video.Thumbnails.getThumbnail(context.getContentResolver(), origId, |
542 | 585 | MediaStore.Video.Thumbnails.MICRO_KIND, null); |
543 | 586 | } |
@@ -552,7 +595,7 @@ public final class CacheService extends IntentService { | ||
552 | 595 | } |
553 | 596 | } |
554 | 597 | |
555 | - public static byte[] writeBitmapToCache(final DiskCache thumbnailCache, final long thumbId, final long origId, | |
598 | + public static final byte[] writeBitmapToCache(final DiskCache thumbnailCache, final long thumbId, final long origId, | |
556 | 599 | final Bitmap bitmap, final int thumbnailWidth, final int thumbnailHeight) { |
557 | 600 | final int width = bitmap.getWidth(); |
558 | 601 | final int height = bitmap.getHeight(); |
@@ -651,23 +694,23 @@ public final class CacheService extends IntentService { | ||
651 | 694 | if (intent.getBooleanExtra("checkthumbnails", false)) { |
652 | 695 | startNewThumbnailThread(this); |
653 | 696 | } else { |
654 | - Thread existingThread = THUMBNAIL_THREAD.getAndSet(null); | |
697 | + final Thread existingThread = THUMBNAIL_THREAD.getAndSet(null); | |
655 | 698 | if (existingThread != null) { |
656 | 699 | existingThread.interrupt(); |
657 | 700 | } |
658 | 701 | } |
659 | 702 | } |
660 | 703 | |
661 | - private static void putLocaleForAlbumCache(Locale locale) { | |
662 | - ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
663 | - DataOutputStream dos = new DataOutputStream(bos); | |
704 | + private static final void putLocaleForAlbumCache(final Locale locale) { | |
705 | + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); | |
706 | + final DataOutputStream dos = new DataOutputStream(bos); | |
664 | 707 | try { |
665 | 708 | Utils.writeUTF(dos, locale.getCountry()); |
666 | 709 | Utils.writeUTF(dos, locale.getLanguage()); |
667 | 710 | Utils.writeUTF(dos, locale.getVariant()); |
668 | 711 | dos.flush(); |
669 | 712 | bos.flush(); |
670 | - byte[] data = bos.toByteArray(); | |
713 | + final byte[] data = bos.toByteArray(); | |
671 | 714 | sAlbumCache.put(ALBUM_CACHE_LOCALE_INDEX, data); |
672 | 715 | sAlbumCache.flush(); |
673 | 716 | dos.close(); |
@@ -679,8 +722,8 @@ public final class CacheService extends IntentService { | ||
679 | 722 | } |
680 | 723 | } |
681 | 724 | |
682 | - private static Locale getLocaleForAlbumCache() { | |
683 | - byte[] data = sAlbumCache.get(ALBUM_CACHE_LOCALE_INDEX, 0); | |
725 | + private static final Locale getLocaleForAlbumCache() { | |
726 | + final byte[] data = sAlbumCache.get(ALBUM_CACHE_LOCALE_INDEX, 0); | |
684 | 727 | if (data != null && data.length > 0) { |
685 | 728 | ByteArrayInputStream bis = new ByteArrayInputStream(data); |
686 | 729 | DataInputStream dis = new DataInputStream(bis); |
@@ -694,7 +737,7 @@ public final class CacheService extends IntentService { | ||
694 | 737 | String variant = Utils.readUTF(dis); |
695 | 738 | if (variant == null) |
696 | 739 | variant = ""; |
697 | - Locale locale = new Locale(language, country, variant); | |
740 | + final Locale locale = new Locale(language, country, variant); | |
698 | 741 | dis.close(); |
699 | 742 | bis.close(); |
700 | 743 | return locale; |
@@ -707,9 +750,9 @@ public final class CacheService extends IntentService { | ||
707 | 750 | return null; |
708 | 751 | } |
709 | 752 | |
710 | - private static void restartThread(final AtomicReference<Thread> threadRef, String name, final Runnable action) { | |
753 | + private static final void restartThread(final AtomicReference<Thread> threadRef, final String name, final Runnable action) { | |
711 | 754 | // Create a new thread. |
712 | - Thread newThread = new Thread() { | |
755 | + final Thread newThread = new Thread() { | |
713 | 756 | public void run() { |
714 | 757 | try { |
715 | 758 | action.run(); |
@@ -722,13 +765,13 @@ public final class CacheService extends IntentService { | ||
722 | 765 | newThread.start(); |
723 | 766 | |
724 | 767 | // Interrupt any existing thread. |
725 | - Thread existingThread = threadRef.getAndSet(newThread); | |
768 | + final Thread existingThread = threadRef.getAndSet(newThread); | |
726 | 769 | if (existingThread != null) { |
727 | 770 | existingThread.interrupt(); |
728 | 771 | } |
729 | 772 | } |
730 | 773 | |
731 | - public static void startNewThumbnailThread(final Context context) { | |
774 | + public static final void startNewThumbnailThread(final Context context) { | |
732 | 775 | restartThread(THUMBNAIL_THREAD, "ThumbnailRefresh", new Runnable() { |
733 | 776 | public void run() { |
734 | 777 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); |
@@ -759,28 +802,28 @@ public final class CacheService extends IntentService { | ||
759 | 802 | }); |
760 | 803 | } |
761 | 804 | |
762 | - private static final byte[] concat(byte[] A, byte[] B) { | |
763 | - byte[] C = (byte[]) new byte[A.length + B.length]; | |
805 | + private static final byte[] concat(final byte[] A, final byte[] B) { | |
806 | + final byte[] C = (byte[]) new byte[A.length + B.length]; | |
764 | 807 | System.arraycopy(A, 0, C, 0, A.length); |
765 | 808 | System.arraycopy(B, 0, C, A.length, B.length); |
766 | 809 | return C; |
767 | 810 | } |
768 | 811 | |
769 | - private static final long[] toLongArray(byte[] data) { | |
770 | - ByteBuffer bBuffer = ByteBuffer.wrap(data); | |
771 | - LongBuffer lBuffer = bBuffer.asLongBuffer(); | |
772 | - int numLongs = lBuffer.capacity(); | |
773 | - long[] retVal = new long[numLongs]; | |
812 | + private static final long[] toLongArray(final byte[] data) { | |
813 | + final ByteBuffer bBuffer = ByteBuffer.wrap(data); | |
814 | + final LongBuffer lBuffer = bBuffer.asLongBuffer(); | |
815 | + final int numLongs = lBuffer.capacity(); | |
816 | + final long[] retVal = new long[numLongs]; | |
774 | 817 | for (int i = 0; i < numLongs; ++i) { |
775 | 818 | retVal[i] = lBuffer.get(i); |
776 | 819 | } |
777 | 820 | return retVal; |
778 | 821 | } |
779 | 822 | |
780 | - private static byte[] longToByteArray(long l) { | |
781 | - byte[] bArray = new byte[8]; | |
782 | - ByteBuffer bBuffer = ByteBuffer.wrap(bArray); | |
783 | - LongBuffer lBuffer = bBuffer.asLongBuffer(); | |
823 | + private static final byte[] longToByteArray(final long l) { | |
824 | + final byte[] bArray = new byte[8]; | |
825 | + final ByteBuffer bBuffer = ByteBuffer.wrap(bArray); | |
826 | + final LongBuffer lBuffer = bBuffer.asLongBuffer(); | |
784 | 827 | lBuffer.put(0, l); |
785 | 828 | return bArray; |
786 | 829 | } |
@@ -789,10 +832,12 @@ public final class CacheService extends IntentService { | ||
789 | 832 | // First we build the album cache. |
790 | 833 | // This is the meta-data about the albums / buckets on the SD card. |
791 | 834 | Log.i(TAG, "Refreshing cache."); |
835 | + int priority = Process.getThreadPriority(Process.myTid()); | |
836 | + Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE); | |
792 | 837 | sAlbumCache.deleteAll(); |
793 | 838 | putLocaleForAlbumCache(Locale.getDefault()); |
794 | - | |
795 | - ArrayList<MediaSet> sets = new ArrayList<MediaSet>(); | |
839 | + | |
840 | + final ArrayList<MediaSet> sets = new ArrayList<MediaSet>(); | |
796 | 841 | LongSparseArray<MediaSet> acceleratedSets = new LongSparseArray<MediaSet>(); |
797 | 842 | Log.i(TAG, "Building albums."); |
798 | 843 | final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build(); |
@@ -833,13 +878,13 @@ public final class CacheService extends IntentService { | ||
833 | 878 | sortCursor.close(); |
834 | 879 | } |
835 | 880 | |
836 | - byte[] data = new byte[] { 1 }; | |
837 | - sAlbumCache.put(ALBUM_CACHE_INCOMPLETE_INDEX, data); | |
881 | + sAlbumCache.put(ALBUM_CACHE_INCOMPLETE_INDEX, sDummyData); | |
838 | 882 | writeSetsToCache(sets); |
839 | 883 | Log.i(TAG, "Done building albums."); |
840 | 884 | // Now we must cache the items contained in every album / bucket. |
841 | 885 | populateMediaItemsForSets(context, sets, acceleratedSets, false); |
842 | 886 | sAlbumCache.delete(ALBUM_CACHE_INCOMPLETE_INDEX); |
887 | + Process.setThreadPriority(priority); | |
843 | 888 | if (QUEUE_DIRTY_ALL) { |
844 | 889 | QUEUE_DIRTY_ALL = false; |
845 | 890 | refresh(context); |
@@ -847,15 +892,15 @@ public final class CacheService extends IntentService { | ||
847 | 892 | } |
848 | 893 | |
849 | 894 | private final static void refreshDirtySets(final Context context) { |
850 | - byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0); | |
895 | + final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0); | |
851 | 896 | if (existingData != null && existingData.length > 0) { |
852 | - long[] ids = toLongArray(existingData); | |
853 | - int numIds = ids.length; | |
897 | + final long[] ids = toLongArray(existingData); | |
898 | + final int numIds = ids.length; | |
854 | 899 | if (numIds > 0) { |
855 | - ArrayList<MediaSet> sets = new ArrayList<MediaSet>(numIds); | |
856 | - LongSparseArray<MediaSet> acceleratedSets = new LongSparseArray<MediaSet>(numIds); | |
900 | + final ArrayList<MediaSet> sets = new ArrayList<MediaSet>(numIds); | |
901 | + final LongSparseArray<MediaSet> acceleratedSets = new LongSparseArray<MediaSet>(numIds); | |
857 | 902 | for (int i = 0; i < numIds; ++i) { |
858 | - MediaSet set = new MediaSet(); | |
903 | + final MediaSet set = new MediaSet(); | |
859 | 904 | set.mId = ids[i]; |
860 | 905 | sets.add(set); |
861 | 906 | acceleratedSets.put(set.mId, set); |
@@ -899,37 +944,38 @@ public final class CacheService extends IntentService { | ||
899 | 944 | |
900 | 945 | final Cursor cursorImages = cr.query(uriImages, PROJECTION_IMAGES, whereClause, null, DEFAULT_IMAGE_SORT_ORDER); |
901 | 946 | final Cursor cursorVideos = cr.query(uriVideos, PROJECTION_VIDEOS, whereClause, null, DEFAULT_VIDEO_SORT_ORDER); |
902 | - Cursor[] cursors = new Cursor[2]; | |
947 | + final Cursor[] cursors = new Cursor[2]; | |
903 | 948 | cursors[0] = cursorImages; |
904 | 949 | cursors[1] = cursorVideos; |
905 | 950 | final SortCursor sortCursor = new SortCursor(cursors, Images.ImageColumns.DATE_TAKEN, SortCursor.TYPE_NUMERIC, true); |
906 | 951 | if (Thread.interrupted()) { |
907 | 952 | return; |
908 | 953 | } |
909 | - | |
954 | + | |
910 | 955 | if (sortCursor != null && sortCursor.moveToFirst()) { |
911 | - int count = sortCursor.getCount(); | |
912 | - int numSets = sets.size(); | |
913 | - int approximateCountPerSet = count / numSets; | |
956 | + final int count = sortCursor.getCount(); | |
957 | + final int numSets = sets.size(); | |
958 | + final int approximateCountPerSet = count / numSets; | |
914 | 959 | for (int i = 0; i < numSets; ++i) { |
915 | - MediaSet set = sets.get(i); | |
960 | + final MediaSet set = sets.get(i); | |
961 | + set.getItems().clear(); | |
916 | 962 | set.setNumExpectedItems(approximateCountPerSet); |
917 | 963 | } |
918 | 964 | do { |
919 | 965 | if (Thread.interrupted()) { |
920 | 966 | return; |
921 | 967 | } |
922 | - MediaItem item = new MediaItem(); | |
923 | - boolean isVideo = (sortCursor.getCurrentCursorIndex() == 1); | |
968 | + final MediaItem item = new MediaItem(); | |
969 | + final boolean isVideo = (sortCursor.getCurrentCursorIndex() == 1); | |
924 | 970 | if (isVideo) { |
925 | - populateVideoItemFromCursor(item, cr, sortCursor, BASE_CONTENT_STRING_VIDEOS); | |
971 | + populateVideoItemFromCursor(item, cr, sortCursor, CacheService.BASE_CONTENT_STRING_VIDEOS); | |
926 | 972 | } else { |
927 | - populateMediaItemFromCursor(item, cr, sortCursor, BASE_CONTENT_STRING_IMAGES); | |
973 | + populateMediaItemFromCursor(item, cr, sortCursor, CacheService.BASE_CONTENT_STRING_IMAGES); | |
928 | 974 | } |
929 | - long setId = sortCursor.getLong(MEDIA_BUCKET_ID_INDEX); | |
930 | - MediaSet set = findSet(setId, acceleratedSets); | |
975 | + final long setId = sortCursor.getLong(MEDIA_BUCKET_ID_INDEX); | |
976 | + final MediaSet set = findSet(setId, acceleratedSets); | |
931 | 977 | if (set != null) { |
932 | - set.addItem(item); | |
978 | + set.getItems().add(item); | |
933 | 979 | } |
934 | 980 | } while (sortCursor.moveToNext()); |
935 | 981 | } |
@@ -985,8 +1031,8 @@ public final class CacheService extends IntentService { | ||
985 | 1031 | final ByteArrayOutputStream bos = new ByteArrayOutputStream(); |
986 | 1032 | final DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(bos, 256)); |
987 | 1033 | try { |
988 | - ArrayList<MediaItem> items = set.getItems(); | |
989 | - int numItems = set.getNumItems(); | |
1034 | + final ArrayList<MediaItem> items = set.getItems(); | |
1035 | + final int numItems = items.size(); | |
990 | 1036 | dos.writeInt(numItems); |
991 | 1037 | dos.writeLong(set.mMinTimestamp); |
992 | 1038 | dos.writeLong(set.mMaxTimestamp); |
@@ -1020,7 +1066,7 @@ public final class CacheService extends IntentService { | ||
1020 | 1066 | } |
1021 | 1067 | } |
1022 | 1068 | |
1023 | - private static final MediaSet findSet(long id, LongSparseArray<MediaSet> acceleratedTable) { | |
1069 | + private static final MediaSet findSet(final long id, final LongSparseArray<MediaSet> acceleratedTable) { | |
1024 | 1070 | // This is the accelerated lookup table for the MediaSet based on set id. |
1025 | 1071 | return acceleratedTable.get(id); |
1026 | 1072 | } |
@@ -0,0 +1,8 @@ | ||
1 | +package com.cooliris.cache; | |
2 | + | |
3 | +public class ImageList { | |
4 | + public long ids[]; | |
5 | + public long thumbids[]; | |
6 | + public long timestamp[]; | |
7 | + public int orientation[]; | |
8 | +} |
@@ -0,0 +1,17 @@ | ||
1 | +package com.cooliris.media; | |
2 | + | |
3 | +import com.cooliris.wallpaper.RandomDataSource; | |
4 | +import com.cooliris.wallpaper.Slideshow; | |
5 | + | |
6 | +import android.app.*; | |
7 | +import android.os.Bundle; | |
8 | + | |
9 | +public class ActiveWallpaper extends Activity { | |
10 | + @Override | |
11 | + public void onCreate(Bundle savedInstanceState) { | |
12 | + super.onCreate(savedInstanceState); | |
13 | + Slideshow slideshow = new Slideshow(this); | |
14 | + slideshow.setDataSource(new RandomDataSource()); | |
15 | + setContentView(slideshow); | |
16 | + } | |
17 | +} |
@@ -76,8 +76,8 @@ public final class AdaptiveBackgroundTexture extends Texture { | ||
76 | 76 | int sourceHeight = source.getHeight(); |
77 | 77 | int destWidth = mWidth; |
78 | 78 | int destHeight = mHeight; |
79 | - float fitX = (float) sourceWidth / destWidth; // CR: cast destWidth to float as well to be clean; no space after the cast. | |
80 | - float fitY = (float) sourceHeight / destHeight; | |
79 | + float fitX = (float)sourceWidth / (float)destWidth; | |
80 | + float fitY = (float)sourceHeight / (float)destHeight; | |
81 | 81 | float scale; |
82 | 82 | int cropX; |
83 | 83 | int cropY; |
@@ -86,10 +86,10 @@ public final class AdaptiveBackgroundTexture extends Texture { | ||
86 | 86 | if (fitX < fitY) { |
87 | 87 | // Full width, partial height. |
88 | 88 | cropWidth = sourceWidth; |
89 | - cropHeight = (int) (destHeight * fitX); // CR: no space after the cast. | |
89 | + cropHeight = (int)(destHeight * fitX); | |
90 | 90 | cropX = 0; |
91 | 91 | cropY = (sourceHeight - cropHeight) / 2; |
92 | - scale = 1f / fitX; // CR: i think 1.0f is clearer than 1f. | |
92 | + scale = 1.0f / fitX; | |
93 | 93 | } else { |
94 | 94 | // Full height, partial or full width. |
95 | 95 | cropWidth = (int) (destHeight * fitY); |
@@ -21,7 +21,7 @@ public final class ArrayUtils { | ||
21 | 21 | int firstListSize = firstList.size(); |
22 | 22 | for (int i = 0; i < firstListSize; ++i) { |
23 | 23 | MediaItem firstListItem = firstList.get(i); |
24 | - MediaItem hashItem = hash[firstListItem.hashCode() & mask]; | |
24 | + MediaItem hashItem = (hash != null) ? hash[firstListItem.hashCode() & mask] : null; | |
25 | 25 | if (hashItem != null && ((hashItem.mId != Shared.INVALID && hashItem.mId == firstListItem.mId) || contains(secondList, firstListItem))) { |
26 | 26 | intersectionList.add(firstListItem); |
27 | 27 | if (--maxSize == 0) { |
@@ -9,7 +9,7 @@ public class BackgroundLayer extends Layer { | ||
9 | 9 | private static final String TAG = "AdaptiveBackground"; |
10 | 10 | private final GridLayer mGridLayer; |
11 | 11 | private CrossFadingTexture mBackground; |
12 | - private static final int MAX_ADAPTIVES_TO_KEEP_IN_MEMORY = 8; | |
12 | + private static final int MAX_ADAPTIVES_TO_KEEP_IN_MEMORY = 16; | |
13 | 13 | |
14 | 14 | private final HashMap<Texture, AdaptiveBackgroundTexture> mCacheAdaptiveTexture = new HashMap<Texture, AdaptiveBackgroundTexture>(); |
15 | 15 | private int mCount; |
@@ -43,7 +43,7 @@ public class BackgroundLayer extends Layer { | ||
43 | 43 | int cameraPosition = (int) mGridLayer.getScrollPosition(); |
44 | 44 | final int backgroundSpacing = mBackgroundBlitWidth - mBackgroundOverlap; |
45 | 45 | cameraPosition = (int) ((cameraPosition / backgroundSpacing) * backgroundSpacing); |
46 | - final DisplayItem displayItem = mGridLayer.getDisplayItemForScrollPosition(cameraPosition); | |
46 | + final DisplayItem displayItem = mGridLayer.getRepresentativeDisplayItem(); | |
47 | 47 | if (displayItem != null) { |
48 | 48 | mBackground.setTexture(getAdaptive(view, displayItem)); |
49 | 49 | } |
@@ -76,13 +76,15 @@ public class BackgroundLayer extends Layer { | ||
76 | 76 | @Override |
77 | 77 | public void renderOpaque(RenderView view, GL11 gl) { |
78 | 78 | gl.glClear(GL11.GL_COLOR_BUFFER_BIT); |
79 | - mFallbackBackground = view.getResource(R.drawable.default_background, false); | |
80 | - view.loadTexture(mFallbackBackground); | |
79 | + if (mFallbackBackground == null) { | |
80 | + mFallbackBackground = view.getResource(R.drawable.default_background, false); | |
81 | + view.loadTexture(mFallbackBackground); | |
82 | + } | |
81 | 83 | } |
82 | 84 | |
83 | 85 | @Override |
84 | 86 | public void renderBlended(RenderView view, GL11 gl) { |
85 | - if (mBackground == null) | |
87 | + if (mBackground == null || mFallbackBackground == null) | |
86 | 88 | return; |
87 | 89 | gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); |
88 | 90 | gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_MODULATE); |
@@ -90,6 +92,11 @@ public class BackgroundLayer extends Layer { | ||
90 | 92 | boolean bind = anchorTexture.bind(view, gl); |
91 | 93 | if (!bind) { |
92 | 94 | view.bind(mFallbackBackground); |
95 | + } else { | |
96 | + Texture texture = anchorTexture.getTexture(); | |
97 | + if (texture.isLoaded()) { | |
98 | + mFallbackBackground = texture; | |
99 | + } | |
93 | 100 | } |
94 | 101 | |
95 | 102 | // We stitch this crossfading texture, and to cover all cases of overlap we need to perform 3 draws. |
@@ -122,6 +129,7 @@ public class BackgroundLayer extends Layer { | ||
122 | 129 | public void clear() { |
123 | 130 | clearCache(); |
124 | 131 | mBackground = null; |
132 | + mFallbackBackground = null; | |
125 | 133 | } |
126 | 134 | |
127 | 135 | public void clearCache() { |
@@ -45,10 +45,6 @@ public final class DiskCache { | ||
45 | 45 | shutdown(); |
46 | 46 | } |
47 | 47 | |
48 | - public void load() { | |
49 | - loadIndex(); | |
50 | - } | |
51 | - | |
52 | 48 | public byte[] get(long key, long timestamp) { |
53 | 49 | // Look up the record for the given key. |
54 | 50 | Record record = null; |
@@ -58,7 +54,6 @@ public final class DiskCache { | ||
58 | 54 | if (record != null) { |
59 | 55 | // Read the chunk from the file. |
60 | 56 | if (record.timestamp < timestamp && timestamp < System.currentTimeMillis()) { |
61 | - Log.i(TAG, "Old copy: CacheTimestamp " + record.timestamp + " new timestamp " + timestamp); | |
62 | 57 | return null; |
63 | 58 | } |
64 | 59 | try { |
@@ -85,9 +80,10 @@ public final class DiskCache { | ||
85 | 80 | return false; |
86 | 81 | } |
87 | 82 | if (record.timestamp < timestamp && timestamp < System.currentTimeMillis()) { |
88 | - Log.i(TAG, "Old copy: CacheTimestamp " + record.timestamp + " new timestamp " + timestamp); | |
89 | 83 | return false; |
90 | 84 | } |
85 | + if (record.size == 0) | |
86 | + return false; | |
91 | 87 | return true; |
92 | 88 | } |
93 | 89 |
@@ -127,4 +127,11 @@ public class FloatUtils { | ||
127 | 127 | } |
128 | 128 | } |
129 | 129 | } |
130 | + | |
131 | + public static final float max(float scaleX, float scaleY) { | |
132 | + if (scaleX > scaleY) | |
133 | + return scaleX; | |
134 | + else | |
135 | + return scaleY; | |
136 | + } | |
130 | 137 | } |
@@ -12,6 +12,7 @@ import android.graphics.Bitmap; | ||
12 | 12 | import android.net.Uri; |
13 | 13 | import android.os.Bundle; |
14 | 14 | import android.os.Handler; |
15 | +import android.provider.MediaStore.Images; | |
15 | 16 | import android.util.DisplayMetrics; |
16 | 17 | import android.util.Log; |
17 | 18 | import android.view.KeyEvent; |
@@ -19,14 +20,16 @@ import android.widget.Toast; | ||
19 | 20 | import android.media.MediaScannerConnection; |
20 | 21 | |
21 | 22 | import com.cooliris.cache.CacheService; |
23 | +import com.cooliris.wallpaper.RandomDataSource; | |
24 | +import com.cooliris.wallpaper.Slideshow; | |
22 | 25 | |
23 | 26 | public final class Gallery extends Activity { |
24 | 27 | public static final TimeZone CURRENT_TIME_ZONE = TimeZone.getDefault(); |
25 | - public static float PIXEL_DENSITY = 1.0f; | |
26 | - public static int DENSITY_DPI = DisplayMetrics.DENSITY_DEFAULT; | |
28 | + public static float PIXEL_DENSITY = 0.0f; | |
27 | 29 | public static boolean NEEDS_REFRESH = true; |
28 | - public static final int CROP_MSG_INTERNAL = 100; | |
30 | + | |
29 | 31 | private static final String TAG = "Gallery"; |
32 | + public static final int CROP_MSG_INTERNAL = 100; | |
30 | 33 | private static final int CROP_MSG = 10; |
31 | 34 | private RenderView mRenderView = null; |
32 | 35 | private GridLayer mGridLayer; |
@@ -34,16 +37,25 @@ public final class Gallery extends Activity { | ||
34 | 37 | private ReverseGeocoder mReverseGeocoder; |
35 | 38 | private boolean mPause; |
36 | 39 | private MediaScannerConnection mConnection; |
40 | + private static final boolean TEST_WALLPAPER = false; | |
37 | 41 | |
38 | 42 | @Override |
39 | 43 | public void onCreate(Bundle savedInstanceState) { |
40 | 44 | super.onCreate(savedInstanceState); |
45 | + if (TEST_WALLPAPER || (isViewIntent() && getIntent().getData().equals(Images.Media.EXTERNAL_CONTENT_URI))) { | |
46 | + Slideshow slideshow = new Slideshow(this); | |
47 | + slideshow.setDataSource(new RandomDataSource()); | |
48 | + setContentView(slideshow); | |
49 | + return; | |
50 | + } | |
41 | 51 | boolean isCacheReady = CacheService.isCacheReady(false); |
42 | 52 | CacheService.startCache(this, false); |
53 | + if (PIXEL_DENSITY == 0.0f) { | |
54 | + DisplayMetrics metrics = new DisplayMetrics(); | |
55 | + getWindowManager().getDefaultDisplay().getMetrics(metrics); | |
56 | + PIXEL_DENSITY = metrics.density; | |
57 | + } | |
43 | 58 | mReverseGeocoder = new ReverseGeocoder(this); |
44 | - DisplayMetrics metrics = new DisplayMetrics(); | |
45 | - getWindowManager().getDefaultDisplay().getMetrics(metrics); | |
46 | - PIXEL_DENSITY = metrics.density; | |
47 | 59 | mRenderView = new RenderView(this); |
48 | 60 | mGridLayer = new GridLayer(this, (int) (96.0f * PIXEL_DENSITY), (int) (72.0f * PIXEL_DENSITY), new GridLayoutInterface(4), |
49 | 61 | mRenderView); |
@@ -99,7 +111,9 @@ public final class Gallery extends Activity { | ||
99 | 111 | Uri uri = getIntent().getData(); |
100 | 112 | boolean slideshow = getIntent().getBooleanExtra("slideshow", false); |
101 | 113 | SingleDataSource localDataSource = new SingleDataSource(this, uri.toString(), slideshow); |
102 | - mGridLayer.setDataSource(localDataSource); | |
114 | + PicasaDataSource picasaDataSource = new PicasaDataSource(this); | |
115 | + ConcatenatedDataSource combinedDataSource = new ConcatenatedDataSource(localDataSource, picasaDataSource); | |
116 | + mGridLayer.setDataSource(combinedDataSource); | |
103 | 117 | mGridLayer.setViewIntent(true, Utils.getBucketNameFromUri(uri)); |
104 | 118 | if (SingleDataSource.isSingleImageMode(uri.toString())) { |
105 | 119 | mGridLayer.setSingleImage(false); |
@@ -133,7 +147,8 @@ public final class Gallery extends Activity { | ||
133 | 147 | @Override |
134 | 148 | public void onResume() { |
135 | 149 | super.onResume(); |
136 | - mRenderView.onResume(); | |
150 | + if (mRenderView != null) | |
151 | + mRenderView.onResume(); | |
137 | 152 | if (NEEDS_REFRESH) { |
138 | 153 | NEEDS_REFRESH = false; |
139 | 154 | CacheService.markDirtyImmediate(LocalDataSource.CAMERA_BUCKET_ID); |
@@ -146,7 +161,8 @@ public final class Gallery extends Activity { | ||
146 | 161 | @Override |
147 | 162 | public void onPause() { |
148 | 163 | super.onPause(); |
149 | - mRenderView.onPause(); | |
164 | + if (mRenderView != null) | |
165 | + mRenderView.onPause(); | |
150 | 166 | mPause = true; |
151 | 167 | } |
152 | 168 |
@@ -172,8 +188,8 @@ public final class Gallery extends Activity { | ||
172 | 188 | public void onDestroy() { |
173 | 189 | // Force GLThread to exit. |
174 | 190 | setContentView(R.layout.main); |
175 | - DataSource dataSource = mGridLayer.getDataSource(); | |
176 | 191 | if (mGridLayer != null) { |
192 | + DataSource dataSource = mGridLayer.getDataSource(); | |
177 | 193 | if (dataSource != null) { |
178 | 194 | dataSource.shutdown(); |
179 | 195 | } |
@@ -181,8 +197,10 @@ public final class Gallery extends Activity { | ||
181 | 197 | } |
182 | 198 | if (mReverseGeocoder != null) |
183 | 199 | mReverseGeocoder.shutdown(); |
184 | - mRenderView.shutdown(); | |
185 | - mRenderView = null; | |
200 | + if (mRenderView != null) { | |
201 | + mRenderView.shutdown(); | |
202 | + mRenderView = null; | |
203 | + } | |
186 | 204 | mGridLayer = null; |
187 | 205 | super.onDestroy(); |
188 | 206 | Log.i(TAG, "onDestroy"); |
@@ -194,13 +212,18 @@ public final class Gallery extends Activity { | ||
194 | 212 | if (mGridLayer != null) { |
195 | 213 | mGridLayer.markDirty(30); |
196 | 214 | } |
197 | - mRenderView.requestRender(); | |
215 | + if (mRenderView != null) | |
216 | + mRenderView.requestRender(); | |
198 | 217 | Log.i(TAG, "onConfigurationChanged"); |
199 | 218 | } |
200 | 219 | |
201 | 220 | @Override |
202 | 221 | public boolean onKeyDown(int keyCode, KeyEvent event) { |
203 | - return mRenderView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); | |
222 | + if (mRenderView != null) { | |
223 | + return mRenderView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); | |
224 | + } else { | |
225 | + return super.onKeyDown(keyCode, event); | |
226 | + } | |
204 | 227 | } |
205 | 228 | |
206 | 229 | private boolean isPickIntent() { |
@@ -293,7 +316,7 @@ public final class Gallery extends Activity { | ||
293 | 316 | public void onScanCompleted(String path, Uri uri) { |
294 | 317 | shutdown(uri.toString()); |
295 | 318 | } |
296 | - | |
319 | + | |
297 | 320 | public void shutdown(String uri) { |
298 | 321 | dialog.dismiss(); |
299 | 322 | performReturn(myExtras, uri.toString()); |
@@ -319,7 +342,7 @@ public final class Gallery extends Activity { | ||
319 | 342 | Bitmap bitmap = null; |
320 | 343 | try { |
321 | 344 | bitmap = UriTexture.createFromUri(this, contentUri, 1024, 1024, 0, null); |
322 | - } catch (IOException e) { | |
345 | + } catch (IOException e) { | |
323 | 346 | ; |
324 | 347 | } catch (URISyntaxException e) { |
325 | 348 | ; |
@@ -1,23 +1,25 @@ | ||
1 | 1 | package com.cooliris.media; |
2 | 2 | |
3 | 3 | public final class GridCameraManager { |
4 | - private GridCamera mCamera; | |
5 | - private ConcurrentPool<Vector3f> mPool; | |
6 | - | |
7 | - public GridCameraManager(GridCamera camera) { | |
8 | - mCamera = camera; | |
9 | - Vector3f[] vectorPool = new Vector3f[128]; | |
4 | + private final GridCamera mCamera; | |
5 | + private static final Pool<Vector3f> sPool; | |
6 | + static { | |
7 | + final Vector3f[] vectorPool = new Vector3f[128]; | |
10 | 8 | int length = vectorPool.length; |
11 | 9 | for (int i = 0; i < length; ++i) { |
12 | 10 | vectorPool[i] = new Vector3f(); |
13 | 11 | } |
14 | - mPool = new ConcurrentPool<Vector3f>(vectorPool); | |
12 | + sPool = new Pool<Vector3f>(vectorPool); | |
13 | + } | |
14 | + | |
15 | + public GridCameraManager(final GridCamera camera) { | |
16 | + mCamera = camera; | |
15 | 17 | } |
16 | 18 | |
17 | 19 | public void centerCameraForSlot(LayoutInterface layout, int slotIndex, float baseConvergence, Vector3f deltaAnchorPositionIn, |
18 | 20 | int selectedSlotIndex, float zoomValue, float imageTheta, int state) { |
19 | 21 | final GridCamera camera = mCamera; |
20 | - final ConcurrentPool<Vector3f> pool = mPool; | |
22 | + final Pool<Vector3f> pool = sPool; | |
21 | 23 | synchronized (camera) { |
22 | 24 | final boolean zoomin = (selectedSlotIndex != Shared.INVALID); |
23 | 25 | final int theta = (int) imageTheta; |
@@ -61,16 +63,16 @@ public final class GridCameraManager { | ||
61 | 63 | */ |
62 | 64 | public boolean constrainCameraForSlot(LayoutInterface layout, int slotIndex, Vector3f deltaAnchorPositionIn, |
63 | 65 | float currentFocusItemWidth, float currentFocusItemHeight) { |
64 | - GridCamera camera = mCamera; | |
65 | - ConcurrentPool<Vector3f> pool = mPool; | |
66 | + final GridCamera camera = mCamera; | |
67 | + final Pool<Vector3f> pool = sPool; | |
66 | 68 | boolean retVal = false; |
67 | 69 | synchronized (camera) { |
68 | - Vector3f position = pool.create(); | |
69 | - Vector3f deltaAnchorPosition = pool.create(); | |
70 | - Vector3f topLeft = pool.create(); | |
71 | - Vector3f bottomRight = pool.create(); | |
72 | - Vector3f imgTopLeft = pool.create(); | |
73 | - Vector3f imgBottomRight = pool.create(); | |
70 | + final Vector3f position = pool.create(); | |
71 | + final Vector3f deltaAnchorPosition = pool.create(); | |
72 | + final Vector3f topLeft = pool.create(); | |
73 | + final Vector3f bottomRight = pool.create(); | |
74 | + final Vector3f imgTopLeft = pool.create(); | |
75 | + final Vector3f imgBottomRight = pool.create(); | |
74 | 76 | |
75 | 77 | try { |
76 | 78 | if (slotIndex >= 0) { |
@@ -120,7 +122,7 @@ public final class GridCameraManager { | ||
120 | 122 | public void computeVisibleRange(MediaFeed feed, LayoutInterface layout, Vector3f deltaAnchorPositionIn, |
121 | 123 | IndexRange outVisibleRange, IndexRange outBufferedVisibleRange, IndexRange outCompleteRange, int state) { |
122 | 124 | GridCamera camera = mCamera; |
123 | - ConcurrentPool<Vector3f> pool = mPool; | |
125 | + Pool<Vector3f> pool = sPool; | |
124 | 126 | float offset = (camera.mLookAtX * camera.mScale); |
125 | 127 | int itemWidth = camera.mItemWidth; |
126 | 128 | float maxIncrement = camera.mWidth * 0.5f + itemWidth; |
@@ -223,8 +225,8 @@ public final class GridCameraManager { | ||
223 | 225 | |
224 | 226 | public static final float getFillScreenZoomValue(GridCamera camera, Pool<Vector3f> pool, float currentFocusItemWidth, |
225 | 227 | float currentFocusItemHeight) { |
226 | - Vector3f topLeft = pool.create(); | |
227 | - Vector3f bottomRight = pool.create(); | |
228 | + final Vector3f topLeft = pool.create(); | |
229 | + final Vector3f bottomRight = pool.create(); | |
228 | 230 | float potentialZoomValue = 1.0f; |
229 | 231 | try { |
230 | 232 | camera.convertToCameraSpace(0, 0, 0, topLeft); |
@@ -21,16 +21,16 @@ public final class GridDrawManager { | ||
21 | 21 | public static final int PASS_LOCATION_LABEL = 8; |
22 | 22 | public static final int PASS_MEDIASET_SOURCE_LABEL = 9; |
23 | 23 | |
24 | - private MediaItemTexture.Config mThumbnailConfig = new MediaItemTexture.Config(); | |
25 | - private DisplayItem[] mDisplayItems; | |
26 | - private DisplaySlot[] mDisplaySlots; | |
27 | - private DisplayList mDisplayList; | |
28 | - private GridCamera mCamera; | |
24 | + private static final MediaItemTexture.Config sThumbnailConfig = new MediaItemTexture.Config(); | |
25 | + private final DisplayItem[] mDisplayItems; | |
26 | + private final DisplaySlot[] mDisplaySlots; | |
27 | + private final DisplayList mDisplayList; | |
28 | + private final GridCamera mCamera; | |
29 | + private final GridDrawables mDrawables; | |
29 | 30 | private IndexRange mBufferedVisibleRange; |
30 | 31 | private IndexRange mVisibleRange; |
31 | 32 | private int mSelectedSlot; |
32 | 33 | private int mCurrentFocusSlot; |
33 | - private GridDrawables mDrawables; | |
34 | 34 | private DisplayItem[] mItemsDrawn; |
35 | 35 | private int mDrawnCounter; |
36 | 36 | private float mTargetFocusMixRatio = 0.0f; |
@@ -41,7 +41,7 @@ public final class GridDrawManager { | ||
41 | 41 | private boolean mCurrentFocusIsPressed; |
42 | 42 | private final Texture mNoItemsTexture; |
43 | 43 | |
44 | - private Comparator<DisplayItem> mDisplayItemComparator = new Comparator<DisplayItem>() { | |
44 | + private static final Comparator<DisplayItem> sDisplayItemComparator = new Comparator<DisplayItem>() { | |
45 | 45 | public int compare(DisplayItem a, DisplayItem b) { |
46 | 46 | if (a == null || b == null) { |
47 | 47 | return 0; |
@@ -59,8 +59,8 @@ public final class GridDrawManager { | ||
59 | 59 | |
60 | 60 | public GridDrawManager(Context context, GridCamera camera, GridDrawables drawables, DisplayList displayList, |
61 | 61 | DisplayItem[] displayItems, DisplaySlot[] displaySlots) { |
62 | - mThumbnailConfig.thumbnailWidth = 128; | |
63 | - mThumbnailConfig.thumbnailHeight = 96; | |
62 | + sThumbnailConfig.thumbnailWidth = 128; | |
63 | + sThumbnailConfig.thumbnailHeight = 96; | |
64 | 64 | mDisplayItems = displayItems; |
65 | 65 | mDisplaySlots = displaySlots; |
66 | 66 | mDisplayList = displayList; |
@@ -96,21 +96,22 @@ public final class GridDrawManager { | ||
96 | 96 | } |
97 | 97 | |
98 | 98 | public void drawThumbnails(RenderView view, GL11 gl, int state) { |
99 | - GridDrawables drawables = mDrawables; | |
100 | - DisplayList displayList = mDisplayList; | |
101 | - DisplayItem[] displayItems = mDisplayItems; | |
102 | - int firstBufferedVisibleSlot = mBufferedVisibleRange.begin; | |
103 | - int lastBufferedVisibleSlot = mBufferedVisibleRange.end; | |
104 | - int firstVisibleSlot = mVisibleRange.begin; | |
105 | - int lastVisibleSlot = mVisibleRange.end; | |
106 | - int selectedSlotIndex = mSelectedSlot; | |
107 | - int currentFocusSlot = mCurrentFocusSlot; | |
108 | - DisplayItem[] itemsDrawn = mItemsDrawn; | |
99 | + final GridDrawables drawables = mDrawables; | |
100 | + final DisplayList displayList = mDisplayList; | |
101 | + final DisplayItem[] displayItems = mDisplayItems; | |
102 | + final int firstBufferedVisibleSlot = mBufferedVisibleRange.begin; | |
103 | + final int lastBufferedVisibleSlot = mBufferedVisibleRange.end; | |
104 | + final int firstVisibleSlot = mVisibleRange.begin; | |
105 | + final int lastVisibleSlot = mVisibleRange.end; | |
106 | + final int selectedSlotIndex = mSelectedSlot; | |
107 | + final int currentFocusSlot = mCurrentFocusSlot; | |
108 | + final DisplayItem[] itemsDrawn = mItemsDrawn; | |
109 | 109 | itemsDrawn[0] = null; // No items drawn yet. |
110 | 110 | int drawnCounter = 0; |
111 | - GridQuad grid = drawables.mGrid; | |
111 | + final GridQuad grid = GridDrawables.sGrid; | |
112 | 112 | grid.bindArrays(gl); |
113 | 113 | int numTexturesQueued = 0; |
114 | + Context context = view.getContext(); | |
114 | 115 | for (int itrSlotIndex = firstBufferedVisibleSlot; itrSlotIndex <= lastBufferedVisibleSlot; ++itrSlotIndex) { |
115 | 116 | int index = itrSlotIndex; |
116 | 117 | boolean priority = !(index < firstVisibleSlot || index > lastVisibleSlot); |
@@ -120,7 +121,7 @@ public final class GridDrawManager { | ||
120 | 121 | if (displayItem == null) { |
121 | 122 | continue; |
122 | 123 | } else { |
123 | - Texture texture = displayItem.getThumbnailImage(view.getContext(), mThumbnailConfig); | |
124 | + Texture texture = displayItem.getThumbnailImage(context, sThumbnailConfig); | |
124 | 125 | if (texture != null && texture.isLoaded() == false) { |
125 | 126 | startSlotIndex = j; |
126 | 127 | break; |
@@ -136,13 +137,13 @@ public final class GridDrawManager { | ||
136 | 137 | if (selectedSlotIndex != Shared.INVALID && (index <= selectedSlotIndex - 2 || index >= selectedSlotIndex + 2)) { |
137 | 138 | displayItem.clearScreennailImage(); |
138 | 139 | } |
139 | - Texture texture = displayItem.getThumbnailImage(view.getContext(), mThumbnailConfig); | |
140 | + Texture texture = displayItem.getThumbnailImage(context, sThumbnailConfig); | |
140 | 141 | if (texture != null && !texture.isLoaded() && numTexturesQueued <= 6) { |
141 | - boolean isUncachedVideo = texture.isUncachedVideo(); | |
142 | - if (!isUncachedVideo) | |
142 | + boolean isCached = texture.isCached(); | |
143 | + if (isCached) | |
143 | 144 | view.prime(texture, priority); |
144 | 145 | view.bind(texture); |
145 | - if (priority && !isUncachedVideo) | |
146 | + if (priority && isCached && texture.mState != Texture.STATE_ERROR) | |
146 | 147 | ++numTexturesQueued; |
147 | 148 | } |
148 | 149 | } |
@@ -164,7 +165,7 @@ public final class GridDrawManager { | ||
164 | 165 | } else { |
165 | 166 | displayList.setHasFocus(displayItem, false, pushDown); |
166 | 167 | } |
167 | - Texture texture = displayItem.getThumbnailImage(view.getContext(), mThumbnailConfig); | |
168 | + Texture texture = displayItem.getThumbnailImage(view.getContext(), sThumbnailConfig); | |
168 | 169 | if (texture != null) { |
169 | 170 | if ((!displayItem.isAnimating() || !texture.isLoaded()) |
170 | 171 | && displayItem.getStackIndex() > GridLayer.MAX_ITEMS_PER_SLOT) { |
@@ -194,7 +195,6 @@ public final class GridDrawManager { | ||
194 | 195 | } |
195 | 196 | mDrawnCounter = drawnCounter; |
196 | 197 | grid.unbindArrays(gl); |
197 | - drawables.swapGridQuads(gl); | |
198 | 198 | } |
199 | 199 | |
200 | 200 | public float getFocusQuadWidth() { |
@@ -255,7 +255,7 @@ public final class GridDrawManager { | ||
255 | 255 | } |
256 | 256 | DisplayItem displayItem = displayItems[indexInDrawnArray]; |
257 | 257 | MediaItem item = displayItem.mItemRef; |
258 | - final Texture thumbnailTexture = displayItem.getThumbnailImage(view.getContext(), mThumbnailConfig); | |
258 | + final Texture thumbnailTexture = displayItem.getThumbnailImage(view.getContext(), sThumbnailConfig); | |
259 | 259 | Texture texture = displayItem.getScreennailImage(view.getContext()); |
260 | 260 | if (isCameraZAnimating && (texture == null || !texture.isLoaded())) { |
261 | 261 | texture = thumbnailTexture; |
@@ -296,11 +296,13 @@ public final class GridDrawManager { | ||
296 | 296 | mSelectedMixRatio.animateValue(1f, 0.75f, view.getFrameTime()); |
297 | 297 | } |
298 | 298 | } |
299 | - if (!slideshowMode && skipPrevious && i == -1) { | |
300 | - continue; | |
301 | - } | |
302 | - if (!skipPrevious && i == 1) { | |
303 | - continue; | |
299 | + if (mCamera.isAnimating()) { | |
300 | + if (!slideshowMode && skipPrevious && i == -1) { | |
301 | + continue; | |
302 | + } | |
303 | + if (!skipPrevious && i == 1) { | |
304 | + continue; | |
305 | + } | |
304 | 306 | } |
305 | 307 | int theta = (int) displayItem.getImageTheta(); |
306 | 308 | // If it is in slideshow mode, we draw the previous item in |
@@ -332,7 +334,7 @@ public final class GridDrawManager { | ||
332 | 334 | texture = thumbnailTexture; |
333 | 335 | view.setAlpha(alpha * (1.0f - selectedMixRatio)); |
334 | 336 | } |
335 | - GridQuad quad = drawables.mFullscreenGrid[vboIndex]; | |
337 | + GridQuad quad = GridDrawables.sFullscreenGrid[vboIndex]; | |
336 | 338 | float u = texture.getNormalizedWidth(); |
337 | 339 | float v = texture.getNormalizedHeight(); |
338 | 340 | float imageWidth = texture.getWidth(); |
@@ -373,9 +375,9 @@ public final class GridDrawManager { | ||
373 | 375 | view.setAlpha(alpha); |
374 | 376 | if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) { |
375 | 377 | // The play graphic overlay. |
376 | - drawables.mVideoGrid.bindArrays(gl); | |
378 | + GridDrawables.sVideoGrid.bindArrays(gl); | |
377 | 379 | drawDisplayItem(view, gl, displayItem, drawables.mTextureVideo, PASS_VIDEO_LABEL, null, 0); |
378 | - drawables.mVideoGrid.unbindArrays(gl); | |
380 | + GridDrawables.sVideoGrid.unbindArrays(gl); | |
379 | 381 | } |
380 | 382 | } |
381 | 383 | } |
@@ -395,7 +397,7 @@ public final class GridDrawManager { | ||
395 | 397 | // We draw the frames around the drawn items. |
396 | 398 | boolean currentFocusIsPressed = mCurrentFocusIsPressed; |
397 | 399 | if (state != GridLayer.STATE_FULL_SCREEN) { |
398 | - drawables.mFrame.bindArrays(gl); | |
400 | + GridDrawables.sFrame.bindArrays(gl); | |
399 | 401 | Texture texturePlaceHolder = (state == GridLayer.STATE_GRID_VIEW) ? drawables.mTextureGridFrame |
400 | 402 | : drawables.mTextureFrame; |
401 | 403 | for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { |
@@ -427,7 +429,7 @@ public final class GridDrawManager { | ||
427 | 429 | DisplayItem[] itemsDrawn = mItemsDrawn; |
428 | 430 | if (texture != null) { |
429 | 431 | if (drawnCounter > 0) { |
430 | - Arrays.sort(itemsDrawn, 0, drawnCounter, mDisplayItemComparator); | |
432 | + Arrays.sort(itemsDrawn, 0, drawnCounter, sDisplayItemComparator); | |
431 | 433 | float timeElapsedSinceGridView = gridMixRatio; |
432 | 434 | float timeElapsedSinceStackView = stackMixRatio; |
433 | 435 | for (int i = drawnCounter - 1; i >= 0; --i) { |
@@ -457,14 +459,14 @@ public final class GridDrawManager { | ||
457 | 459 | } |
458 | 460 | } |
459 | 461 | } |
460 | - drawables.mFrame.unbindArrays(gl); | |
462 | + GridDrawables.sFrame.unbindArrays(gl); | |
461 | 463 | gl.glDepthFunc(GL10.GL_ALWAYS); |
462 | 464 | if (state == GridLayer.STATE_MEDIA_SETS || state == GridLayer.STATE_TIMELINE) { |
463 | 465 | DisplaySlot[] displaySlots = mDisplaySlots; |
464 | - drawables.mTextGrid.bindArrays(gl); | |
466 | + GridDrawables.sTextGrid.bindArrays(gl); | |
465 | 467 | final float textOffsetY = 0.82f; |
466 | 468 | gl.glTranslatef(0.0f, -textOffsetY, 0.0f); |
467 | - HashMap<String, StringTexture> stringTextureTable = drawables.mStringTextureTable; | |
469 | + HashMap<String, StringTexture> stringTextureTable = GridDrawables.sStringTextureTable; | |
468 | 470 | ReverseGeocoder reverseGeocoder = ((Gallery) view.getContext()).getReverseGeocoder(); |
469 | 471 | |
470 | 472 | boolean itemsPresent = false; |
@@ -512,7 +514,7 @@ public final class GridDrawManager { | ||
512 | 514 | } |
513 | 515 | } |
514 | 516 | if (state == GridLayer.STATE_TIMELINE) { |
515 | - drawables.mLocationGrid.bindArrays(gl); | |
517 | + GridDrawables.sLocationGrid.bindArrays(gl); | |
516 | 518 | Texture locationTexture = drawables.mTextureLocation; |
517 | 519 | final float yLocationLabelOffset = 0.19f; |
518 | 520 | for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { |
@@ -536,9 +538,9 @@ public final class GridDrawManager { | ||
536 | 538 | } |
537 | 539 | } |
538 | 540 | |
539 | - drawables.mLocationGrid.unbindArrays(gl); | |
541 | + GridDrawables.sLocationGrid.unbindArrays(gl); | |
540 | 542 | } else if (state == GridLayer.STATE_MEDIA_SETS && stackMixRatio > 0.0f) { |
541 | - drawables.mSourceIconGrid.bindArrays(gl); | |
543 | + GridDrawables.sSourceIconGrid.bindArrays(gl); | |
542 | 544 | Texture transparentTexture = drawables.mTextureTransparent; |
543 | 545 | for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { |
544 | 546 | DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; |
@@ -556,18 +558,18 @@ public final class GridDrawManager { | ||
556 | 558 | } |
557 | 559 | } |
558 | 560 | } |
559 | - drawables.mSourceIconGrid.unbindArrays(gl); | |
561 | + GridDrawables.sSourceIconGrid.unbindArrays(gl); | |
560 | 562 | } |
561 | 563 | gl.glTranslatef(0.0f, yLocOffset, 0.0f); |
562 | 564 | gl.glTranslatef(0.0f, textOffsetY, 0.0f); |
563 | - drawables.mTextGrid.unbindArrays(gl); | |
565 | + GridDrawables.sTextGrid.unbindArrays(gl); | |
564 | 566 | } |
565 | 567 | if (hudMode == HudLayer.MODE_SELECT && state != GridLayer.STATE_FULL_SCREEN) { |
566 | 568 | Texture textureSelectedOn = drawables.mTextureCheckmarkOn; |
567 | 569 | Texture textureSelectedOff = drawables.mTextureCheckmarkOff; |
568 | 570 | view.prime(textureSelectedOn, true); |
569 | 571 | view.prime(textureSelectedOff, true); |
570 | - drawables.mSelectedGrid.bindArrays(gl); | |
572 | + GridDrawables.sSelectedGrid.bindArrays(gl); | |
571 | 573 | for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { |
572 | 574 | DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; |
573 | 575 | if (displayItem != null) { |
@@ -575,9 +577,9 @@ public final class GridDrawManager { | ||
575 | 577 | drawDisplayItem(view, gl, displayItem, textureToUse, PASS_SELECTION_LABEL, null, 0); |
576 | 578 | } |
577 | 579 | } |
578 | - drawables.mSelectedGrid.unbindArrays(gl); | |
580 | + GridDrawables.sSelectedGrid.unbindArrays(gl); | |
579 | 581 | } |
580 | - drawables.mVideoGrid.bindArrays(gl); | |
582 | + GridDrawables.sVideoGrid.bindArrays(gl); | |
581 | 583 | Texture videoTexture = drawables.mTextureVideo; |
582 | 584 | for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) { |
583 | 585 | DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT]; |
@@ -587,7 +589,7 @@ public final class GridDrawManager { | ||
587 | 589 | } |
588 | 590 | } |
589 | 591 | } |
590 | - drawables.mVideoGrid.unbindArrays(gl); | |
592 | + GridDrawables.sVideoGrid.unbindArrays(gl); | |
591 | 593 | gl.glDepthFunc(GL10.GL_LEQUAL); |
592 | 594 | } |
593 | 595 | } |
@@ -656,7 +658,9 @@ public final class GridDrawManager { | ||
656 | 658 | gl.glTranslatef(-translateXf, -translateYf, -translateZf); |
657 | 659 | float theta = (pass == PASS_FOCUS_CONTENT) ? displayItem.mAnimatedImageTheta + displayItem.mAnimatedTheta |
658 | 660 | : displayItem.mAnimatedTheta; |
659 | - gl.glRotatef(theta, 0.0f, 0.0f, 1.0f); | |
661 | + if (theta != 0.0f) { | |
662 | + gl.glRotatef(theta, 0.0f, 0.0f, 1.0f); | |
663 | + } | |
660 | 664 | float orientation = 0.0f; |
661 | 665 | if (pass == PASS_THUMBNAIL_CONTENT && displayItem.mAnimatedImageTheta != 0.0f) { |
662 | 666 | orientation = displayItem.mAnimatedImageTheta; |
@@ -666,7 +670,9 @@ public final class GridDrawManager { | ||
666 | 670 | } else { |
667 | 671 | GridQuad.draw(gl, orientation); |
668 | 672 | } |
669 | - gl.glRotatef(-theta, 0.0f, 0.0f, 1.0f); | |
673 | + if (theta != 0.0f) { | |
674 | + gl.glRotatef(-theta, 0.0f, 0.0f, 1.0f); | |
675 | + } | |
670 | 676 | gl.glTranslatef(translateXf, translateYf, translateZf); |
671 | 677 | if (usingMixedTextures) { |
672 | 678 | view.unbindMixed(); |
@@ -3,19 +3,17 @@ package com.cooliris.media; | ||
3 | 3 | import java.util.HashMap; |
4 | 4 | |
5 | 5 | import javax.microedition.khronos.opengles.GL11; |
6 | -import android.os.Process; | |
7 | 6 | |
8 | 7 | public final class GridDrawables { |
9 | 8 | // The display primitives. |
10 | - public GridQuad mGrid; | |
11 | - public final GridQuadFrame mFrame; | |
12 | - public final GridQuad mTextGrid; | |
13 | - public final GridQuad mSelectedGrid; | |
14 | - public final GridQuad mVideoGrid; | |
15 | - public final GridQuad mLocationGrid; | |
16 | - public final GridQuad mSourceIconGrid; | |
17 | - public final GridQuad[] mFullscreenGrid = new GridQuad[3]; | |
18 | - private GridQuad mGridNew; | |
9 | + public static GridQuad sGrid; | |
10 | + public static GridQuadFrame sFrame; | |
11 | + public static GridQuad sTextGrid; | |
12 | + public static GridQuad sSelectedGrid; | |
13 | + public static GridQuad sVideoGrid; | |
14 | + public static GridQuad sLocationGrid; | |
15 | + public static GridQuad sSourceIconGrid; | |
16 | + public static final GridQuad[] sFullscreenGrid = new GridQuad[3]; | |
19 | 17 | |
20 | 18 | // All the resource Textures. |
21 | 19 | private static final int TEXTURE_FRAME = R.drawable.stack_frame; |
@@ -31,7 +29,7 @@ public final class GridDrawables { | ||
31 | 29 | public static final int[] TEXTURE_SPINNER = new int[8]; |
32 | 30 | private static final int TEXTURE_TRANSPARENT = R.drawable.transparent; |
33 | 31 | private static final int TEXTURE_PLACEHOLDER = R.drawable.grid_placeholder; |
34 | - | |
32 | + | |
35 | 33 | public Texture mTextureFrame; |
36 | 34 | public Texture mTextureGridFrame; |
37 | 35 | public Texture mTextureFrameFocus; |
@@ -47,9 +45,9 @@ public final class GridDrawables { | ||
47 | 45 | public Texture mTexturePlaceholder; |
48 | 46 | |
49 | 47 | // The textures generated from strings. |
50 | - public final HashMap<String, StringTexture> mStringTextureTable = new HashMap<String, StringTexture>(128); | |
48 | + public static final HashMap<String, StringTexture> sStringTextureTable = new HashMap<String, StringTexture>(128); | |
51 | 49 | |
52 | - public GridDrawables(final int itemWidth, final int itemHeight) { | |
50 | + static { | |
53 | 51 | // We first populate the spinner textures. |
54 | 52 | final int[] textureSpinner = TEXTURE_SPINNER; |
55 | 53 | textureSpinner[0] = R.drawable.ic_spinner1; |
@@ -60,107 +58,88 @@ public final class GridDrawables { | ||
60 | 58 | textureSpinner[5] = R.drawable.ic_spinner6; |
61 | 59 | textureSpinner[6] = R.drawable.ic_spinner7; |
62 | 60 | textureSpinner[7] = R.drawable.ic_spinner8; |
63 | - | |
64 | - final float height = 1.0f; | |
65 | - final float width = (float) (height * itemWidth) / (float) itemHeight; | |
66 | - final float aspectRatio = (float) itemWidth / (float) itemHeight; | |
67 | - final float oneByAspect = 1.0f / aspectRatio; | |
68 | - | |
69 | - // We create the grid quad. | |
70 | - mGrid = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, false); | |
71 | - | |
72 | - // We create the quads used in fullscreen. | |
73 | - mFullscreenGrid[0] = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, false); | |
74 | - mFullscreenGrid[0].setDynamic(true); | |
75 | - mFullscreenGrid[1] = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, false); | |
76 | - mFullscreenGrid[1].setDynamic(true); | |
77 | - mFullscreenGrid[2] = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, false); | |
78 | - mFullscreenGrid[2].setDynamic(true); | |
79 | - | |
80 | - // We create supplementary quads for the checkmarks, video overlay and location button | |
81 | - float sizeOfSelectedIcon = 32 * Gallery.PIXEL_DENSITY; // In pixels. | |
82 | - sizeOfSelectedIcon /= itemHeight; | |
83 | - float sizeOfLocationIcon = 52 * Gallery.PIXEL_DENSITY; // In pixels. | |
84 | - sizeOfLocationIcon /= itemHeight; | |
85 | - float sizeOfSourceIcon = 76 * Gallery.PIXEL_DENSITY; // In pixels. | |
86 | - sizeOfSourceIcon /= itemHeight; | |
87 | - mSelectedGrid = GridQuad.createGridQuad(sizeOfSelectedIcon, sizeOfSelectedIcon, -0.5f, 0.25f, 1.0f, 1.0f, false); | |
88 | - mVideoGrid = GridQuad.createGridQuad(sizeOfSelectedIcon, sizeOfSelectedIcon, -0.08f, -0.09f, 1.0f, 1.0f, false); | |
89 | - mLocationGrid = GridQuad.createGridQuad(sizeOfLocationIcon, sizeOfLocationIcon, 0, 0, 1.0f, 1.0f, false); | |
90 | - mSourceIconGrid = GridQuad.createGridQuad(sizeOfSourceIcon, sizeOfSourceIcon, 0, 0, 1.0f, 1.0f, false); | |
91 | - | |
92 | - // We create the quad for the text label. | |
93 | - float seedTextWidth = (Gallery.PIXEL_DENSITY < 1.5f) ? 128.0f : 256.0f; | |
94 | - float textWidth = (seedTextWidth / (float) itemWidth) * width; | |
95 | - float textHeightPow2 = (Gallery.PIXEL_DENSITY < 1.5f) ? 32.0f : 64.0f; | |
96 | - float textHeight = (textHeightPow2 / (float) itemHeight) * height; | |
97 | - float textOffsetY = 0.0f; | |
98 | - mTextGrid = GridQuad.createGridQuad(textWidth, textHeight, 0, textOffsetY, 1.0f, 1.0f, false); | |
99 | - | |
100 | - // We finally create the frame around every grid item | |
101 | - mFrame = GridQuadFrame.createFrame(width, height, itemWidth, itemHeight); | |
102 | - | |
103 | - Thread creationThread = new Thread() { | |
104 | - public void run() { | |
105 | - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); | |
106 | - try { | |
107 | - Thread.sleep(2000); | |
108 | - } catch (InterruptedException e) { | |
109 | - ; | |
110 | - } | |
111 | - mGridNew = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, true); | |
112 | - } | |
113 | - }; | |
114 | - creationThread.start(); | |
115 | 61 | } |
116 | - | |
117 | - public void swapGridQuads(GL11 gl) { | |
118 | - if (mGridNew != null) { | |
119 | - mGrid.freeHardwareBuffers(gl); | |
120 | - mGrid = mGridNew; | |
121 | - mGrid.generateHardwareBuffers(gl); | |
122 | - mGridNew = null; | |
62 | + | |
63 | + public GridDrawables(final int itemWidth, final int itemHeight) { | |
64 | + if (sGrid == null) { | |
65 | + final float height = 1.0f; | |
66 | + final float width = (float) (height * itemWidth) / (float) itemHeight; | |
67 | + final float aspectRatio = (float) itemWidth / (float) itemHeight; | |
68 | + final float oneByAspect = 1.0f / aspectRatio; | |
69 | + | |
70 | + // We create the grid quad. | |
71 | + sGrid = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, true); | |
72 | + | |
73 | + // We create the quads used in fullscreen. | |
74 | + sFullscreenGrid[0] = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, false); | |
75 | + sFullscreenGrid[0].setDynamic(true); | |
76 | + sFullscreenGrid[1] = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, false); | |
77 | + sFullscreenGrid[1].setDynamic(true); | |
78 | + sFullscreenGrid[2] = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, false); | |
79 | + sFullscreenGrid[2].setDynamic(true); | |
80 | + | |
81 | + // We create supplementary quads for the checkmarks, video overlay and location button | |
82 | + float sizeOfSelectedIcon = 32 * Gallery.PIXEL_DENSITY; // In pixels. | |
83 | + sizeOfSelectedIcon /= itemHeight; | |
84 | + float sizeOfLocationIcon = 52 * Gallery.PIXEL_DENSITY; // In pixels. | |
85 | + sizeOfLocationIcon /= itemHeight; | |
86 | + float sizeOfSourceIcon = 76 * Gallery.PIXEL_DENSITY; // In pixels. | |
87 | + sizeOfSourceIcon /= itemHeight; | |
88 | + sSelectedGrid = GridQuad.createGridQuad(sizeOfSelectedIcon, sizeOfSelectedIcon, -0.5f, 0.25f, 1.0f, 1.0f, false); | |
89 | + sVideoGrid = GridQuad.createGridQuad(sizeOfSelectedIcon, sizeOfSelectedIcon, -0.08f, -0.09f, 1.0f, 1.0f, false); | |
90 | + sLocationGrid = GridQuad.createGridQuad(sizeOfLocationIcon, sizeOfLocationIcon, 0, 0, 1.0f, 1.0f, false); | |
91 | + sSourceIconGrid = GridQuad.createGridQuad(sizeOfSourceIcon, sizeOfSourceIcon, 0, 0, 1.0f, 1.0f, false); | |
92 | + | |
93 | + // We create the quad for the text label. | |
94 | + float seedTextWidth = (Gallery.PIXEL_DENSITY < 1.5f) ? 128.0f : 256.0f; | |
95 | + float textWidth = (seedTextWidth / (float) itemWidth) * width; | |
96 | + float textHeightPow2 = (Gallery.PIXEL_DENSITY < 1.5f) ? 32.0f : 64.0f; | |
97 | + float textHeight = (textHeightPow2 / (float) itemHeight) * height; | |
98 | + float textOffsetY = 0.0f; | |
99 | + sTextGrid = GridQuad.createGridQuad(textWidth, textHeight, 0, textOffsetY, 1.0f, 1.0f, false); | |
100 | + | |
101 | + // We finally create the frame around every grid item | |
102 | + sFrame = GridQuadFrame.createFrame(width, height, itemWidth, itemHeight); | |
123 | 103 | } |
124 | 104 | } |
125 | 105 | |
126 | 106 | public void onSurfaceCreated(RenderView view, GL11 gl) { |
127 | 107 | // The grid quad. |
128 | - mGrid.freeHardwareBuffers(gl); | |
129 | - mGrid.generateHardwareBuffers(gl); | |
108 | + sGrid.freeHardwareBuffers(gl); | |
109 | + sGrid.generateHardwareBuffers(gl); | |
130 | 110 | |
131 | 111 | // The fullscreen quads. |
132 | - mFullscreenGrid[0].freeHardwareBuffers(gl); | |
133 | - mFullscreenGrid[1].freeHardwareBuffers(gl); | |
134 | - mFullscreenGrid[2].freeHardwareBuffers(gl); | |
135 | - mFullscreenGrid[0].generateHardwareBuffers(gl); | |
136 | - mFullscreenGrid[1].generateHardwareBuffers(gl); | |
137 | - mFullscreenGrid[2].generateHardwareBuffers(gl); | |
112 | + sFullscreenGrid[0].freeHardwareBuffers(gl); | |
113 | + sFullscreenGrid[1].freeHardwareBuffers(gl); | |
114 | + sFullscreenGrid[2].freeHardwareBuffers(gl); | |
115 | + sFullscreenGrid[0].generateHardwareBuffers(gl); | |
116 | + sFullscreenGrid[1].generateHardwareBuffers(gl); | |
117 | + sFullscreenGrid[2].generateHardwareBuffers(gl); | |
138 | 118 | |
139 | 119 | // Supplementary quads. |
140 | - mSelectedGrid.freeHardwareBuffers(gl); | |
141 | - mVideoGrid.freeHardwareBuffers(gl); | |
142 | - mLocationGrid.freeHardwareBuffers(gl); | |
143 | - mSourceIconGrid.freeHardwareBuffers(gl); | |
144 | - mSelectedGrid.generateHardwareBuffers(gl); | |
145 | - mVideoGrid.generateHardwareBuffers(gl); | |
146 | - mLocationGrid.generateHardwareBuffers(gl); | |
147 | - mSourceIconGrid.generateHardwareBuffers(gl); | |
120 | + sSelectedGrid.freeHardwareBuffers(gl); | |
121 | + sVideoGrid.freeHardwareBuffers(gl); | |
122 | + sLocationGrid.freeHardwareBuffers(gl); | |
123 | + sSourceIconGrid.freeHardwareBuffers(gl); | |
124 | + sSelectedGrid.generateHardwareBuffers(gl); | |
125 | + sVideoGrid.generateHardwareBuffers(gl); | |
126 | + sLocationGrid.generateHardwareBuffers(gl); | |
127 | + sSourceIconGrid.generateHardwareBuffers(gl); | |
148 | 128 | |
149 | 129 | // Text quads. |
150 | - mTextGrid.freeHardwareBuffers(gl); | |
151 | - mTextGrid.generateHardwareBuffers(gl); | |
130 | + sTextGrid.freeHardwareBuffers(gl); | |
131 | + sTextGrid.generateHardwareBuffers(gl); | |
152 | 132 | |
153 | 133 | // Frame mesh. |
154 | - mFrame.freeHardwareBuffers(gl); | |
155 | - mFrame.generateHardwareBuffers(gl); | |
134 | + sFrame.freeHardwareBuffers(gl); | |
135 | + sFrame.generateHardwareBuffers(gl); | |
156 | 136 | |
157 | 137 | // Clear the string table. |
158 | - mStringTextureTable.clear(); | |
159 | - | |
138 | + sStringTextureTable.clear(); | |
139 | + | |
160 | 140 | // Regenerate all the textures. |
161 | 141 | mTextureFrame = view.getResource(TEXTURE_FRAME, false); |
162 | 142 | mTextureGridFrame = view.getResource(TEXTURE_GRID_FRAME, false); |
163 | - view.loadTexture(mTextureGridFrame); | |
164 | 143 | mTextureFrameFocus = view.getResource(TEXTURE_FRAME_FOCUS, false); |
165 | 144 | mTextureFramePressed = view.getResource(TEXTURE_FRAME_PRESSED, false); |
166 | 145 | mTextureLocation = view.getResource(TEXTURE_LOCATION, false); |
@@ -171,7 +150,11 @@ public final class GridDrawables { | ||
171 | 150 | mTexturePicasaSmall = view.getResource(TEXTURE_PICASA_SMALL, false); |
172 | 151 | mTextureTransparent = view.getResource(TEXTURE_TRANSPARENT, false); |
173 | 152 | mTexturePlaceholder = view.getResource(TEXTURE_PLACEHOLDER, false); |
174 | - | |
153 | + view.loadTexture(mTextureFrame); | |
154 | + view.loadTexture(mTextureGridFrame); | |
155 | + view.loadTexture(mTextureFrameFocus); | |
156 | + view.loadTexture(mTextureFramePressed); | |
157 | + | |
175 | 158 | mTextureSpinner[0] = view.getResource(R.drawable.ic_spinner1); |
176 | 159 | mTextureSpinner[1] = view.getResource(R.drawable.ic_spinner2); |
177 | 160 | mTextureSpinner[2] = view.getResource(R.drawable.ic_spinner3); |
@@ -438,14 +438,6 @@ public final class GridInputProcessor implements GestureDetector.OnGestureListen | ||
438 | 438 | } |
439 | 439 | } |
440 | 440 | |
441 | - public int getSelectedSlot() { | |
442 | - return mCurrentSelectedSlot; | |
443 | - } | |
444 | - | |
445 | - public int getFocusSlot() { | |
446 | - return mCurrentFocusSlot; | |
447 | - } | |
448 | - | |
449 | 441 | public void clearSelection() { |
450 | 442 | mCurrentSelectedSlot = Shared.INVALID; |
451 | 443 | } |
@@ -489,10 +481,10 @@ public final class GridInputProcessor implements GestureDetector.OnGestureListen | ||
489 | 481 | slotsToSkip = maxSlots; |
490 | 482 | if (slotsToSkip < -maxSlots) |
491 | 483 | slotsToSkip = -maxSlots; |
492 | - if (slotsToSkip <= 1) { | |
484 | + if (Math.abs(slotsToSkip) <= 1) { | |
493 | 485 | if (velocityX > 0) |
494 | 486 | slotsToSkip = -2; |
495 | - else | |
487 | + else if (velocityX < 0) | |
496 | 488 | slotsToSkip = 2; |
497 | 489 | } |
498 | 490 | int slotToGetTo = mLayer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER) + slotsToSkip; |
@@ -21,24 +21,42 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
21 | 21 | public static final int ANCHOR_RIGHT = 1; |
22 | 22 | public static final int ANCHOR_CENTER = 2; |
23 | 23 | |
24 | - public static final int MAX_ITEMS_PER_SLOT = 24; | |
24 | + public static final int MAX_ITEMS_PER_SLOT = 12; | |
25 | 25 | public static final int MAX_DISPLAYED_ITEMS_PER_SLOT = 4; |
26 | 26 | public static final int MAX_DISPLAY_SLOTS = 96; |
27 | 27 | public static final int MAX_ITEMS_DRAWABLE = MAX_ITEMS_PER_SLOT * MAX_DISPLAY_SLOTS; |
28 | 28 | |
29 | 29 | private static final float SLIDESHOW_TRANSITION_TIME = 3.5f; |
30 | 30 | |
31 | - private HudLayer mHud; | |
31 | + private static HudLayer sHud; | |
32 | 32 | private int mState; |
33 | - private IndexRange mBufferedVisibleRange; | |
34 | - private IndexRange mVisibleRange; | |
35 | - private IndexRange mPreviousDataRange; | |
36 | - private IndexRange mCompleteRange; | |
37 | - private Pool<Vector3f> mTempVec; | |
38 | - private final ArrayList<MediaItem> mTempList = new ArrayList<MediaItem>(); | |
39 | - private final MediaItem[] mTempHash = new MediaItem[64]; | |
40 | - private Vector3f mDeltaAnchorPositionUncommited; | |
41 | - private Vector3f mDeltaAnchorPosition; | |
33 | + private static final IndexRange sBufferedVisibleRange = new IndexRange(); | |
34 | + private static final IndexRange sVisibleRange = new IndexRange(); | |
35 | + private static final IndexRange sPreviousDataRange = new IndexRange(); | |
36 | + private static final IndexRange sCompleteRange = new IndexRange(); | |
37 | + | |
38 | + private static final Pool<Vector3f> sTempVec; | |
39 | + private static final Pool<Vector3f> sTempVecAlt; | |
40 | + static { | |
41 | + Vector3f[] vectorPool = new Vector3f[128]; | |
42 | + int length = vectorPool.length; | |
43 | + for (int i = 0; i < length; ++i) { | |
44 | + vectorPool[i] = new Vector3f(); | |
45 | + } | |
46 | + Vector3f[] vectorPoolRenderThread = new Vector3f[128]; | |
47 | + length = vectorPoolRenderThread.length; | |
48 | + for (int i = 0; i < length; ++i) { | |
49 | + vectorPoolRenderThread[i] = new Vector3f(); | |
50 | + } | |
51 | + sTempVec = new Pool<Vector3f>(vectorPool); | |
52 | + sTempVecAlt = new Pool<Vector3f>(vectorPoolRenderThread); | |
53 | + } | |
54 | + | |
55 | + private static final ArrayList<MediaItem> sTempList = new ArrayList<MediaItem>(); | |
56 | + private static final MediaItem[] sTempHash = new MediaItem[64]; | |
57 | + | |
58 | + private static final Vector3f sDeltaAnchorPositionUncommited = new Vector3f(); | |
59 | + private static Vector3f sDeltaAnchorPosition = new Vector3f(); | |
42 | 60 | |
43 | 61 | // The display primitives. |
44 | 62 | private GridDrawables mDrawables; |
@@ -54,16 +72,18 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
54 | 72 | private boolean mPerformingLayoutChange; |
55 | 73 | private boolean mFeedChanged; |
56 | 74 | |
57 | - private LayoutInterface mLayoutInterface; | |
58 | - private LayoutInterface mPrevLayoutInterface; | |
75 | + private final LayoutInterface mLayoutInterface; | |
76 | + private static final LayoutInterface sfullScreenLayoutInterface = new GridLayoutInterface(1); | |
77 | + | |
59 | 78 | private MediaFeed mMediaFeed; |
60 | 79 | private boolean mInAlbum = false; |
61 | 80 | private int mCurrentExpandedSlot; |
62 | 81 | |
63 | - private ArrayList<MediaItem> mVisibleItems; | |
64 | - private DisplayList mDisplayList = new DisplayList(); | |
65 | - private DisplayItem[] mDisplayItems = new DisplayItem[MAX_ITEMS_DRAWABLE]; | |
66 | - private DisplaySlot[] mDisplaySlots = new DisplaySlot[MAX_DISPLAY_SLOTS]; | |
82 | + private static final DisplayList sDisplayList = new DisplayList(); | |
83 | + private static final DisplayItem[] sDisplayItems = new DisplayItem[MAX_ITEMS_DRAWABLE]; | |
84 | + private static final DisplaySlot[] sDisplaySlots = new DisplaySlot[MAX_DISPLAY_SLOTS]; | |
85 | + private static ArrayList<MediaItem> sVisibleItems; | |
86 | + | |
67 | 87 | private float mTimeElapsedSinceTransition; |
68 | 88 | private BackgroundLayer mBackground; |
69 | 89 | private boolean mLocationFilter; |
@@ -75,9 +95,9 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
75 | 95 | private boolean mSlideshowMode; |
76 | 96 | private boolean mNoDeleteMode = false; |
77 | 97 | private float mTimeElapsedSinceView; |
78 | - private MediaBucketList mBucketList = new MediaBucketList(); | |
98 | + private static final MediaBucketList sBucketList = new MediaBucketList(); | |
79 | 99 | private float mTimeElapsedSinceStackViewReady; |
80 | - private Pool<Vector3f> mTempVecAlt; | |
100 | + | |
81 | 101 | private Context mContext; |
82 | 102 | private RenderView mView; |
83 | 103 | private boolean mPickIntent; |
@@ -91,19 +111,8 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
91 | 111 | mBackground = new BackgroundLayer(this); |
92 | 112 | mContext = context; |
93 | 113 | mView = view; |
94 | - Vector3f[] vectorPool = new Vector3f[128]; | |
95 | - int length = vectorPool.length; | |
96 | - for (int i = 0; i < length; ++i) { | |
97 | - vectorPool[i] = new Vector3f(); | |
98 | - } | |
99 | - Vector3f[] vectorPoolRenderThread = new Vector3f[128]; | |
100 | - length = vectorPoolRenderThread.length; | |
101 | - for (int i = 0; i < length; ++i) { | |
102 | - vectorPoolRenderThread[i] = new Vector3f(); | |
103 | - } | |
104 | - mTempVec = new Pool<Vector3f>(vectorPool); | |
105 | - mTempVecAlt = new Pool<Vector3f>(vectorPoolRenderThread); | |
106 | - DisplaySlot[] displaySlots = mDisplaySlots; | |
114 | + | |
115 | + DisplaySlot[] displaySlots = sDisplaySlots; | |
107 | 116 | for (int i = 0; i < MAX_DISPLAY_SLOTS; ++i) { |
108 | 117 | DisplaySlot slot = new DisplaySlot(); |
109 | 118 | displaySlots[i] = slot; |
@@ -111,39 +120,43 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
111 | 120 | mLayoutInterface = layoutInterface; |
112 | 121 | mCamera = new GridCamera(0, 0, itemWidth, itemHeight); |
113 | 122 | mDrawables = new GridDrawables(itemWidth, itemHeight); |
114 | - mBufferedVisibleRange = new IndexRange(); | |
115 | - mVisibleRange = new IndexRange(); | |
116 | - mCompleteRange = new IndexRange(); | |
117 | - mPreviousDataRange = new IndexRange(); | |
118 | - mPreviousDataRange.begin = Shared.INVALID; | |
119 | - mPreviousDataRange.end = Shared.INVALID; | |
120 | - mDeltaAnchorPosition = new Vector3f(); | |
121 | - mDeltaAnchorPositionUncommited = new Vector3f(); | |
122 | - mPrevLayoutInterface = new GridLayoutInterface(1); | |
123 | - mVisibleItems = new ArrayList<MediaItem>(); | |
124 | - mHud = new HudLayer(context); | |
125 | - mHud.setGridLayer(this); | |
126 | - mHud.getTimeBar().setListener(this); | |
127 | - mHud.getPathBar().pushLabel(R.drawable.icon_home_small, context.getResources().getString(R.string.app_name), | |
123 | + sBufferedVisibleRange.set(Shared.INVALID, Shared.INVALID); | |
124 | + sVisibleRange.set(Shared.INVALID, Shared.INVALID); | |
125 | + sCompleteRange.set(Shared.INVALID, Shared.INVALID); | |
126 | + sPreviousDataRange.set(Shared.INVALID, Shared.INVALID); | |
127 | + sDeltaAnchorPosition.set(0, 0, 0); | |
128 | + sDeltaAnchorPositionUncommited.set(0, 0, 0); | |
129 | + sBucketList.clear(); | |
130 | + | |
131 | + sVisibleItems = new ArrayList<MediaItem>(); | |
132 | + if (sHud == null) { | |
133 | + sHud = new HudLayer(context); | |
134 | + } | |
135 | + sHud.setContext(context); | |
136 | + sHud.setGridLayer(this); | |
137 | + sHud.getPathBar().clear(); | |
138 | + sHud.setGridLayer(this); | |
139 | + sHud.getTimeBar().setListener(this); | |
140 | + sHud.getPathBar().pushLabel(R.drawable.icon_home_small, context.getResources().getString(R.string.app_name), | |
128 | 141 | new Runnable() { |
129 | 142 | public void run() { |
130 | - if (mHud.getAlpha() == 1.0f) { | |
143 | + if (sHud.getAlpha() == 1.0f) { | |
131 | 144 | if (!mFeedAboutToChange) { |
132 | 145 | setState(STATE_MEDIA_SETS); |
133 | 146 | } |
134 | 147 | } else { |
135 | - mHud.setAlpha(1.0f); | |
148 | + sHud.setAlpha(1.0f); | |
136 | 149 | } |
137 | 150 | } |
138 | 151 | }); |
139 | 152 | mCameraManager = new GridCameraManager(mCamera); |
140 | - mDrawManager = new GridDrawManager(context, mCamera, mDrawables, mDisplayList, mDisplayItems, mDisplaySlots); | |
141 | - mInputProcessor = new GridInputProcessor(context, mCamera, this, mView, mTempVec, mDisplayItems); | |
153 | + mDrawManager = new GridDrawManager(context, mCamera, mDrawables, sDisplayList, sDisplayItems, sDisplaySlots); | |
154 | + mInputProcessor = new GridInputProcessor(context, mCamera, this, mView, sTempVec, sDisplayItems); | |
142 | 155 | setState(STATE_MEDIA_SETS); |
143 | 156 | } |
144 | 157 | |
145 | 158 | public HudLayer getHud() { |
146 | - return mHud; | |
159 | + return sHud; | |
147 | 160 | } |
148 | 161 | |
149 | 162 | public void shutdown() { |
@@ -153,16 +166,11 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
153 | 166 | mContext = null; |
154 | 167 | mInputProcessor = null; |
155 | 168 | mBackground = null; |
156 | - mBucketList = null; | |
169 | + sBucketList.clear(); | |
157 | 170 | mCameraManager = null; |
158 | 171 | mDrawManager = null; |
159 | - mHud.shutDown(); | |
160 | - mHud = null; | |
172 | + sHud.shutDown(); | |
161 | 173 | mView = null; |
162 | - | |
163 | - mDisplayItems = null; | |
164 | - mDisplayList = null; | |
165 | - mDisplaySlots = null; | |
166 | 174 | } |
167 | 175 | |
168 | 176 | public void stop() { |
@@ -178,13 +186,13 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
178 | 186 | mBackground.generate(view, lists); |
179 | 187 | lists.blendedList.add(this); |
180 | 188 | lists.hitTestList.add(this); |
181 | - mHud.generate(view, lists); | |
189 | + sHud.generate(view, lists); | |
182 | 190 | } |
183 | 191 | |
184 | 192 | @Override |
185 | 193 | protected void onSizeChanged() { |
186 | - mHud.setSize(mWidth, mHeight); | |
187 | - mHud.setAlpha(1.0f); | |
194 | + sHud.setSize(mWidth, mHeight); | |
195 | + sHud.setAlpha(1.0f); | |
188 | 196 | mBackground.setSize(mWidth, mHeight); |
189 | 197 | mTimeElapsedSinceTransition = 0.0f; |
190 | 198 | if (mView != null) { |
@@ -202,7 +210,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
202 | 210 | feedUnchanged = true; |
203 | 211 | } |
204 | 212 | GridLayoutInterface layoutInterface = (GridLayoutInterface) mLayoutInterface; |
205 | - GridLayoutInterface oldLayout = (GridLayoutInterface) mPrevLayoutInterface; | |
213 | + GridLayoutInterface oldLayout = (GridLayoutInterface) sfullScreenLayoutInterface; | |
206 | 214 | oldLayout.mNumRows = layoutInterface.mNumRows; |
207 | 215 | oldLayout.mSpacingX = layoutInterface.mSpacingX; |
208 | 216 | oldLayout.mSpacingY = layoutInterface.mSpacingY; |
@@ -233,24 +241,24 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
233 | 241 | MediaSet set = feed.getCurrentSet(); |
234 | 242 | int icon = mDrawables.getIconForSet(set, true); |
235 | 243 | if (set != null) { |
236 | - mHud.getPathBar().pushLabel(icon, set.mNoCountTitleString, new Runnable() { | |
244 | + sHud.getPathBar().pushLabel(icon, set.mNoCountTitleString, new Runnable() { | |
237 | 245 | public void run() { |
238 | 246 | if (mFeedAboutToChange) { |
239 | 247 | return; |
240 | 248 | } |
241 | - if (mHud.getAlpha() == 1.0f) { | |
249 | + if (sHud.getAlpha() == 1.0f) { | |
242 | 250 | disableLocationFiltering(); |
243 | 251 | mInputProcessor.clearSelection(); |
244 | 252 | setState(STATE_GRID_VIEW); |
245 | 253 | } else { |
246 | - mHud.setAlpha(1.0f); | |
254 | + sHud.setAlpha(1.0f); | |
247 | 255 | } |
248 | 256 | } |
249 | 257 | }); |
250 | 258 | } |
251 | 259 | } |
252 | 260 | if (mState == STATE_FULL_SCREEN) { |
253 | - mHud.getPathBar().popLabel(); | |
261 | + sHud.getPathBar().popLabel(); | |
254 | 262 | } |
255 | 263 | break; |
256 | 264 | case STATE_TIMELINE: |
@@ -269,12 +277,12 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
269 | 277 | layoutInterface.mSpacingX = (int) (40 * Gallery.PIXEL_DENSITY); |
270 | 278 | layoutInterface.mSpacingY = (int) (40 * Gallery.PIXEL_DENSITY); |
271 | 279 | if (mState != STATE_FULL_SCREEN) { |
272 | - mHud.getPathBar().pushLabel(R.drawable.ic_fs_details, "", new Runnable() { | |
280 | + sHud.getPathBar().pushLabel(R.drawable.ic_fs_details, "", new Runnable() { | |
273 | 281 | public void run() { |
274 | - if (mHud.getAlpha() == 1.0f) { | |
275 | - mHud.swapFullscreenLabel(); | |
282 | + if (sHud.getAlpha() == 1.0f) { | |
283 | + sHud.swapFullscreenLabel(); | |
276 | 284 | } |
277 | - mHud.setAlpha(1.0f); | |
285 | + sHud.setAlpha(1.0f); | |
278 | 286 | } |
279 | 287 | }); |
280 | 288 | } |
@@ -293,15 +301,15 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
293 | 301 | layoutInterface.mSpacingY = (int) (70 * Gallery.PIXEL_DENSITY * yStretch); |
294 | 302 | if (mInAlbum) { |
295 | 303 | if (mState == STATE_FULL_SCREEN) { |
296 | - mHud.getPathBar().popLabel(); | |
304 | + sHud.getPathBar().popLabel(); | |
297 | 305 | } |
298 | - mHud.getPathBar().popLabel(); | |
306 | + sHud.getPathBar().popLabel(); | |
299 | 307 | mInAlbum = false; |
300 | 308 | } |
301 | 309 | break; |
302 | 310 | } |
303 | 311 | mState = state; |
304 | - mHud.onGridStateChanged(); | |
312 | + sHud.onGridStateChanged(); | |
305 | 313 | if (performLayout && mFeedAboutToChange == false) { |
306 | 314 | onLayout(Shared.INVALID, Shared.INVALID, oldLayout); |
307 | 315 | } |
@@ -314,9 +322,9 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
314 | 322 | protected void enableLocationFiltering(String label) { |
315 | 323 | if (mLocationFilter == false) { |
316 | 324 | mLocationFilter = true; |
317 | - mHud.getPathBar().pushLabel(R.drawable.icon_location_small, label, new Runnable() { | |
325 | + sHud.getPathBar().pushLabel(R.drawable.icon_location_small, label, new Runnable() { | |
318 | 326 | public void run() { |
319 | - if (mHud.getAlpha() == 1.0f) { | |
327 | + if (sHud.getAlpha() == 1.0f) { | |
320 | 328 | if (mState == STATE_FULL_SCREEN) { |
321 | 329 | mInputProcessor.clearSelection(); |
322 | 330 | setState(STATE_GRID_VIEW); |
@@ -324,7 +332,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
324 | 332 | disableLocationFiltering(); |
325 | 333 | } |
326 | 334 | } else { |
327 | - mHud.setAlpha(1.0f); | |
335 | + sHud.setAlpha(1.0f); | |
328 | 336 | } |
329 | 337 | } |
330 | 338 | }); |
@@ -335,7 +343,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
335 | 343 | if (mLocationFilter) { |
336 | 344 | mLocationFilter = false; |
337 | 345 | mMediaFeed.removeFilter(); |
338 | - mHud.getPathBar().popLabel(); | |
346 | + sHud.getPathBar().popLabel(); | |
339 | 347 | } |
340 | 348 | } |
341 | 349 |
@@ -344,7 +352,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
344 | 352 | return false; |
345 | 353 | } |
346 | 354 | int state = mState; |
347 | - if (mInputProcessor.getSelectedSlot() == Shared.INVALID) { | |
355 | + if (mInputProcessor.getCurrentSelectedSlot() == Shared.INVALID) { | |
348 | 356 | if (mLocationFilter) { |
349 | 357 | disableLocationFiltering(); |
350 | 358 | setState(STATE_TIMELINE); |
@@ -376,7 +384,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
376 | 384 | } |
377 | 385 | mWakeLock = null; |
378 | 386 | } |
379 | - mHud.setAlpha(1.0f); | |
387 | + sHud.setAlpha(1.0f); | |
380 | 388 | } |
381 | 389 | |
382 | 390 | @Override |
@@ -394,7 +402,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
394 | 402 | MediaFeed feed = mMediaFeed; |
395 | 403 | if (feed != null) { |
396 | 404 | feed.shutdown(); |
397 | - mDisplayList.clear(); | |
405 | + sDisplayList.clear(); | |
398 | 406 | mBackground.clear(); |
399 | 407 | } |
400 | 408 | mMediaFeed = new MediaFeed(mContext, dataSource, this); |
@@ -402,33 +410,33 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
402 | 410 | } |
403 | 411 | |
404 | 412 | public IndexRange getVisibleRange() { |
405 | - return mVisibleRange; | |
413 | + return sVisibleRange; | |
406 | 414 | } |
407 | 415 | |
408 | 416 | public IndexRange getBufferedVisibleRange() { |
409 | - return mBufferedVisibleRange; | |
417 | + return sBufferedVisibleRange; | |
410 | 418 | } |
411 | 419 | |
412 | 420 | public IndexRange getCompleteRange() { |
413 | - return mCompleteRange; | |
421 | + return sCompleteRange; | |
414 | 422 | } |
415 | 423 | |
416 | 424 | private int hitTest(Vector3f worldPos, int itemWidth, int itemHeight) { |
417 | 425 | int retVal = Shared.INVALID; |
418 | 426 | int firstSlotIndex = 0; |
419 | 427 | int lastSlotIndex = 0; |
420 | - IndexRange rangeToUse = mVisibleRange; | |
428 | + IndexRange rangeToUse = sVisibleRange; | |
421 | 429 | synchronized (rangeToUse) { |
422 | 430 | firstSlotIndex = rangeToUse.begin; |
423 | 431 | lastSlotIndex = rangeToUse.end; |
424 | 432 | } |
425 | - Pool<Vector3f> pool = mTempVec; | |
433 | + Pool<Vector3f> pool = sTempVec; | |
426 | 434 | float itemWidthBy2 = itemWidth * 0.5f; |
427 | 435 | float itemHeightBy2 = itemHeight * 0.5f; |
428 | 436 | Vector3f position = pool.create(); |
429 | 437 | Vector3f deltaAnchorPosition = pool.create(); |
430 | 438 | try { |
431 | - deltaAnchorPosition.set(mDeltaAnchorPosition); | |
439 | + deltaAnchorPosition.set(sDeltaAnchorPosition); | |
432 | 440 | for (int i = firstSlotIndex; i <= lastSlotIndex; ++i) { |
433 | 441 | GridCameraManager.getSlotPositionForSlotIndex(i, mCamera, mLayoutInterface, deltaAnchorPosition, position); |
434 | 442 | if (FloatUtils.boundsContainsPoint(position.x - itemWidthBy2, position.x + itemWidthBy2, |
@@ -450,12 +458,12 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
450 | 458 | if (displayItem != null) { |
451 | 459 | imageTheta = displayItem.getImageTheta(); |
452 | 460 | } |
453 | - mCameraManager.centerCameraForSlot(mLayoutInterface, slotIndex, baseConvergence, mDeltaAnchorPositionUncommited, | |
461 | + mCameraManager.centerCameraForSlot(mLayoutInterface, slotIndex, baseConvergence, sDeltaAnchorPositionUncommited, | |
454 | 462 | mInputProcessor.getCurrentSelectedSlot(), mZoomValue, imageTheta, mState); |
455 | 463 | } |
456 | 464 | |
457 | 465 | boolean constrainCameraForSlot(int slotIndex) { |
458 | - return mCameraManager.constrainCameraForSlot(mLayoutInterface, slotIndex, mDeltaAnchorPosition, mCurrentFocusItemWidth, | |
466 | + return mCameraManager.constrainCameraForSlot(mLayoutInterface, slotIndex, sDeltaAnchorPosition, mCurrentFocusItemWidth, | |
459 | 467 | mCurrentFocusItemHeight); |
460 | 468 | } |
461 | 469 |
@@ -475,10 +483,17 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
475 | 483 | } else { |
476 | 484 | mTimeElapsedSinceTransition = 0; |
477 | 485 | } |
486 | + if (mMediaFeed != null && mMediaFeed.isSingleImageMode()) { | |
487 | + HudLayer hud = getHud(); | |
488 | + hud.getPathBar().setHidden(true); | |
489 | + hud.getMenuBar().setHidden(true); | |
490 | + if (hud.getMode() != HudLayer.MODE_NORMAL) | |
491 | + hud.setMode(HudLayer.MODE_NORMAL); | |
492 | + } | |
478 | 493 | if (view.elapsedLoadingExpensiveTextures() > 150 || (mMediaFeed != null && mMediaFeed.getWaitingForMediaScanner())) { |
479 | - mHud.getPathBar().setAnimatedIcons(GridDrawables.TEXTURE_SPINNER); | |
494 | + sHud.getPathBar().setAnimatedIcons(GridDrawables.TEXTURE_SPINNER); | |
480 | 495 | } else { |
481 | - mHud.getPathBar().setAnimatedIcons(null); | |
496 | + sHud.getPathBar().setAnimatedIcons(null); | |
482 | 497 | } |
483 | 498 | |
484 | 499 | // In that case, we need to commit the respective Display Items when the |
@@ -486,19 +501,19 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
486 | 501 | GridCamera camera = mCamera; |
487 | 502 | camera.update(timeElapsed); |
488 | 503 | DisplayItem anchorDisplayItem = getAnchorDisplayItem(ANCHOR_CENTER); |
489 | - if (anchorDisplayItem != null && !mHud.getTimeBar().isDragged()) { | |
490 | - mHud.getTimeBar().setItem(anchorDisplayItem.mItemRef); | |
504 | + if (anchorDisplayItem != null && !sHud.getTimeBar().isDragged()) { | |
505 | + sHud.getTimeBar().setItem(anchorDisplayItem.mItemRef); | |
491 | 506 | } |
492 | - mDisplayList.update(timeElapsed); | |
507 | + sDisplayList.update(timeElapsed); | |
493 | 508 | mInputProcessor.update(timeElapsed); |
494 | 509 | mSelectedAlpha = FloatUtils.animate(mSelectedAlpha, mTargetAlpha, timeElapsed * 0.5f); |
495 | 510 | if (mState == STATE_FULL_SCREEN) { |
496 | - mHud.autoHide(true); | |
511 | + sHud.autoHide(true); | |
497 | 512 | } else { |
498 | - mHud.autoHide(false); | |
499 | - mHud.setAlpha(1.0f); | |
513 | + sHud.autoHide(false); | |
514 | + sHud.setAlpha(1.0f); | |
500 | 515 | } |
501 | - GridQuad[] fullscreenQuads = mDrawables.mFullscreenGrid; | |
516 | + GridQuad[] fullscreenQuads = GridDrawables.sFullscreenGrid; | |
502 | 517 | int numFullScreenQuads = fullscreenQuads.length; |
503 | 518 | for (int i = 0; i < numFullScreenQuads; ++i) { |
504 | 519 | fullscreenQuads[i].update(timeElapsed); |
@@ -531,7 +546,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
531 | 546 | } catch (InterruptedException e) { |
532 | 547 | |
533 | 548 | } |
534 | - if (mDisplayList.getNumAnimatables() != 0 || mCamera.isAnimating() | |
549 | + if (sDisplayList.getNumAnimatables() != 0 || mCamera.isAnimating() | |
535 | 550 | || (mTimeElapsedSinceTransition > 0.0f && mTimeElapsedSinceTransition < 1.0f) || mSelectedAlpha != mTargetAlpha |
536 | 551 | // || (mAnimatedFov != mTargetFov) |
537 | 552 | || dirty) |
@@ -543,41 +558,40 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
543 | 558 | private void computeVisibleRange() { |
544 | 559 | if (mPerformingLayoutChange) |
545 | 560 | return; |
546 | - if (mDeltaAnchorPosition.equals(mDeltaAnchorPositionUncommited) == false) { | |
547 | - mDeltaAnchorPosition.set(mDeltaAnchorPositionUncommited); | |
561 | + if (sDeltaAnchorPosition.equals(sDeltaAnchorPositionUncommited) == false) { | |
562 | + sDeltaAnchorPosition.set(sDeltaAnchorPositionUncommited); | |
548 | 563 | } |
549 | - mCameraManager.computeVisibleRange(mMediaFeed, mLayoutInterface, mDeltaAnchorPosition, mVisibleRange, | |
550 | - mBufferedVisibleRange, mCompleteRange, mState); | |
564 | + mCameraManager.computeVisibleRange(mMediaFeed, mLayoutInterface, sDeltaAnchorPosition, sVisibleRange, | |
565 | + sBufferedVisibleRange, sCompleteRange, mState); | |
551 | 566 | } |
552 | 567 | |
553 | 568 | private void computeVisibleItems() { |
554 | 569 | if (mFeedAboutToChange == true || mPerformingLayoutChange == true) { |
555 | 570 | return; |
556 | 571 | } |
557 | - | |
558 | 572 | computeVisibleRange(); |
559 | - int deltaBegin = mBufferedVisibleRange.begin - mPreviousDataRange.begin; | |
560 | - int deltaEnd = mBufferedVisibleRange.end - mPreviousDataRange.end; | |
573 | + int deltaBegin = sBufferedVisibleRange.begin - sPreviousDataRange.begin; | |
574 | + int deltaEnd = sBufferedVisibleRange.end - sPreviousDataRange.end; | |
561 | 575 | if (deltaBegin != 0 || deltaEnd != 0) { |
562 | 576 | // The delta has changed, we have to compute the display items again. |
563 | 577 | // We find the intersection range, these slots have not changed at all. |
564 | - int firstVisibleSlotIndex = mBufferedVisibleRange.begin; | |
565 | - int lastVisibleSlotIndex = mBufferedVisibleRange.end; | |
566 | - mPreviousDataRange.begin = firstVisibleSlotIndex; | |
567 | - mPreviousDataRange.end = lastVisibleSlotIndex; | |
578 | + int firstVisibleSlotIndex = sBufferedVisibleRange.begin; | |
579 | + int lastVisibleSlotIndex = sBufferedVisibleRange.end; | |
580 | + sPreviousDataRange.begin = firstVisibleSlotIndex; | |
581 | + sPreviousDataRange.end = lastVisibleSlotIndex; | |
568 | 582 | |
569 | - Pool<Vector3f> pool = mTempVec; | |
583 | + Pool<Vector3f> pool = sTempVec; | |
570 | 584 | Vector3f position = pool.create(); |
571 | 585 | Vector3f deltaAnchorPosition = pool.create(); |
572 | 586 | try { |
573 | 587 | MediaFeed feed = mMediaFeed; |
574 | - DisplayList displayList = mDisplayList; | |
575 | - DisplayItem[] displayItems = mDisplayItems; | |
576 | - DisplaySlot[] displaySlots = mDisplaySlots; | |
588 | + DisplayList displayList = sDisplayList; | |
589 | + DisplayItem[] displayItems = sDisplayItems; | |
590 | + DisplaySlot[] displaySlots = sDisplaySlots; | |
577 | 591 | int numDisplayItems = displayItems.length; |
578 | 592 | int numDisplaySlots = displaySlots.length; |
579 | - ArrayList<MediaItem> visibleItems = mVisibleItems; | |
580 | - deltaAnchorPosition.set(mDeltaAnchorPosition); | |
593 | + ArrayList<MediaItem> visibleItems = sVisibleItems; | |
594 | + deltaAnchorPosition.set(sDeltaAnchorPosition); | |
581 | 595 | LayoutInterface layout = mLayoutInterface; |
582 | 596 | GridCamera camera = mCamera; |
583 | 597 | for (int i = firstVisibleSlotIndex; i <= lastVisibleSlotIndex; ++i) { |
@@ -588,12 +602,15 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
588 | 602 | if (set != null && indexIntoSlots >= 0 && indexIntoSlots < numDisplaySlots) { |
589 | 603 | ArrayList<MediaItem> items = set.getItems(); |
590 | 604 | displaySlots[indexIntoSlots].setMediaSet(set); |
591 | - ArrayList<MediaItem> bestItems = mTempList; | |
605 | + ArrayList<MediaItem> bestItems = sTempList; | |
592 | 606 | if (mTimeElapsedSinceTransition < 1.0f) { |
593 | - ArrayUtils.computeSortedIntersection(visibleItems, items, MAX_ITEMS_PER_SLOT, bestItems, mTempHash); | |
607 | + // We always show the same top thumbnails for a stack of albums | |
608 | + if (mState == STATE_MEDIA_SETS) | |
609 | + ArrayUtils.computeSortedIntersection(items, visibleItems, MAX_ITEMS_PER_SLOT, bestItems, sTempHash); | |
610 | + else | |
611 | + ArrayUtils.computeSortedIntersection(visibleItems, items, MAX_ITEMS_PER_SLOT, bestItems, sTempHash); | |
594 | 612 | } |
595 | - | |
596 | - // TODO: Could be problematic with dummy items in set. | |
613 | + | |
597 | 614 | int numItemsInSet = set.getNumItems(); |
598 | 615 | int numBestItems = bestItems.size(); |
599 | 616 | int originallyFoundItems = numBestItems; |
@@ -621,7 +638,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
621 | 638 | MediaItem item = bestItems.get(j); |
622 | 639 | if (item != null) { |
623 | 640 | DisplayItem displayItem = displayList.get(item); |
624 | - if (mState == STATE_FULL_SCREEN | |
641 | + if ((mState == STATE_FULL_SCREEN && i != mInputProcessor.getCurrentSelectedSlot()) | |
625 | 642 | || (mState == STATE_GRID_VIEW && (mTimeElapsedSinceTransition > 1.0f || j >= originallyFoundItems))) { |
626 | 643 | displayItem.set(position, j, false); |
627 | 644 | displayItem.commit(); |
@@ -642,22 +659,22 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
642 | 659 | mFeedChanged = false; |
643 | 660 | if (mInputProcessor != null && mState == STATE_FULL_SCREEN) { |
644 | 661 | int currentSelectedSlot = mInputProcessor.getCurrentSelectedSlot(); |
645 | - if (currentSelectedSlot > mCompleteRange.end) | |
646 | - currentSelectedSlot = mCompleteRange.end; | |
662 | + if (currentSelectedSlot > sCompleteRange.end) | |
663 | + currentSelectedSlot = sCompleteRange.end; | |
647 | 664 | mInputProcessor.setCurrentSelectedSlot(currentSelectedSlot); |
648 | 665 | } |
649 | 666 | if (mState == STATE_GRID_VIEW) { |
650 | 667 | MediaSet expandedSet = mMediaFeed.getExpandedMediaSet(); |
651 | 668 | if (expandedSet != null) { |
652 | - if (!mHud.getPathBar().getCurrentLabel().equals(expandedSet.mNoCountTitleString)) { | |
653 | - mHud.getPathBar().changeLabel(expandedSet.mNoCountTitleString); | |
669 | + if (!sHud.getPathBar().getCurrentLabel().equals(expandedSet.mNoCountTitleString)) { | |
670 | + sHud.getPathBar().changeLabel(expandedSet.mNoCountTitleString); | |
654 | 671 | } |
655 | 672 | } |
656 | 673 | } |
657 | 674 | if (mRequestFocusContentUri != null) { |
658 | 675 | // We have to find the item that has this contentUri |
659 | 676 | if (mState == STATE_FULL_SCREEN) { |
660 | - int numSlots = mCompleteRange.end; | |
677 | + int numSlots = sCompleteRange.end; | |
661 | 678 | for (int i = 0; i < numSlots; ++i) { |
662 | 679 | MediaSet set = feed.getSetForSlot(i); |
663 | 680 | ArrayList<MediaItem> items = set.getItems(); |
@@ -679,7 +696,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
679 | 696 | } |
680 | 697 | // We keep upto 400 thumbnails in memory. |
681 | 698 | int numThumbnailsToKeepInMemory = (mState == STATE_MEDIA_SETS || mState == STATE_TIMELINE) ? 100 : 400; |
682 | - int startMemoryRange = (mBufferedVisibleRange.begin / numThumbnailsToKeepInMemory) * numThumbnailsToKeepInMemory; | |
699 | + int startMemoryRange = (sBufferedVisibleRange.begin / numThumbnailsToKeepInMemory) * numThumbnailsToKeepInMemory; | |
683 | 700 | if (mStartMemoryRange != startMemoryRange) { |
684 | 701 | mStartMemoryRange = startMemoryRange; |
685 | 702 | clearUnusedThumbnails(); |
@@ -690,22 +707,23 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
690 | 707 | @Override |
691 | 708 | public void handleLowMemory() { |
692 | 709 | clearUnusedThumbnails(); |
693 | - mDrawables.mStringTextureTable.clear(); | |
710 | + GridDrawables.sStringTextureTable.clear(); | |
694 | 711 | mBackground.clearCache(); |
695 | 712 | } |
696 | 713 | |
697 | 714 | // This method can be potentially expensive |
698 | 715 | public void clearUnusedThumbnails() { |
699 | - mDisplayList.clearExcept(mDisplayItems); | |
716 | + sDisplayList.clearExcept(sDisplayItems); | |
700 | 717 | } |
701 | 718 | |
702 | 719 | @Override |
703 | 720 | public void onSurfaceCreated(RenderView view, GL11 gl) { |
704 | - mDisplayList.clear(); | |
705 | - mHud.clear(); | |
706 | - mHud.reset(); | |
707 | - mDrawables.mStringTextureTable.clear(); | |
721 | + sDisplayList.clear(); | |
722 | + sHud.clear(); | |
723 | + sHud.reset(); | |
724 | + GridDrawables.sStringTextureTable.clear(); | |
708 | 725 | mDrawables.onSurfaceCreated(view, gl); |
726 | + mBackground.clear(); | |
709 | 727 | } |
710 | 728 | |
711 | 729 | @Override |
@@ -720,7 +738,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
720 | 738 | GridCamera camera = mCamera; |
721 | 739 | int selectedSlotIndex = mInputProcessor.getCurrentSelectedSlot(); |
722 | 740 | computeVisibleItems(); |
723 | - | |
741 | + | |
724 | 742 | gl.glMatrixMode(GL11.GL_MODELVIEW); |
725 | 743 | gl.glLoadIdentity(); |
726 | 744 | GLU.gluLookAt(gl, -camera.mEyeX, -camera.mEyeY, -camera.mEyeZ, -camera.mLookAtX, -camera.mLookAtY, -camera.mLookAtZ, |
@@ -736,12 +754,14 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
736 | 754 | } else { |
737 | 755 | mTargetAlpha = 1.0f; |
738 | 756 | } |
739 | - mDrawManager.prepareDraw(mBufferedVisibleRange, mVisibleRange, selectedSlotIndex, mInputProcessor.getCurrentFocusSlot(), | |
757 | + mDrawManager.prepareDraw(sBufferedVisibleRange, sVisibleRange, selectedSlotIndex, mInputProcessor.getCurrentFocusSlot(), | |
740 | 758 | mInputProcessor.isFocusItemPressed()); |
741 | 759 | if (mSelectedAlpha != 0.0f) { |
742 | 760 | mDrawManager.drawThumbnails(view, gl, mState); |
743 | 761 | } |
744 | - gl.glDisable(GL11.GL_BLEND); | |
762 | + if (mSelectedAlpha != 1.0f) { | |
763 | + gl.glDisable(GL11.GL_BLEND); | |
764 | + } | |
745 | 765 | // We draw the selected slotIndex. |
746 | 766 | if (selectedSlotIndex != Shared.INVALID) { |
747 | 767 | mDrawManager.drawFocusItems(view, gl, mZoomValue, mSlideshowMode, mTimeElapsedSinceView); |
@@ -753,15 +773,15 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
753 | 773 | |
754 | 774 | public void renderBlended(RenderView view, GL11 gl) { |
755 | 775 | // We draw the placeholder for all visible slots. |
756 | - if (mHud != null && mDrawManager != null) { | |
757 | - mDrawManager.drawBlendedComponents(view, gl, mSelectedAlpha, mState, mHud.getMode(), mTimeElapsedSinceStackViewReady, | |
758 | - mTimeElapsedSinceGridViewReady, mBucketList, mMediaFeed.getWaitingForMediaScanner() || mFeedAboutToChange | |
776 | + if (sHud != null && mDrawManager != null) { | |
777 | + mDrawManager.drawBlendedComponents(view, gl, mSelectedAlpha, mState, sHud.getMode(), mTimeElapsedSinceStackViewReady, | |
778 | + mTimeElapsedSinceGridViewReady, sBucketList, mMediaFeed.getWaitingForMediaScanner() || mFeedAboutToChange | |
759 | 779 | || mMediaFeed.isLoading()); |
760 | 780 | } |
761 | 781 | } |
762 | 782 | |
763 | 783 | public synchronized void onLayout(int newAnchorSlotIndex, int currentAnchorSlotIndex, LayoutInterface oldLayout) { |
764 | - if (mPerformingLayoutChange || !mDeltaAnchorPosition.equals(mDeltaAnchorPositionUncommited)) { | |
784 | + if (mPerformingLayoutChange || !sDeltaAnchorPosition.equals(sDeltaAnchorPositionUncommited)) { | |
765 | 785 | return; |
766 | 786 | } |
767 | 787 |
@@ -769,7 +789,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
769 | 789 | mPerformingLayoutChange = true; |
770 | 790 | LayoutInterface layout = mLayoutInterface; |
771 | 791 | if (oldLayout == null) { |
772 | - oldLayout = mPrevLayoutInterface; | |
792 | + oldLayout = sfullScreenLayoutInterface; | |
773 | 793 | } |
774 | 794 | GridCamera camera = mCamera; |
775 | 795 | if (currentAnchorSlotIndex == Shared.INVALID) { |
@@ -787,7 +807,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
787 | 807 | } |
788 | 808 | int itemHeight = camera.mItemHeight; |
789 | 809 | int itemWidth = camera.mItemWidth; |
790 | - Pool<Vector3f> pool = mTempVec; | |
810 | + Pool<Vector3f> pool = sTempVec; | |
791 | 811 | Vector3f deltaAnchorPosition = pool.create(); |
792 | 812 | Vector3f currentSlotPosition = pool.create(); |
793 | 813 | try { |
@@ -795,12 +815,12 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
795 | 815 | if (currentAnchorSlotIndex != Shared.INVALID && newAnchorSlotIndex != Shared.INVALID) { |
796 | 816 | layout.getPositionForSlotIndex(newAnchorSlotIndex, itemWidth, itemHeight, deltaAnchorPosition); |
797 | 817 | oldLayout.getPositionForSlotIndex(currentAnchorSlotIndex, itemWidth, itemHeight, currentSlotPosition); |
798 | - currentSlotPosition.subtract(mDeltaAnchorPosition); | |
818 | + currentSlotPosition.subtract(sDeltaAnchorPosition); | |
799 | 819 | deltaAnchorPosition.subtract(currentSlotPosition); |
800 | 820 | deltaAnchorPosition.y = 0; |
801 | 821 | deltaAnchorPosition.z = 0; |
802 | 822 | } |
803 | - mDeltaAnchorPositionUncommited.set(deltaAnchorPosition); | |
823 | + sDeltaAnchorPositionUncommited.set(deltaAnchorPosition); | |
804 | 824 | } finally { |
805 | 825 | pool.delete(deltaAnchorPosition); |
806 | 826 | pool.delete(currentSlotPosition); |
@@ -817,8 +837,8 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
817 | 837 | } |
818 | 838 | |
819 | 839 | private void forceRecomputeVisibleRange() { |
820 | - mPreviousDataRange.begin = Shared.INVALID; | |
821 | - mPreviousDataRange.end = Shared.INVALID; | |
840 | + sPreviousDataRange.begin = Shared.INVALID; | |
841 | + sPreviousDataRange.end = Shared.INVALID; | |
822 | 842 | if (mView != null) { |
823 | 843 | mView.requestRender(); |
824 | 844 | } |
@@ -830,7 +850,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
830 | 850 | mFeedChanged = true; |
831 | 851 | forceRecomputeVisibleRange(); |
832 | 852 | if (mState == STATE_GRID_VIEW || mState == STATE_FULL_SCREEN) |
833 | - mHud.setFeed(feed, mState, needsLayout); | |
853 | + sHud.setFeed(feed, mState, needsLayout); | |
834 | 854 | return; |
835 | 855 | } |
836 | 856 |
@@ -838,21 +858,21 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
838 | 858 | Thread.yield(); |
839 | 859 | } |
840 | 860 | if (mState == STATE_GRID_VIEW) { |
841 | - if (mHud != null) { | |
861 | + if (sHud != null) { | |
842 | 862 | MediaSet set = feed.getCurrentSet(); |
843 | 863 | if (set != null && !mLocationFilter) |
844 | - mHud.getPathBar().changeLabel(set.mNoCountTitleString); | |
864 | + sHud.getPathBar().changeLabel(set.mNoCountTitleString); | |
845 | 865 | } |
846 | 866 | } |
847 | - DisplayItem[] displayItems = mDisplayItems; | |
848 | - int firstBufferedVisibleSlotIndex = mBufferedVisibleRange.begin; | |
849 | - int lastBufferedVisibleSlotIndex = mBufferedVisibleRange.end; | |
867 | + DisplayItem[] displayItems = sDisplayItems; | |
868 | + int firstBufferedVisibleSlotIndex = sBufferedVisibleRange.begin; | |
869 | + int lastBufferedVisibleSlotIndex = sBufferedVisibleRange.end; | |
850 | 870 | int currentlyVisibleSlotIndex = getAnchorSlotIndex(ANCHOR_CENTER); |
851 | 871 | if (mCurrentExpandedSlot != Shared.INVALID) { |
852 | 872 | currentlyVisibleSlotIndex = mCurrentExpandedSlot; |
853 | 873 | } |
854 | 874 | MediaItem anchorItem = null; |
855 | - ArrayList<MediaItem> visibleItems = mVisibleItems; | |
875 | + ArrayList<MediaItem> visibleItems = sVisibleItems; | |
856 | 876 | visibleItems.clear(); |
857 | 877 | visibleItems.ensureCapacity(lastBufferedVisibleSlotIndex - firstBufferedVisibleSlotIndex); |
858 | 878 | if (currentlyVisibleSlotIndex != Shared.INVALID && currentlyVisibleSlotIndex >= firstBufferedVisibleSlotIndex |
@@ -915,7 +935,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
915 | 935 | // We must create a new display store now since the data has changed. |
916 | 936 | if (newSlotIndex != Shared.INVALID) { |
917 | 937 | if (mState == STATE_MEDIA_SETS) { |
918 | - mDisplayList.clearExcept(displayItems); | |
938 | + sDisplayList.clearExcept(displayItems); | |
919 | 939 | } |
920 | 940 | onLayout(newSlotIndex, currentlyVisibleSlotIndex, null); |
921 | 941 | } else { |
@@ -925,25 +945,37 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
925 | 945 | mFeedAboutToChange = false; |
926 | 946 | mFeedChanged = true; |
927 | 947 | if (feed != null) { |
928 | - mHud.setFeed(feed, mState, needsLayout); | |
948 | + if (mState == STATE_GRID_VIEW || mState == STATE_FULL_SCREEN) | |
949 | + sHud.setFeed(feed, mState, needsLayout); | |
929 | 950 | } |
930 | 951 | if (mView != null) { |
931 | 952 | mView.requestRender(); |
932 | 953 | } |
933 | 954 | } |
955 | + | |
956 | + public DisplayItem getRepresentativeDisplayItem() { | |
957 | + int slotIndex = Shared.INVALID; | |
958 | + if (mInputProcessor != null) { | |
959 | + slotIndex = mInputProcessor.getCurrentFocusSlot(); | |
960 | + } | |
961 | + if (slotIndex == Shared.INVALID) { | |
962 | + slotIndex = getAnchorSlotIndex(ANCHOR_CENTER); | |
963 | + } | |
964 | + return sDisplayItems[(slotIndex - sBufferedVisibleRange.begin) * MAX_ITEMS_PER_SLOT]; | |
965 | + } | |
934 | 966 | |
935 | 967 | public DisplayItem getAnchorDisplayItem(int type) { |
936 | 968 | int slotIndex = getAnchorSlotIndex(type); |
937 | - return mDisplayItems[(slotIndex - mBufferedVisibleRange.begin) * MAX_ITEMS_PER_SLOT]; | |
969 | + return sDisplayItems[(slotIndex - sBufferedVisibleRange.begin) * MAX_ITEMS_PER_SLOT]; | |
938 | 970 | } |
939 | 971 | |
940 | 972 | public float getScrollPosition() { |
941 | - return (mCamera.mLookAtX * mCamera.mScale + mDeltaAnchorPosition.x); // in | |
973 | + return (mCamera.mLookAtX * mCamera.mScale + sDeltaAnchorPosition.x); // in | |
942 | 974 | // pixels |
943 | 975 | } |
944 | 976 | |
945 | 977 | public DisplayItem getDisplayItemForScrollPosition(float posX) { |
946 | - Pool<Vector3f> pool = mTempVecAlt; | |
978 | + Pool<Vector3f> pool = sTempVecAlt; | |
947 | 979 | MediaFeed feed = mMediaFeed; |
948 | 980 | int itemWidth = mCamera.mItemWidth; |
949 | 981 | int itemHeight = mCamera.mItemHeight; |
@@ -978,7 +1010,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
978 | 1010 | if (set != null) { |
979 | 1011 | ArrayList<MediaItem> items = set.getItems(); |
980 | 1012 | if (items != null && set.getNumItems() > 0) { |
981 | - return (mDisplayList.get(items.get(0))); | |
1013 | + return (sDisplayList.get(items.get(0))); | |
982 | 1014 | } |
983 | 1015 | } |
984 | 1016 | return null; |
@@ -989,22 +1021,22 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
989 | 1021 | int retVal = 0; |
990 | 1022 | switch (anchorType) { |
991 | 1023 | case ANCHOR_LEFT: |
992 | - retVal = mVisibleRange.begin; | |
1024 | + retVal = sVisibleRange.begin; | |
993 | 1025 | break; |
994 | 1026 | case ANCHOR_RIGHT: |
995 | - retVal = mVisibleRange.end; | |
1027 | + retVal = sVisibleRange.end; | |
996 | 1028 | break; |
997 | 1029 | case ANCHOR_CENTER: |
998 | - retVal = (mVisibleRange.begin + mVisibleRange.end) / 2; | |
1030 | + retVal = (sVisibleRange.begin + sVisibleRange.end) / 2; | |
999 | 1031 | break; |
1000 | 1032 | } |
1001 | 1033 | return retVal; |
1002 | 1034 | } |
1003 | 1035 | |
1004 | 1036 | DisplayItem getDisplayItemForSlotId(int slotId) { |
1005 | - int index = slotId - mBufferedVisibleRange.begin; | |
1006 | - if (index >= 0 && slotId <= mBufferedVisibleRange.end) { | |
1007 | - return mDisplayItems[index * MAX_ITEMS_PER_SLOT]; | |
1037 | + int index = slotId - sBufferedVisibleRange.begin; | |
1038 | + if (index >= 0 && slotId <= sBufferedVisibleRange.end) { | |
1039 | + return sDisplayItems[index * MAX_ITEMS_PER_SLOT]; | |
1008 | 1040 | } |
1009 | 1041 | return null; |
1010 | 1042 | } |
@@ -1014,20 +1046,20 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1014 | 1046 | boolean retVal = changeFocusToSlot(currentSelectedSlot + 1, convergence); |
1015 | 1047 | if (mInputProcessor.getCurrentSelectedSlot() == currentSelectedSlot) { |
1016 | 1048 | endSlideshow(); |
1017 | - mHud.setAlpha(1.0f); | |
1049 | + sHud.setAlpha(1.0f); | |
1018 | 1050 | } |
1019 | 1051 | return retVal; |
1020 | 1052 | } |
1021 | 1053 | |
1022 | 1054 | boolean changeFocusToSlot(int slotId, float convergence) { |
1023 | 1055 | mZoomValue = 1.0f; |
1024 | - int index = slotId - mBufferedVisibleRange.begin; | |
1025 | - if (index >= 0 && slotId <= mBufferedVisibleRange.end) { | |
1026 | - DisplayItem displayItem = mDisplayItems[index * MAX_ITEMS_PER_SLOT]; | |
1056 | + int index = slotId - sBufferedVisibleRange.begin; | |
1057 | + if (index >= 0 && slotId <= sBufferedVisibleRange.end) { | |
1058 | + DisplayItem displayItem = sDisplayItems[index * MAX_ITEMS_PER_SLOT]; | |
1027 | 1059 | if (displayItem != null) { |
1028 | 1060 | MediaItem item = displayItem.mItemRef; |
1029 | - mHud.fullscreenSelectionChanged(item, slotId + 1, mCompleteRange.end + 1); | |
1030 | - if (slotId != Shared.INVALID && slotId <= mCompleteRange.end) { | |
1061 | + sHud.fullscreenSelectionChanged(item, slotId + 1, sCompleteRange.end + 1); | |
1062 | + if (slotId != Shared.INVALID && slotId <= sCompleteRange.end) { | |
1031 | 1063 | mInputProcessor.setCurrentFocusSlot(slotId); |
1032 | 1064 | centerCameraForSlot(slotId, convergence); |
1033 | 1065 | return true; |
@@ -1045,12 +1077,12 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1045 | 1077 | } |
1046 | 1078 | |
1047 | 1079 | public ArrayList<MediaBucket> getSelectedBuckets() { |
1048 | - return mBucketList.get(); | |
1080 | + return sBucketList.get(); | |
1049 | 1081 | } |
1050 | 1082 | |
1051 | 1083 | public void selectAll() { |
1052 | 1084 | if (mState != STATE_FULL_SCREEN) { |
1053 | - int numSlots = mCompleteRange.end + 1; | |
1085 | + int numSlots = sCompleteRange.end + 1; | |
1054 | 1086 | for (int i = 0; i < numSlots; ++i) { |
1055 | 1087 | addSlotToSelectedItems(i, false, false); |
1056 | 1088 | } |
@@ -1061,17 +1093,17 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1061 | 1093 | } |
1062 | 1094 | |
1063 | 1095 | public void deselectOrCancelSelectMode() { |
1064 | - if (mBucketList.size() == 0) { | |
1065 | - mHud.cancelSelection(); | |
1096 | + if (sBucketList.size() == 0) { | |
1097 | + sHud.cancelSelection(); | |
1066 | 1098 | } else { |
1067 | - mBucketList.clear(); | |
1099 | + sBucketList.clear(); | |
1068 | 1100 | updateCountOfSelectedItems(); |
1069 | 1101 | } |
1070 | 1102 | } |
1071 | 1103 | |
1072 | 1104 | public void deselectAll() { |
1073 | - mHud.cancelSelection(); | |
1074 | - mBucketList.clear(); | |
1105 | + sHud.cancelSelection(); | |
1106 | + sBucketList.clear(); | |
1075 | 1107 | updateCountOfSelectedItems(); |
1076 | 1108 | } |
1077 | 1109 |
@@ -1081,7 +1113,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1081 | 1113 | deselectAll(); |
1082 | 1114 | |
1083 | 1115 | // If the current set is now empty, return to the parent set. |
1084 | - if (mCompleteRange.isEmpty()) { | |
1116 | + if (sCompleteRange.isEmpty()) { | |
1085 | 1117 | goBack(); // TODO(venkat): This does not work most of the time, can you take a look? |
1086 | 1118 | } |
1087 | 1119 | } |
@@ -1089,17 +1121,17 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1089 | 1121 | void addSlotToSelectedItems(int slotId, boolean removeIfAlreadyAdded, boolean updateCount) { |
1090 | 1122 | if (mFeedAboutToChange == false) { |
1091 | 1123 | MediaFeed feed = mMediaFeed; |
1092 | - mBucketList.add(slotId, feed, removeIfAlreadyAdded); | |
1124 | + sBucketList.add(slotId, feed, removeIfAlreadyAdded); | |
1093 | 1125 | if (updateCount) { |
1094 | 1126 | updateCountOfSelectedItems(); |
1095 | - if (mBucketList.size() == 0) | |
1127 | + if (sBucketList.size() == 0) | |
1096 | 1128 | deselectAll(); |
1097 | 1129 | } |
1098 | 1130 | } |
1099 | 1131 | } |
1100 | 1132 | |
1101 | 1133 | private void updateCountOfSelectedItems() { |
1102 | - mHud.updateNumItemsSelected(mBucketList.size()); | |
1134 | + sHud.updateNumItemsSelected(sBucketList.size()); | |
1103 | 1135 | } |
1104 | 1136 | |
1105 | 1137 | public int getMetadataSlotIndexForScreenPosition(int posX, int posY) { |
@@ -1112,7 +1144,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1112 | 1144 | } |
1113 | 1145 | |
1114 | 1146 | private int getSlotForScreenPosition(int posX, int posY, int itemWidth, int itemHeight) { |
1115 | - Pool<Vector3f> pool = mTempVec; | |
1147 | + Pool<Vector3f> pool = sTempVec; | |
1116 | 1148 | int retVal = 0; |
1117 | 1149 | Vector3f worldPos = pool.create(); |
1118 | 1150 | try { |
@@ -1148,7 +1180,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1148 | 1180 | mCurrentExpandedSlot = slotIndex; |
1149 | 1181 | goBack(); |
1150 | 1182 | if (metadata) { |
1151 | - DisplaySlot slot = mDisplaySlots[slotIndex - mBufferedVisibleRange.begin]; | |
1183 | + DisplaySlot slot = sDisplaySlots[slotIndex - sBufferedVisibleRange.begin]; | |
1152 | 1184 | if (slot.hasValidLocation()) { |
1153 | 1185 | MediaSet set = slot.getMediaSet(); |
1154 | 1186 | if (set.mReverseGeocodedLocation != null) { |
@@ -1196,7 +1228,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1196 | 1228 | mZoomValue = 1.0f; |
1197 | 1229 | centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f); |
1198 | 1230 | mTimeElapsedSinceView = SLIDESHOW_TRANSITION_TIME - 1.0f; |
1199 | - mHud.setAlpha(0); | |
1231 | + sHud.setAlpha(0); | |
1200 | 1232 | PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); |
1201 | 1233 | mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow"); |
1202 | 1234 | mWakeLock.acquire(); |
@@ -1204,7 +1236,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1204 | 1236 | |
1205 | 1237 | public void enterSelectionMode() { |
1206 | 1238 | mSlideshowMode = false; |
1207 | - mHud.enterSelectionMode(); | |
1239 | + sHud.enterSelectionMode(); | |
1208 | 1240 | int currentSlot = mInputProcessor.getCurrentSelectedSlot(); |
1209 | 1241 | if (currentSlot == Shared.INVALID) { |
1210 | 1242 | currentSlot = mInputProcessor.getCurrentFocusSlot(); |
@@ -1213,7 +1245,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1213 | 1245 | } |
1214 | 1246 | |
1215 | 1247 | private float getFillScreenZoomValue() { |
1216 | - return GridCameraManager.getFillScreenZoomValue(mCamera, mTempVec, mCurrentFocusItemWidth, mCurrentFocusItemHeight); | |
1248 | + return GridCameraManager.getFillScreenZoomValue(mCamera, sTempVec, mCurrentFocusItemWidth, mCurrentFocusItemHeight); | |
1217 | 1249 | } |
1218 | 1250 | |
1219 | 1251 | public void zoomInToSelectedItem() { |
@@ -1227,7 +1259,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1227 | 1259 | if (mZoomValue > 6.0f) { |
1228 | 1260 | mZoomValue = 6.0f; |
1229 | 1261 | } |
1230 | - mHud.setAlpha(1.0f); | |
1262 | + sHud.setAlpha(1.0f); | |
1231 | 1263 | centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f); |
1232 | 1264 | } |
1233 | 1265 |
@@ -1241,14 +1273,14 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1241 | 1273 | if (mZoomValue < 1.0f) { |
1242 | 1274 | mZoomValue = 1.0f; |
1243 | 1275 | } |
1244 | - mHud.setAlpha(1.0f); | |
1276 | + sHud.setAlpha(1.0f); | |
1245 | 1277 | centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f); |
1246 | 1278 | } |
1247 | 1279 | |
1248 | 1280 | public void rotateSelectedItems(float f) { |
1249 | - MediaBucketList bucketList = mBucketList; | |
1281 | + MediaBucketList bucketList = sBucketList; | |
1250 | 1282 | ArrayList<MediaBucket> mediaBuckets = bucketList.get(); |
1251 | - DisplayList displayList = mDisplayList; | |
1283 | + DisplayList displayList = sDisplayList; | |
1252 | 1284 | int numBuckets = mediaBuckets.size(); |
1253 | 1285 | for (int i = 0; i < numBuckets; ++i) { |
1254 | 1286 | MediaBucket bucket = mediaBuckets.get(i); |
@@ -1307,7 +1339,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1307 | 1339 | } |
1308 | 1340 | |
1309 | 1341 | public Vector3f getDeltaAnchorPosition() { |
1310 | - return mDeltaAnchorPosition; | |
1342 | + return sDeltaAnchorPosition; | |
1311 | 1343 | } |
1312 | 1344 | |
1313 | 1345 | public int getExpandedSlot() { |
@@ -1325,16 +1357,16 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1325 | 1357 | |
1326 | 1358 | public void setPickIntent(boolean b) { |
1327 | 1359 | mPickIntent = b; |
1328 | - mHud.getPathBar().popLabel(); | |
1329 | - mHud.getPathBar().pushLabel(R.drawable.icon_location_small, mContext.getResources().getString(R.string.pick), | |
1360 | + sHud.getPathBar().popLabel(); | |
1361 | + sHud.getPathBar().pushLabel(R.drawable.icon_location_small, mContext.getResources().getString(R.string.pick), | |
1330 | 1362 | new Runnable() { |
1331 | 1363 | public void run() { |
1332 | - if (mHud.getAlpha() == 1.0f) { | |
1364 | + if (sHud.getAlpha() == 1.0f) { | |
1333 | 1365 | if (!mFeedAboutToChange) { |
1334 | 1366 | setState(STATE_MEDIA_SETS); |
1335 | 1367 | } |
1336 | 1368 | } else { |
1337 | - mHud.setAlpha(1.0f); | |
1369 | + sHud.setAlpha(1.0f); | |
1338 | 1370 | } |
1339 | 1371 | } |
1340 | 1372 | }); |
@@ -1350,18 +1382,18 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti | ||
1350 | 1382 | mMediaFeed.expandMediaSet(0); |
1351 | 1383 | setState(STATE_GRID_VIEW); |
1352 | 1384 | // We need to make sure we haven't pushed the same label twice |
1353 | - if (mHud.getPathBar().getNumLevels() == 1) { | |
1354 | - mHud.getPathBar().pushLabel(R.drawable.icon_folder_small, setName, new Runnable() { | |
1385 | + if (sHud.getPathBar().getNumLevels() == 1) { | |
1386 | + sHud.getPathBar().pushLabel(R.drawable.icon_folder_small, setName, new Runnable() { | |
1355 | 1387 | public void run() { |
1356 | 1388 | if (mFeedAboutToChange) { |
1357 | 1389 | return; |
1358 | 1390 | } |
1359 | - if (mHud.getAlpha() == 1.0f) { | |
1391 | + if (sHud.getAlpha() == 1.0f) { | |
1360 | 1392 | disableLocationFiltering(); |
1361 | 1393 | mInputProcessor.clearSelection(); |
1362 | 1394 | setState(STATE_GRID_VIEW); |
1363 | 1395 | } else { |
1364 | - mHud.setAlpha(1.0f); | |
1396 | + sHud.setAlpha(1.0f); | |
1365 | 1397 | } |
1366 | 1398 | } |
1367 | 1399 | }); |
@@ -15,6 +15,7 @@ import android.content.pm.ResolveInfo; | ||
15 | 15 | import android.content.res.Resources; |
16 | 16 | import android.net.Uri; |
17 | 17 | import android.util.FloatMath; |
18 | +import android.util.Log; | |
18 | 19 | import android.view.MotionEvent; |
19 | 20 | |
20 | 21 | import com.cooliris.media.MenuBar.Menu; |
@@ -24,13 +25,13 @@ public final class HudLayer extends Layer { | ||
24 | 25 | public static final int MODE_NORMAL = 0; |
25 | 26 | public static final int MODE_SELECT = 1; |
26 | 27 | |
27 | - private final Context mContext; | |
28 | + private Context mContext; | |
28 | 29 | private GridLayer mGridLayer; |
29 | 30 | private final ImageButton mTopRightButton = new ImageButton(); |
30 | 31 | private final ImageButton mZoomInButton = new ImageButton(); |
31 | 32 | private final ImageButton mZoomOutButton = new ImageButton(); |
32 | - private final PathBarLayer mPathBar; | |
33 | - private final TimeBar mTimeBar; | |
33 | + private static PathBarLayer sPathBar; | |
34 | + private static TimeBar sTimeBar; | |
34 | 35 | private MenuBar.Menu[] mNormalBottomMenu = null; |
35 | 36 | private MenuBar.Menu[] mSingleViewIntentBottomMenu = null; |
36 | 37 | private final MenuBar mSelectionMenuBottom; |
@@ -103,9 +104,10 @@ public final class HudLayer extends Layer { | ||
103 | 104 | |
104 | 105 | HudLayer(Context context) { |
105 | 106 | mAlpha = 1.0f; |
106 | - mContext = context; | |
107 | - mTimeBar = new TimeBar(context); | |
108 | - mPathBar = new PathBarLayer(); | |
107 | + if (sTimeBar == null) { | |
108 | + sTimeBar = new TimeBar(context); | |
109 | + sPathBar = new PathBarLayer(); | |
110 | + } | |
109 | 111 | mTopRightButton.setSize((int) (100 * Gallery.PIXEL_DENSITY), (int) (94 * Gallery.PIXEL_DENSITY)); |
110 | 112 | |
111 | 113 | mZoomInButton.setSize(43 * Gallery.PIXEL_DENSITY, 43 * Gallery.PIXEL_DENSITY); |
@@ -118,13 +120,13 @@ public final class HudLayer extends Layer { | ||
118 | 120 | // The Share submenu is populated dynamically when opened. |
119 | 121 | Resources resources = context.getResources(); |
120 | 122 | PopupMenu.Option[] deleteOptions = { |
121 | - new PopupMenu.Option(mContext.getResources().getString(R.string.confirm_delete), resources | |
123 | + new PopupMenu.Option(context.getResources().getString(R.string.confirm_delete), resources | |
122 | 124 | .getDrawable(R.drawable.icon_delete), new Runnable() { |
123 | 125 | public void run() { |
124 | 126 | deleteSelection(); |
125 | 127 | } |
126 | 128 | }), |
127 | - new PopupMenu.Option(mContext.getResources().getString(R.string.cancel), resources | |
129 | + new PopupMenu.Option(context.getResources().getString(R.string.cancel), resources | |
128 | 130 | .getDrawable(R.drawable.icon_cancel), new Runnable() { |
129 | 131 | public void run() { |
130 | 132 |
@@ -132,17 +134,17 @@ public final class HudLayer extends Layer { | ||
132 | 134 | }), }; |
133 | 135 | mSelectionMenuBottom = new MenuBar(context); |
134 | 136 | |
135 | - MenuBar.Menu shareMenu = new MenuBar.Menu.Builder(mContext.getResources().getString(R.string.share)).icon( | |
137 | + MenuBar.Menu shareMenu = new MenuBar.Menu.Builder(context.getResources().getString(R.string.share)).icon( | |
136 | 138 | R.drawable.icon_share).onSelect(new Runnable() { |
137 | 139 | public void run() { |
138 | 140 | updateShareMenu(); |
139 | 141 | } |
140 | 142 | }).build(); |
141 | 143 | |
142 | - MenuBar.Menu deleteMenu = new MenuBar.Menu.Builder(mContext.getResources().getString(R.string.delete)).icon( | |
144 | + MenuBar.Menu deleteMenu = new MenuBar.Menu.Builder(context.getResources().getString(R.string.delete)).icon( | |
143 | 145 | R.drawable.icon_delete).options(deleteOptions).build(); |
144 | 146 | |
145 | - MenuBar.Menu moreMenu = new MenuBar.Menu.Builder(mContext.getResources().getString(R.string.more)).icon( | |
147 | + MenuBar.Menu moreMenu = new MenuBar.Menu.Builder(context.getResources().getString(R.string.more)).icon( | |
146 | 148 | R.drawable.icon_more).onSelect(new Runnable() { |
147 | 149 | public void run() { |
148 | 150 | buildMoreOptions(); |
@@ -155,19 +157,19 @@ public final class HudLayer extends Layer { | ||
155 | 157 | mSelectionMenuBottom.setMenus(mNormalBottomMenu); |
156 | 158 | mSelectionMenuTop = new MenuBar(context); |
157 | 159 | mSelectionMenuTop.setMenus(new MenuBar.Menu[] { |
158 | - new MenuBar.Menu.Builder(mContext.getResources().getString(R.string.select_all)).onSelect(new Runnable() { | |
160 | + new MenuBar.Menu.Builder(context.getResources().getString(R.string.select_all)).onSelect(new Runnable() { | |
159 | 161 | public void run() { |
160 | 162 | mGridLayer.selectAll(); |
161 | 163 | } |
162 | 164 | }).build(), new MenuBar.Menu.Builder("").build(), |
163 | - new MenuBar.Menu.Builder(mContext.getResources().getString(R.string.deselect_all)).onSelect(new Runnable() { | |
165 | + new MenuBar.Menu.Builder(context.getResources().getString(R.string.deselect_all)).onSelect(new Runnable() { | |
164 | 166 | public void run() { |
165 | 167 | mGridLayer.deselectOrCancelSelectMode(); |
166 | 168 | } |
167 | 169 | }).build() }); |
168 | 170 | mFullscreenMenu = new MenuBar(context); |
169 | 171 | mFullscreenMenu.setMenus(new MenuBar.Menu[] { |
170 | - new MenuBar.Menu.Builder(mContext.getResources().getString(R.string.slideshow)).icon(R.drawable.icon_play) | |
172 | + new MenuBar.Menu.Builder(context.getResources().getString(R.string.slideshow)).icon(R.drawable.icon_play) | |
171 | 173 | .onSingleTapUp(new Runnable() { |
172 | 174 | public void run() { |
173 | 175 | if (getAlpha() == 1.0f) |
@@ -176,7 +178,7 @@ public final class HudLayer extends Layer { | ||
176 | 178 | setAlpha(1.0f); |
177 | 179 | } |
178 | 180 | }).build(), /* new MenuBar.Menu.Builder("").build(), */ |
179 | - new MenuBar.Menu.Builder(mContext.getResources().getString(R.string.menu)).icon(R.drawable.icon_more) | |
181 | + new MenuBar.Menu.Builder(context.getResources().getString(R.string.menu)).icon(R.drawable.icon_more) | |
180 | 182 | .onSingleTapUp(new Runnable() { |
181 | 183 | public void run() { |
182 | 184 | if (getAlpha() == 1.0f) |
@@ -186,6 +188,13 @@ public final class HudLayer extends Layer { | ||
186 | 188 | } |
187 | 189 | }).build() }); |
188 | 190 | } |
191 | + | |
192 | + public void setContext(Context context) { | |
193 | + if (mContext != context) { | |
194 | + mContext = context; | |
195 | + sTimeBar.regenerateStringsForContext(context); | |
196 | + } | |
197 | + } | |
189 | 198 | |
190 | 199 | private void buildMoreOptions() { |
191 | 200 | ArrayList<MediaBucket> buckets = mGridLayer.getSelectedBuckets(); |
@@ -407,8 +416,8 @@ public final class HudLayer extends Layer { | ||
407 | 416 | final float height = mHeight; |
408 | 417 | closeSelectionMenu(); |
409 | 418 | |
410 | - mTimeBar.setPosition(0f, height - TimeBar.HEIGHT * Gallery.PIXEL_DENSITY); | |
411 | - mTimeBar.setSize(width, TimeBar.HEIGHT * Gallery.PIXEL_DENSITY); | |
419 | + sTimeBar.setPosition(0f, height - TimeBar.HEIGHT * Gallery.PIXEL_DENSITY); | |
420 | + sTimeBar.setSize(width, TimeBar.HEIGHT * Gallery.PIXEL_DENSITY); | |
412 | 421 | mSelectionMenuTop.setPosition(0f, 0); |
413 | 422 | mSelectionMenuTop.setSize(width, MenuBar.HEIGHT * Gallery.PIXEL_DENSITY); |
414 | 423 | mSelectionMenuBottom.setPosition(0f, height - MenuBar.HEIGHT * Gallery.PIXEL_DENSITY); |
@@ -417,7 +426,7 @@ public final class HudLayer extends Layer { | ||
417 | 426 | mFullscreenMenu.setPosition(0f, height - MenuBar.HEIGHT * Gallery.PIXEL_DENSITY); |
418 | 427 | mFullscreenMenu.setSize(width, MenuBar.HEIGHT * Gallery.PIXEL_DENSITY); |
419 | 428 | |
420 | - mPathBar.setPosition(0f, -4f * Gallery.PIXEL_DENSITY); | |
429 | + sPathBar.setPosition(0f, -4f * Gallery.PIXEL_DENSITY); | |
421 | 430 | computeSizeForPathbar(); |
422 | 431 | |
423 | 432 | mTopRightButton.setPosition(width - mTopRightButton.getWidth(), 0f); |
@@ -429,12 +438,12 @@ public final class HudLayer extends Layer { | ||
429 | 438 | float pathBarWidth = mWidth |
430 | 439 | - ((mGridLayer.getState() == GridLayer.STATE_FULL_SCREEN) ? 32 * Gallery.PIXEL_DENSITY |
431 | 440 | : 120 * Gallery.PIXEL_DENSITY); |
432 | - mPathBar.setSize(pathBarWidth, FloatMath.ceil(39 * Gallery.PIXEL_DENSITY)); | |
433 | - mPathBar.recomputeComponents(); | |
441 | + sPathBar.setSize(pathBarWidth, FloatMath.ceil(39 * Gallery.PIXEL_DENSITY)); | |
442 | + sPathBar.recomputeComponents(); | |
434 | 443 | } |
435 | 444 | |
436 | 445 | public void setFeed(MediaFeed feed, int state, boolean needsLayout) { |
437 | - mTimeBar.setFeed(feed, state, needsLayout); | |
446 | + sTimeBar.setFeed(feed, state, needsLayout); | |
438 | 447 | } |
439 | 448 | |
440 | 449 | public void onGridStateChanged() { |
@@ -442,8 +451,9 @@ public final class HudLayer extends Layer { | ||
442 | 451 | } |
443 | 452 | |
444 | 453 | private void updateViews() { |
454 | + if (mGridLayer == null) | |
455 | + return; | |
445 | 456 | final int state = mGridLayer.getState(); |
446 | - | |
447 | 457 | // Show the selection menu in selection mode. |
448 | 458 | final boolean selectionMode = mMode == MODE_SELECT; |
449 | 459 | final boolean fullscreenMode = state == GridLayer.STATE_FULL_SCREEN; |
@@ -455,11 +465,11 @@ public final class HudLayer extends Layer { | ||
455 | 465 | mZoomOutButton.setHidden(mFullscreenMenu.isHidden()); |
456 | 466 | |
457 | 467 | // Show the time bar in stack and grid states, except in selection mode. |
458 | - mTimeBar.setHidden(fullscreenMode || selectionMode || stackMode); | |
468 | + sTimeBar.setHidden(fullscreenMode || selectionMode || stackMode); | |
459 | 469 | // mTimeBar.setHidden(selectionMode || (state != GridLayer.STATE_TIMELINE && state != GridLayer.STATE_GRID_VIEW)); |
460 | 470 | |
461 | 471 | // Hide the path bar and top-right button in selection mode. |
462 | - mPathBar.setHidden(selectionMode); | |
472 | + sPathBar.setHidden(selectionMode); | |
463 | 473 | mTopRightButton.setHidden(selectionMode || fullscreenMode); |
464 | 474 | computeSizeForPathbar(); |
465 | 475 |
@@ -495,11 +505,11 @@ public final class HudLayer extends Layer { | ||
495 | 505 | } |
496 | 506 | |
497 | 507 | public TimeBar getTimeBar() { |
498 | - return mTimeBar; | |
508 | + return sTimeBar; | |
499 | 509 | } |
500 | 510 | |
501 | 511 | public PathBarLayer getPathBar() { |
502 | - return mPathBar; | |
512 | + return sPathBar; | |
503 | 513 | } |
504 | 514 | |
505 | 515 | public GridLayer getGridLayer() { |
@@ -566,12 +576,12 @@ public final class HudLayer extends Layer { | ||
566 | 576 | mTopRightButton.generate(view, lists); |
567 | 577 | mZoomInButton.generate(view, lists); |
568 | 578 | mZoomOutButton.generate(view, lists); |
569 | - mTimeBar.generate(view, lists); | |
579 | + sTimeBar.generate(view, lists); | |
570 | 580 | mSelectionMenuTop.generate(view, lists); |
571 | 581 | mSelectionMenuBottom.generate(view, lists); |
572 | 582 | mFullscreenMenu.generate(view, lists); |
573 | - mPathBar.generate(view, lists); | |
574 | - //mLoadingLayer.generate(view, lists); | |
583 | + sPathBar.generate(view, lists); | |
584 | + // mLoadingLayer.generate(view, lists); | |
575 | 585 | mView = view; |
576 | 586 | } |
577 | 587 |
@@ -609,6 +619,7 @@ public final class HudLayer extends Layer { | ||
609 | 619 | |
610 | 620 | void reset() { |
611 | 621 | mLoadingLayer.reset(); |
622 | + sTimeBar.regenerateStringsForContext(mContext); | |
612 | 623 | } |
613 | 624 | |
614 | 625 | public void fullscreenSelectionChanged(MediaItem item, int index, int count) { |
@@ -622,12 +633,7 @@ public final class HudLayer extends Layer { | ||
622 | 633 | mCachedCaption = item.mCaption; |
623 | 634 | mCachedPosition = location; |
624 | 635 | mCachedCurrentLabel = location; |
625 | - mPathBar.changeLabel(location); | |
626 | - // String displayString = DateFormat.format("h:mmaa MMM dd yyyy", item.dateTaken).toString(); | |
627 | - // Menu menu = new | |
628 | - // MenuBar.Menu.Builder(displayString).StringTexture.Config(MenuBar.MENU_TITLE_STYLE_TEXT).resizeToAccomodate() | |
629 | - // .build(); | |
630 | - // mFullscreenMenu.updateMenu(menu, 1); | |
636 | + sPathBar.changeLabel(location); | |
631 | 637 | } |
632 | 638 | |
633 | 639 | private void updateShareMenu() { |
@@ -739,7 +745,7 @@ public final class HudLayer extends Layer { | ||
739 | 745 | |
740 | 746 | public void swapFullscreenLabel() { |
741 | 747 | mCachedCurrentLabel = (mCachedCurrentLabel == mCachedCaption || mCachedCaption == null) ? mCachedPosition : mCachedCaption; |
742 | - mPathBar.changeLabel(mCachedCurrentLabel); | |
748 | + sPathBar.changeLabel(mCachedCurrentLabel); | |
743 | 749 | } |
744 | 750 | |
745 | 751 | public void clear() { |
@@ -747,7 +753,7 @@ public final class HudLayer extends Layer { | ||
747 | 753 | } |
748 | 754 | |
749 | 755 | public void shutDown() { |
750 | - mGridLayer = null; | |
756 | + | |
751 | 757 | } |
752 | 758 | |
753 | 759 | public void enterSelectionMode() { |
@@ -280,9 +280,9 @@ public class ImageManager { | ||
280 | 280 | return false; |
281 | 281 | } |
282 | 282 | |
283 | - private static Cursor query(ContentResolver resolver, Uri uri, | |
284 | - String[] projection, String selection, String[] selectionArgs, | |
285 | - String sortOrder) { | |
283 | + private static final Cursor query(final ContentResolver resolver, final Uri uri, | |
284 | + final String[] projection, final String selection, final String[] selectionArgs, | |
285 | + final String sortOrder) { | |
286 | 286 | try { |
287 | 287 | if (resolver == null) { |
288 | 288 | return null; |
@@ -295,9 +295,9 @@ public class ImageManager { | ||
295 | 295 | |
296 | 296 | } |
297 | 297 | |
298 | - public static boolean isMediaScannerScanning(ContentResolver cr) { | |
298 | + public static final boolean isMediaScannerScanning(final ContentResolver cr) { | |
299 | 299 | boolean result = false; |
300 | - Cursor cursor = query(cr, MediaStore.getMediaScannerUri(), | |
300 | + final Cursor cursor = query(cr, MediaStore.getMediaScannerUri(), | |
301 | 301 | new String [] {MediaStore.MEDIA_SCANNER_VOLUME}, |
302 | 302 | null, null, null); |
303 | 303 | if (cursor != null) { |
@@ -94,6 +94,9 @@ public final class LocalDataSource implements DataSource { | ||
94 | 94 | } |
95 | 95 | |
96 | 96 | public void shutdown() { |
97 | + if (ImageManager.isMediaScannerScanning(mContext.getContentResolver())) { | |
98 | + stopListeners(); | |
99 | + } | |
97 | 100 | } |
98 | 101 | |
99 | 102 | private void stopListeners() { |
@@ -113,7 +116,6 @@ public final class LocalDataSource implements DataSource { | ||
113 | 116 | Log.i(TAG, "Refreshing local data source"); |
114 | 117 | Gallery.NEEDS_REFRESH = true; |
115 | 118 | if (feed.getMediaSet(setIdToUse) == null) { |
116 | - Log.i(TAG, "We check to see if there are any items with this bucket id in the database."); | |
117 | 119 | if (!CacheService.setHasItems(mContext.getContentResolver(), setIdToUse)) |
118 | 120 | return; |
119 | 121 | MediaSet mediaSet = feed.addMediaSet(setIdToUse, this); |
@@ -23,6 +23,7 @@ public final class MediaFeed implements Runnable { | ||
23 | 23 | private Listener mListener; |
24 | 24 | private DataSource mDataSource; |
25 | 25 | private boolean mListenerNeedsUpdate = false; |
26 | + private boolean mMediaFeedNeedsToRun = false; | |
26 | 27 | private MediaSet mSingleWrapper = new MediaSet(); |
27 | 28 | private boolean mInClusteringMode = false; |
28 | 29 | private HashMap<MediaSet, MediaClustering> mClusterSets = new HashMap<MediaSet, MediaClustering>(32); |
@@ -50,7 +51,7 @@ public final class MediaFeed implements Runnable { | ||
50 | 51 | mSingleWrapper.setNumExpectedItems(1); |
51 | 52 | mLoading = true; |
52 | 53 | } |
53 | - | |
54 | + | |
54 | 55 | public void shutdown() { |
55 | 56 | if (mDataSourceThread != null) { |
56 | 57 | mDataSource.shutdown(); |
@@ -83,13 +84,16 @@ public final class MediaFeed implements Runnable { | ||
83 | 84 | } |
84 | 85 | |
85 | 86 | public void setVisibleRange(int begin, int end) { |
86 | - mVisibleRange.begin = begin; | |
87 | - mVisibleRange.end = end; | |
88 | - int numItems = 96; | |
89 | - int numItemsBy2 = numItems / 2; | |
90 | - int numItemsBy4 = numItems / 4; | |
91 | - mBufferedRange.begin = (begin / numItemsBy2) * numItemsBy2 - numItemsBy4; | |
92 | - mBufferedRange.end = mBufferedRange.begin + numItems; | |
87 | + if (begin != mVisibleRange.begin || end != mVisibleRange.end) { | |
88 | + mVisibleRange.begin = begin; | |
89 | + mVisibleRange.end = end; | |
90 | + int numItems = 96; | |
91 | + int numItemsBy2 = numItems / 2; | |
92 | + int numItemsBy4 = numItems / 4; | |
93 | + mBufferedRange.begin = (begin / numItemsBy2) * numItemsBy2 - numItemsBy4; | |
94 | + mBufferedRange.end = mBufferedRange.begin + numItems; | |
95 | + mMediaFeedNeedsToRun = true; | |
96 | + } | |
93 | 97 | } |
94 | 98 | |
95 | 99 | public void setFilter(MediaFilter filter) { |
@@ -98,6 +102,7 @@ public final class MediaFeed implements Runnable { | ||
98 | 102 | if (mListener != null) { |
99 | 103 | mListener.onFeedAboutToChange(this); |
100 | 104 | } |
105 | + mMediaFeedNeedsToRun = true; | |
101 | 106 | } |
102 | 107 | |
103 | 108 | public void removeFilter() { |
@@ -107,19 +112,24 @@ public final class MediaFeed implements Runnable { | ||
107 | 112 | mListener.onFeedAboutToChange(this); |
108 | 113 | updateListener(true); |
109 | 114 | } |
115 | + mMediaFeedNeedsToRun = true; | |
110 | 116 | } |
111 | 117 | |
112 | 118 | public ArrayList<MediaSet> getMediaSets() { |
113 | 119 | return mMediaSets; |
114 | 120 | } |
115 | 121 | |
116 | - public synchronized MediaSet getMediaSet(final long setId) { | |
122 | + public MediaSet getMediaSet(final long setId) { | |
117 | 123 | if (setId != Shared.INVALID) { |
118 | - int mMediaSetsSize = mMediaSets.size(); | |
119 | - for (int i = 0; i < mMediaSetsSize; i++) { | |
120 | - if (mMediaSets.get(i).mId == setId) { | |
121 | - return mMediaSets.get(i); | |
124 | + try { | |
125 | + int mMediaSetsSize = mMediaSets.size(); | |
126 | + for (int i = 0; i < mMediaSetsSize; i++) { | |
127 | + if (mMediaSets.get(i).mId == setId) { | |
128 | + return mMediaSets.get(i); | |
129 | + } | |
122 | 130 | } |
131 | + } catch (Exception e) { | |
132 | + return null; | |
123 | 133 | } |
124 | 134 | } |
125 | 135 | return null; |
@@ -133,6 +143,10 @@ public final class MediaFeed implements Runnable { | ||
133 | 143 | MediaSet mediaSet = new MediaSet(dataSource); |
134 | 144 | mediaSet.mId = setId; |
135 | 145 | mMediaSets.add(mediaSet); |
146 | + if (mDataSourceThread != null && !mDataSourceThread.isAlive()) { | |
147 | + mDataSourceThread.start(); | |
148 | + } | |
149 | + mMediaFeedNeedsToRun = true; | |
136 | 150 | return mediaSet; |
137 | 151 | } |
138 | 152 |
@@ -161,7 +175,7 @@ public final class MediaFeed implements Runnable { | ||
161 | 175 | public void addItemToMediaSet(MediaItem item, MediaSet mediaSet) { |
162 | 176 | item.mParentMediaSet = mediaSet; |
163 | 177 | mediaSet.addItem(item); |
164 | - synchronized (this) { | |
178 | + synchronized (mClusterSets) { | |
165 | 179 | if (item.mClusteringState == MediaItem.NOT_CLUSTERED) { |
166 | 180 | MediaClustering clustering = mClusterSets.get(mediaSet); |
167 | 181 | if (clustering == null) { |
@@ -173,6 +187,7 @@ public final class MediaFeed implements Runnable { | ||
173 | 187 | item.mClusteringState = MediaItem.CLUSTERED; |
174 | 188 | } |
175 | 189 | } |
190 | + mMediaFeedNeedsToRun = true; | |
176 | 191 | } |
177 | 192 | |
178 | 193 | public void performOperation(final int operation, final ArrayList<MediaBucket> mediaBuckets, final Object data) { |
@@ -183,7 +198,6 @@ public final class MediaFeed implements Runnable { | ||
183 | 198 | } |
184 | 199 | if (operation == OPERATION_DELETE && mListener != null) { |
185 | 200 | mListener.onFeedAboutToChange(this); |
186 | - | |
187 | 201 | } |
188 | 202 | Thread operationThread = new Thread(new Runnable() { |
189 | 203 | public void run() { |
@@ -214,6 +228,7 @@ public final class MediaFeed implements Runnable { | ||
214 | 228 | } |
215 | 229 | } |
216 | 230 | updateListener(true); |
231 | + mMediaFeedNeedsToRun = true; | |
217 | 232 | if (mDataSource != null) { |
218 | 233 | mDataSource.performOperation(OPERATION_DELETE, mediaBuckets, null); |
219 | 234 | } |
@@ -228,16 +243,18 @@ public final class MediaFeed implements Runnable { | ||
228 | 243 | |
229 | 244 | public void removeMediaSet(MediaSet set) { |
230 | 245 | mMediaSets.remove(set); |
246 | + mMediaFeedNeedsToRun = true; | |
231 | 247 | } |
232 | 248 | |
233 | 249 | private void removeItemFromMediaSet(MediaItem item, MediaSet mediaSet) { |
234 | 250 | mediaSet.removeItem(item); |
235 | - synchronized (this) { | |
251 | + synchronized (mClusterSets) { | |
236 | 252 | MediaClustering clustering = mClusterSets.get(mediaSet); |
237 | 253 | if (clustering != null) { |
238 | 254 | clustering.removeItemFromClustering(item); |
239 | 255 | } |
240 | 256 | } |
257 | + mMediaFeedNeedsToRun = true; | |
241 | 258 | } |
242 | 259 | |
243 | 260 | public void updateListener(boolean needsLayout) { |
@@ -311,7 +328,7 @@ public final class MediaFeed implements Runnable { | ||
311 | 328 | public boolean getWaitingForMediaScanner() { |
312 | 329 | return mWaitingForMediaScanner; |
313 | 330 | } |
314 | - | |
331 | + | |
315 | 332 | public boolean isLoading() { |
316 | 333 | return mLoading; |
317 | 334 | } |
@@ -319,6 +336,8 @@ public final class MediaFeed implements Runnable { | ||
319 | 336 | public void start() { |
320 | 337 | final MediaFeed feed = this; |
321 | 338 | mLoading = true; |
339 | + mDataSourceThread = new Thread(this); | |
340 | + mDataSourceThread.setName("MediaFeed"); | |
322 | 341 | mAlbumSourceThread = new Thread(new Runnable() { |
323 | 342 | public void run() { |
324 | 343 | if (mContext == null) |
@@ -326,6 +345,9 @@ public final class MediaFeed implements Runnable { | ||
326 | 345 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); |
327 | 346 | DataSource dataSource = mDataSource; |
328 | 347 | // We must wait while the SD card is mounted or the MediaScanner is running. |
348 | + if (dataSource != null) { | |
349 | + dataSource.loadMediaSets(feed); | |
350 | + } | |
329 | 351 | mWaitingForMediaScanner = false; |
330 | 352 | while (ImageManager.isMediaScannerScanning(mContext.getContentResolver())) { |
331 | 353 | // MediaScanner is still running, wait |
@@ -341,19 +363,16 @@ public final class MediaFeed implements Runnable { | ||
341 | 363 | } |
342 | 364 | if (mWaitingForMediaScanner) { |
343 | 365 | showToast(mContext.getResources().getString(R.string.loading_new), Toast.LENGTH_LONG); |
344 | - } | |
345 | - mWaitingForMediaScanner = false; | |
346 | - if (dataSource != null) { | |
347 | - dataSource.loadMediaSets(feed); | |
366 | + mWaitingForMediaScanner = false; | |
367 | + if (dataSource != null) { | |
368 | + dataSource.loadMediaSets(feed); | |
369 | + } | |
348 | 370 | } |
349 | 371 | mLoading = false; |
350 | 372 | } |
351 | 373 | }); |
352 | 374 | mAlbumSourceThread.setName("MediaSets"); |
353 | 375 | mAlbumSourceThread.start(); |
354 | - mDataSourceThread = new Thread(this); | |
355 | - mDataSourceThread.setName("MediaFeed"); | |
356 | - mDataSourceThread.start(); | |
357 | 376 | } |
358 | 377 | |
359 | 378 | private void showToast(final String string, final int duration) { |
@@ -361,7 +380,7 @@ public final class MediaFeed implements Runnable { | ||
361 | 380 | } |
362 | 381 | |
363 | 382 | private void showToast(final String string, final int duration, final boolean centered) { |
364 | - if (mContext != null && !((Gallery)mContext).isPaused()) { | |
383 | + if (mContext != null && !((Gallery) mContext).isPaused()) { | |
365 | 384 | ((Gallery) mContext).getHandler().post(new Runnable() { |
366 | 385 | public void run() { |
367 | 386 | if (mContext != null) { |
@@ -378,10 +397,10 @@ public final class MediaFeed implements Runnable { | ||
378 | 397 | |
379 | 398 | public void run() { |
380 | 399 | DataSource dataSource = mDataSource; |
381 | - int sleepMs = 100; | |
400 | + int sleepMs = 10; | |
382 | 401 | Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); |
383 | 402 | if (dataSource != null) { |
384 | - while (Thread.interrupted() == false) { | |
403 | + while (!Thread.interrupted()) { | |
385 | 404 | if (mListenerNeedsUpdate) { |
386 | 405 | mListenerNeedsUpdate = false; |
387 | 406 | if (mListener != null) |
@@ -392,13 +411,21 @@ public final class MediaFeed implements Runnable { | ||
392 | 411 | return; |
393 | 412 | } |
394 | 413 | } else { |
414 | + if (mWaitingForMediaScanner) { | |
415 | + synchronized (mMediaSets) { | |
416 | + mMediaSets.clear(); | |
417 | + } | |
418 | + } | |
395 | 419 | try { |
396 | 420 | Thread.sleep(sleepMs); |
397 | 421 | } catch (InterruptedException e) { |
398 | 422 | return; |
399 | 423 | } |
400 | 424 | } |
401 | - sleepMs = 100; | |
425 | + sleepMs = 300; | |
426 | + if (!mMediaFeedNeedsToRun) | |
427 | + continue; | |
428 | + mMediaFeedNeedsToRun = false; | |
402 | 429 | ArrayList<MediaSet> mediaSets = mMediaSets; |
403 | 430 | synchronized (mediaSets) { |
404 | 431 | int expandedSetIndex = mExpandedMediaSetIndex; |
@@ -415,13 +442,6 @@ public final class MediaFeed implements Runnable { | ||
415 | 442 | if (i >= visibleRange.begin && i <= visibleRange.end && scanMediaSets) { |
416 | 443 | MediaSet set = mediaSets.get(i); |
417 | 444 | int numItemsLoaded = set.mNumItemsLoaded; |
418 | - if (!set.setContainsValidItems()) { | |
419 | - mediaSets.remove(set); | |
420 | - if (mListener != null) { | |
421 | - mListener.onFeedChanged(this, false); | |
422 | - } | |
423 | - break; | |
424 | - } | |
425 | 445 | if (numItemsLoaded < set.getNumExpectedItems() && numItemsLoaded < 8) { |
426 | 446 | dataSource.loadItemsForSet(this, set, numItemsLoaded, 8); |
427 | 447 | if (set.getNumExpectedItems() == 0) { |
@@ -434,6 +454,13 @@ public final class MediaFeed implements Runnable { | ||
434 | 454 | sleepMs = 100; |
435 | 455 | scanMediaSets = false; |
436 | 456 | } |
457 | + if (!set.setContainsValidItems()) { | |
458 | + mediaSets.remove(set); | |
459 | + if (mListener != null) { | |
460 | + mListener.onFeedChanged(this, false); | |
461 | + } | |
462 | + break; | |
463 | + } | |
437 | 464 | } |
438 | 465 | } |
439 | 466 | numSets = mMediaSets.size(); |
@@ -455,7 +482,7 @@ public final class MediaFeed implements Runnable { | ||
455 | 482 | scanMediaSets = false; |
456 | 483 | } |
457 | 484 | } |
458 | - } else if (i < bufferedRange.begin || i > bufferedRange.end){ | |
485 | + } else if (i < bufferedRange.begin || i > bufferedRange.end) { | |
459 | 486 | // Purge this set to its initial status. |
460 | 487 | MediaClustering clustering = mClusterSets.get(set); |
461 | 488 | if (clustering != null) { |
@@ -555,6 +582,7 @@ public final class MediaFeed implements Runnable { | ||
555 | 582 | // PicasaService.requestSync(mContext, PicasaService.TYPE_ALBUM_PHOTOS, set.mPicasaAlbumId); |
556 | 583 | } |
557 | 584 | updateListener(true); |
585 | + mMediaFeedNeedsToRun = true; | |
558 | 586 | } |
559 | 587 | |
560 | 588 | public boolean canExpandSet(int slotIndex) { |
@@ -583,6 +611,7 @@ public final class MediaFeed implements Runnable { | ||
583 | 611 | mListener.onFeedAboutToChange(this); |
584 | 612 | } |
585 | 613 | updateListener(true); |
614 | + mMediaFeedNeedsToRun = true; | |
586 | 615 | } |
587 | 616 | return retVal; |
588 | 617 | } |
@@ -591,6 +620,7 @@ public final class MediaFeed implements Runnable { | ||
591 | 620 | if (mInClusteringMode) { |
592 | 621 | // Disable clustering. |
593 | 622 | mInClusteringMode = false; |
623 | + mMediaFeedNeedsToRun = true; | |
594 | 624 | return true; |
595 | 625 | } |
596 | 626 | return false; |
@@ -617,7 +647,7 @@ public final class MediaFeed implements Runnable { | ||
617 | 647 | } |
618 | 648 | if (setToUse != null) { |
619 | 649 | MediaClustering clustering = null; |
620 | - synchronized (this) { | |
650 | + synchronized (mClusterSets) { | |
621 | 651 | // Make sure the computation is completed to the end. |
622 | 652 | clustering = mClusterSets.get(setToUse); |
623 | 653 | if (clustering != null) { |
@@ -627,6 +657,7 @@ public final class MediaFeed implements Runnable { | ||
627 | 657 | } |
628 | 658 | } |
629 | 659 | mInClusteringMode = true; |
660 | + mMediaFeedNeedsToRun = true; | |
630 | 661 | updateListener(true); |
631 | 662 | } |
632 | 663 | } |
@@ -660,6 +691,7 @@ public final class MediaFeed implements Runnable { | ||
660 | 691 | mediaSets.set(i - 1, setEnd); |
661 | 692 | } |
662 | 693 | } |
694 | + mMediaFeedNeedsToRun = true; | |
663 | 695 | } |
664 | 696 | |
665 | 697 | public MediaSet replaceMediaSet(long setId, DataSource dataSource) { |
@@ -675,9 +707,10 @@ public final class MediaFeed implements Runnable { | ||
675 | 707 | break; |
676 | 708 | } |
677 | 709 | } |
710 | + mMediaFeedNeedsToRun = true; | |
678 | 711 | return mediaSet; |
679 | 712 | } |
680 | - | |
713 | + | |
681 | 714 | public void setSingleImageMode(boolean singleImageMode) { |
682 | 715 | mSingleImageMode = singleImageMode; |
683 | 716 | } |
@@ -91,11 +91,13 @@ public final class MediaItem { | ||
91 | 91 | public boolean isPicassaItem() { |
92 | 92 | return (mParentMediaSet != null && mParentMediaSet.isPicassaAlbum()); |
93 | 93 | } |
94 | + | |
95 | + private static final String VIDEO = "video/"; | |
94 | 96 | |
95 | 97 | public int getMediaType() { |
96 | 98 | if (mMediaType == -1) { |
97 | 99 | // Default to image if mMimetype is null or not video. |
98 | - mMediaType = (mMimeType != null && mMimeType.startsWith("video/")) ? MediaItem.MEDIA_TYPE_VIDEO : MediaItem.MEDIA_TYPE_IMAGE; | |
100 | + mMediaType = (mMimeType != null && mMimeType.startsWith(VIDEO)) ? MediaItem.MEDIA_TYPE_VIDEO : MediaItem.MEDIA_TYPE_IMAGE; | |
99 | 101 | } |
100 | 102 | return mMediaType; |
101 | 103 | } |
@@ -24,6 +24,7 @@ public final class MediaItemTexture extends Texture { | ||
24 | 24 | private final MediaItem mItem; |
25 | 25 | private Context mContext; |
26 | 26 | private boolean mIsRetrying; |
27 | + private boolean mCached; | |
27 | 28 | |
28 | 29 | public static final class Config { |
29 | 30 | public int thumbnailWidth; |
@@ -34,23 +35,10 @@ public final class MediaItemTexture extends Texture { | ||
34 | 35 | mConfig = config; |
35 | 36 | mContext = context; |
36 | 37 | mItem = item; |
38 | + mCached = computeCache(); | |
37 | 39 | } |
38 | 40 | |
39 | - @Override | |
40 | - public boolean isUncachedVideo() { | |
41 | - if (isCached()) | |
42 | - return false; | |
43 | - if (mItem.mParentMediaSet == null || mItem.mMimeType == null) | |
44 | - return false; | |
45 | - if (mItem.mParentMediaSet.mPicasaAlbumId == Shared.INVALID && mItem.mMimeType.contains("video")) { | |
46 | - return true; | |
47 | - } else { | |
48 | - return false; | |
49 | - } | |
50 | - } | |
51 | - | |
52 | - @Override | |
53 | - public boolean isCached() { | |
41 | + private boolean computeCache() { | |
54 | 42 | final Config config = mConfig; |
55 | 43 | final MediaItem item = mItem; |
56 | 44 | DiskCache cache = null; |
@@ -61,7 +49,7 @@ public final class MediaItemTexture extends Texture { | ||
61 | 49 | if (item.mMimeType.contains("video")) { |
62 | 50 | cache = LocalDataSource.sThumbnailCacheVideo; |
63 | 51 | } |
64 | - } | |
52 | + } | |
65 | 53 | } |
66 | 54 | if (cache == null) { |
67 | 55 | return false; |
@@ -72,6 +60,24 @@ public final class MediaItemTexture extends Texture { | ||
72 | 60 | } |
73 | 61 | } |
74 | 62 | |
63 | + @Override | |
64 | + public boolean isUncachedVideo() { | |
65 | + if (isCached()) | |
66 | + return false; | |
67 | + if (mItem.mParentMediaSet == null || mItem.mMimeType == null) | |
68 | + return false; | |
69 | + if (mItem.mParentMediaSet.mPicasaAlbumId == Shared.INVALID && mItem.mMimeType.contains("video")) { | |
70 | + return true; | |
71 | + } else { | |
72 | + return false; | |
73 | + } | |
74 | + } | |
75 | + | |
76 | + @Override | |
77 | + public boolean isCached() { | |
78 | + return mCached; | |
79 | + } | |
80 | + | |
75 | 81 | protected Bitmap load(RenderView view) { |
76 | 82 | |
77 | 83 | final Config config = mConfig; |
@@ -112,11 +118,15 @@ public final class MediaItemTexture extends Texture { | ||
112 | 118 | new Thread() { |
113 | 119 | public void run() { |
114 | 120 | try { |
115 | - Thread.sleep(5000); | |
121 | + Thread.sleep(5000); | |
116 | 122 | } catch (InterruptedException e) { |
117 | 123 | ; |
118 | 124 | } |
119 | - MediaStore.Video.Thumbnails.cancelThumbnailRequest(mContext.getContentResolver(), mItem.mId); | |
125 | + try { | |
126 | + MediaStore.Video.Thumbnails.cancelThumbnailRequest(mContext.getContentResolver(), mItem.mId); | |
127 | + } catch (Exception e) { | |
128 | + ; | |
129 | + } | |
120 | 130 | } |
121 | 131 | }.start(); |
122 | 132 | retVal = MediaStore.Video.Thumbnails.getThumbnail(mContext.getContentResolver(), mItem.mId, |
@@ -169,7 +179,7 @@ public final class MediaItemTexture extends Texture { | ||
169 | 179 | item.mThumbnailFocusY = dataInput.readShort(); |
170 | 180 | // Decode the thumbnail. |
171 | 181 | final BitmapFactory.Options options = new BitmapFactory.Options(); |
172 | - options.inDither = true; | |
182 | + options.inDither = false; | |
173 | 183 | options.inScaled = false; |
174 | 184 | options.inPreferredConfig = Bitmap.Config.RGB_565; |
175 | 185 | final Bitmap bitmap = BitmapFactory.decodeByteArray(data, CACHE_HEADER_SIZE, data.length - CACHE_HEADER_SIZE, |
@@ -142,7 +142,6 @@ public final class MenuBar extends Layer implements PopupMenu.Listener { | ||
142 | 142 | view.draw2D(icon, menu.x + offset, iconY); |
143 | 143 | } |
144 | 144 | float titleY = y + (height - MENU_TITLE_STYLE.height) / 2 + 1; |
145 | - //Log.i("MENUBAR", "Drawing label (" + title.getWidth() + ", " + title.getHeight() + ", " + title.mNormalizedWidth + ")"); | |
146 | 145 | view.draw2D(titleTexture, menu.x + offset + iconWidth, titleY); |
147 | 146 | } |
148 | 147 | } |
@@ -260,4 +260,8 @@ public final class PathBarLayer extends Layer { | ||
260 | 260 | public int getNumLevels() { |
261 | 261 | return mComponents.size(); |
262 | 262 | } |
263 | + | |
264 | + public void clear() { | |
265 | + mComponents.clear(); | |
266 | + } | |
263 | 267 | } |
@@ -189,7 +189,6 @@ public final class PicasaDataSource implements DataSource { | ||
189 | 189 | for (int j = 0, numItems = items.size(); j != numItems; ++j) { |
190 | 190 | MediaItem item = items.get(j); |
191 | 191 | if (item != null) { |
192 | - Log.i(TAG, "Deleting picasa photo " + item.mContentUri); | |
193 | 192 | String itemUri = PicasaContentProvider.PHOTOS_URI + "/" + item.mId; |
194 | 193 | client.delete(Uri.parse(itemUri), null, null); |
195 | 194 | } |
@@ -31,7 +31,7 @@ import android.view.SurfaceHolder; | ||
31 | 31 | public final class RenderView extends GLSurfaceView implements GLSurfaceView.Renderer, SensorEventListener { |
32 | 32 | private static final String TAG = "RenderView"; |
33 | 33 | private static final int NUM_TEXTURE_LOAD_THREADS = 4; |
34 | - private static final int MAX_LOADING_COUNT = 8; | |
34 | + private static final int MAX_LOADING_COUNT = 128; | |
35 | 35 | |
36 | 36 | private static final int EVENT_NONE = 0; |
37 | 37 | // private static final int EVENT_TOUCH = 1; |
@@ -46,7 +46,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
46 | 46 | |
47 | 47 | private RootLayer mRootLayer = null; |
48 | 48 | private boolean mListsDirty = false; |
49 | - private final Lists mLists = new Lists(); | |
49 | + private static final Lists sLists = new Lists(); | |
50 | 50 | |
51 | 51 | private Layer mTouchEventTarget = null; |
52 | 52 |
@@ -56,16 +56,18 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
56 | 56 | private volatile boolean mPendingSensorEvent = false; |
57 | 57 | |
58 | 58 | private int mLoadingCount = 0; |
59 | - private final Deque<Texture> mLoadInputQueue = new Deque<Texture>(); | |
60 | - private final Deque<Texture> mLoadInputQueueCached = new Deque<Texture>(); | |
61 | - private final Deque<Texture> mLoadInputQueueVideo = new Deque<Texture>(); | |
62 | - private final Deque<Texture> mLoadOutputQueue = new Deque<Texture>(); | |
59 | + private static final Deque<Texture> sLoadInputQueue = new Deque<Texture>(); | |
60 | + private static final Deque<Texture> sLoadInputQueueCached = new Deque<Texture>(); | |
61 | + private static final Deque<Texture> sLoadInputQueueVideo = new Deque<Texture>(); | |
62 | + private static final Deque<Texture> sLoadOutputQueue = new Deque<Texture>(); | |
63 | + private static TextureLoadThread sCachedTextureLoadThread = null; | |
64 | + private static TextureLoadThread sVideoTextureLoadThread = null; | |
65 | + private static final TextureLoadThread[] sTextureLoadThreads = new TextureLoadThread[NUM_TEXTURE_LOAD_THREADS]; | |
66 | + | |
63 | 67 | private final Deque<MotionEvent> mTouchEventQueue = new Deque<MotionEvent>(); |
64 | 68 | private final DirectLinkedList<TextureReference> mActiveTextureList = new DirectLinkedList<TextureReference>(); |
69 | + @SuppressWarnings("unchecked") | |
65 | 70 | private final ReferenceQueue mUnreferencedTextureQueue = new ReferenceQueue(); |
66 | - private final TextureLoadThread[] mTextureLoadThreads = new TextureLoadThread[NUM_TEXTURE_LOAD_THREADS]; | |
67 | - private TextureLoadThread mCachedTextureLoadThread = null; | |
68 | - private TextureLoadThread mVideoTextureLoadThread = null; | |
69 | 71 | |
70 | 72 | // Frame time in milliseconds and delta since last frame in seconds. Uses SystemClock.getUptimeMillis(). |
71 | 73 | private long mFrameTime = 0; |
@@ -77,10 +79,14 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
77 | 79 | private final SparseArray<ResourceTexture> sCacheUnscaled = new SparseArray<ResourceTexture>(); |
78 | 80 | |
79 | 81 | private boolean mFirstDraw; |
82 | + // The cached texture that is bound to Texture Unit 0. | |
83 | + // We need to reset this to null whenever the active texture unit changes. | |
84 | + private Texture mBoundTexture; | |
80 | 85 | |
81 | 86 | // Weak reference to a texture that stores the associated texture ID. |
82 | 87 | private static final class TextureReference extends WeakReference<Texture> { |
83 | - public TextureReference(Texture texture, GL11 gl, ReferenceQueue<Texture> referenceQueue, int textureId) { | |
88 | + @SuppressWarnings("unchecked") | |
89 | + public TextureReference(Texture texture, GL11 gl, ReferenceQueue referenceQueue, int textureId) { | |
84 | 90 | super(texture, referenceQueue); |
85 | 91 | this.textureId = textureId; |
86 | 92 | this.gl = gl; |
@@ -107,24 +113,25 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
107 | 113 | } |
108 | 114 | } |
109 | 115 | |
110 | - public RenderView(Context context) { | |
116 | + public RenderView(final Context context) { | |
111 | 117 | super(context); |
112 | 118 | setBackgroundDrawable(null); |
113 | 119 | setFocusable(true); |
114 | 120 | setEGLConfigChooser(true); |
115 | 121 | setRenderer(this); |
116 | 122 | mSensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE); |
117 | - | |
118 | - for (int i = 0; i != NUM_TEXTURE_LOAD_THREADS; ++i) { | |
119 | - TextureLoadThread thread = new TextureLoadThread(); | |
120 | - if (i == 0) { | |
121 | - mCachedTextureLoadThread = thread; | |
122 | - } | |
123 | - if (i == 1) { | |
124 | - mVideoTextureLoadThread = thread; | |
123 | + if (sCachedTextureLoadThread == null) { | |
124 | + for (int i = 0; i != NUM_TEXTURE_LOAD_THREADS; ++i) { | |
125 | + TextureLoadThread thread = new TextureLoadThread(); | |
126 | + if (i == 0) { | |
127 | + sCachedTextureLoadThread = thread; | |
128 | + } | |
129 | + if (i == 1) { | |
130 | + sVideoTextureLoadThread = thread; | |
131 | + } | |
132 | + sTextureLoadThreads[i] = thread; | |
133 | + thread.start(); | |
125 | 134 | } |
126 | - mTextureLoadThreads[i] = thread; | |
127 | - thread.start(); | |
128 | 135 | } |
129 | 136 | } |
130 | 137 |
@@ -241,11 +248,13 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
241 | 248 | |
242 | 249 | public boolean bind(Texture texture) { |
243 | 250 | if (texture != null) { |
251 | + if (texture == mBoundTexture) | |
252 | + return true; | |
244 | 253 | switch (texture.mState) { |
245 | 254 | case Texture.STATE_UNLOADED: |
246 | 255 | if (texture.getClass().equals(ResourceTexture.class)) { |
247 | 256 | loadTexture(texture); |
248 | - return true; | |
257 | + return false; | |
249 | 258 | } |
250 | 259 | if (mLoadingCount < MAX_LOADING_COUNT) { |
251 | 260 | queueLoad(texture, false); |
@@ -253,6 +262,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
253 | 262 | break; |
254 | 263 | case Texture.STATE_LOADED: |
255 | 264 | mGL.glBindTexture(GL11.GL_TEXTURE_2D, texture.mId); |
265 | + mBoundTexture = texture; | |
256 | 266 | return true; |
257 | 267 | default: |
258 | 268 | break; |
@@ -308,8 +318,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
308 | 318 | texture.mState = Texture.STATE_LOADING; |
309 | 319 | |
310 | 320 | // Push the texture onto the load input queue. |
311 | - Deque<Texture> inputQueue = (texture.isCached()) ? mLoadInputQueueCached : mLoadInputQueue; | |
312 | - inputQueue = (texture.isUncachedVideo()) ? mLoadInputQueueVideo : mLoadInputQueue; | |
321 | + Deque<Texture> inputQueue = (texture.isUncachedVideo()) ? sLoadInputQueueVideo : (texture.isCached()) ? sLoadInputQueueCached : sLoadInputQueue;; | |
313 | 322 | synchronized (inputQueue) { |
314 | 323 | if (highPriority) { |
315 | 324 | inputQueue.addFirst(texture); |
@@ -351,6 +360,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
351 | 360 | boolean bind = true; |
352 | 361 | bind &= bind(from); |
353 | 362 | gl.glActiveTexture(GL11.GL_TEXTURE1); |
363 | + mBoundTexture = null; | |
354 | 364 | bind &= bind(to); |
355 | 365 | if (!bind) { |
356 | 366 | return false; |
@@ -385,6 +395,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
385 | 395 | |
386 | 396 | // Switch back to the default texture unit. |
387 | 397 | gl.glActiveTexture(GL11.GL_TEXTURE0); |
398 | + mBoundTexture = null; | |
388 | 399 | } |
389 | 400 | |
390 | 401 | public void drawMixed2D(Texture from, Texture to, float ratio, float x, float y, float z, float width, float height) { |
@@ -393,6 +404,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
393 | 404 | // Bind "from" and "to" to TEXTURE0 and TEXTURE1, respectively. |
394 | 405 | if (bind(from)) { |
395 | 406 | gl.glActiveTexture(GL11.GL_TEXTURE1); |
407 | + mBoundTexture = null; | |
396 | 408 | if (bind(to)) { |
397 | 409 | // Enable TEXTURE1. |
398 | 410 | gl.glEnable(GL11.GL_TEXTURE_2D); |
@@ -423,6 +435,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
423 | 435 | |
424 | 436 | // Switch back to the default texture unit. |
425 | 437 | gl.glActiveTexture(GL11.GL_TEXTURE0); |
438 | + mBoundTexture = null; | |
426 | 439 | } |
427 | 440 | } |
428 | 441 |
@@ -445,7 +458,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
445 | 458 | } |
446 | 459 | mActiveTextureList.remove(textureReference.activeListEntry); |
447 | 460 | } |
448 | - Deque<Texture> outputQueue = mLoadOutputQueue; | |
461 | + Deque<Texture> outputQueue = sLoadOutputQueue; | |
449 | 462 | Texture texture; |
450 | 463 | do { |
451 | 464 | // Upload loaded textures to the GPU one frame at a time. |
@@ -467,6 +480,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
467 | 480 | private void uploadTexture(Texture texture, int[] textureId) { |
468 | 481 | Bitmap bitmap = texture.mBitmap; |
469 | 482 | GL11 gl = mGL; |
483 | + int glError = GL11.GL_NO_ERROR; | |
470 | 484 | if (bitmap != null) { |
471 | 485 | final int width = texture.mWidth; |
472 | 486 | final int height = texture.mHeight; |
@@ -474,41 +488,38 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
474 | 488 | // Define a vertically flipped crop rectangle for OES_draw_texture. |
475 | 489 | int[] cropRect = { 0, height, width, -height }; |
476 | 490 | |
477 | - // Handle texture upload failures | |
478 | - int numTextureFails = 0; | |
479 | - boolean textureFail = false; | |
480 | - do { | |
481 | - textureFail = false; | |
482 | - // Upload the bitmap to a new texture. | |
483 | - gl.glGenTextures(1, textureId, 0); | |
484 | - gl.glBindTexture(GL11.GL_TEXTURE_2D, textureId[0]); | |
485 | - gl.glTexParameteriv(GL11.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, 0); | |
486 | - gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); | |
487 | - gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); | |
488 | - gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); | |
489 | - gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); | |
490 | - GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0); | |
491 | - int glError = gl.glGetError(); | |
492 | - if (glError == GL11.GL_OUT_OF_MEMORY) { | |
493 | - Log.i(TAG, "Texture creation fail, glError " + glError + " retry id " + numTextureFails); | |
494 | - ++numTextureFails; | |
495 | - textureFail = true; | |
496 | - handleLowMemory(); | |
497 | - // TODO: Retry logic | |
498 | - numTextureFails = 3; | |
499 | - } | |
500 | - } while (textureFail && numTextureFails < 3); | |
491 | + // Upload the bitmap to a new texture. | |
492 | + gl.glGenTextures(1, textureId, 0); | |
493 | + gl.glBindTexture(GL11.GL_TEXTURE_2D, textureId[0]); | |
494 | + gl.glTexParameteriv(GL11.GL_TEXTURE_2D, GL11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, 0); | |
495 | + gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_S, GL11.GL_CLAMP_TO_EDGE); | |
496 | + gl.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_WRAP_T, GL11.GL_CLAMP_TO_EDGE); | |
497 | + gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_LINEAR); | |
498 | + gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR); | |
499 | + GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0); | |
500 | + glError = gl.glGetError(); | |
501 | + | |
501 | 502 | bitmap.recycle(); |
502 | - | |
503 | - // Update texture state. | |
504 | - texture.mBitmap = null; | |
505 | - texture.mId = textureId[0]; | |
506 | - texture.mState = Texture.STATE_LOADED; | |
507 | - | |
508 | - // Add to the active list. | |
509 | - final TextureReference textureRef = new TextureReference(texture, gl, mUnreferencedTextureQueue, textureId[0]); | |
510 | - mActiveTextureList.add(textureRef.activeListEntry); | |
511 | - requestRender(); | |
503 | + if (glError == GL11.GL_OUT_OF_MEMORY) { | |
504 | + handleLowMemory(); | |
505 | + } | |
506 | + if (glError != GL11.GL_NO_ERROR) { | |
507 | + // There was an error, we need to retry this texture at some later time | |
508 | + Log.i(TAG, "Texture creation fail, glError " + glError); | |
509 | + texture.mId = 0; | |
510 | + texture.mBitmap = null; | |
511 | + texture.mState = Texture.STATE_UNLOADED; | |
512 | + } else { | |
513 | + // Update texture state. | |
514 | + texture.mBitmap = null; | |
515 | + texture.mId = textureId[0]; | |
516 | + texture.mState = Texture.STATE_LOADED; | |
517 | + | |
518 | + // Add to the active list. | |
519 | + final TextureReference textureRef = new TextureReference(texture, gl, mUnreferencedTextureQueue, textureId[0]); | |
520 | + mActiveTextureList.add(textureRef.activeListEntry); | |
521 | + requestRender(); | |
522 | + } | |
512 | 523 | } else { |
513 | 524 | texture.mState = Texture.STATE_ERROR; |
514 | 525 | } |
@@ -551,9 +562,9 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
551 | 562 | |
552 | 563 | boolean wasLoadingExpensiveTextures = isLoadingExpensiveTextures(); |
553 | 564 | boolean loadingExpensiveTextures = false; |
554 | - int numTextureThreads = mTextureLoadThreads.length; | |
565 | + int numTextureThreads = sTextureLoadThreads.length; | |
555 | 566 | for (int i = 2; i < numTextureThreads; ++i) { |
556 | - if (mTextureLoadThreads[i].mIsLoading) { | |
567 | + if (sTextureLoadThreads[i].mIsLoading) { | |
557 | 568 | loadingExpensiveTextures = true; |
558 | 569 | break; |
559 | 570 | } |
@@ -566,7 +577,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
566 | 577 | processTextures(false); |
567 | 578 | |
568 | 579 | // Update the current time and frame time interval. |
569 | - final long now = SystemClock.uptimeMillis(); | |
580 | + long now = SystemClock.uptimeMillis(); | |
570 | 581 | final float dt = 0.001f * Math.min(50, now - mFrameTime); |
571 | 582 | mFrameInterval = dt; |
572 | 583 | mFrameTime = now; |
@@ -575,7 +586,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
575 | 586 | processCurrentEvent(); |
576 | 587 | processTouchEvent(); |
577 | 588 | // Run the update pass. |
578 | - final Lists lists = mLists; | |
589 | + final Lists lists = sLists; | |
579 | 590 | synchronized (lists) { |
580 | 591 | final ArrayList<Layer> updateList = lists.updateList; |
581 | 592 | boolean isDirty = false; |
@@ -586,7 +597,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
586 | 597 | if (isDirty) { |
587 | 598 | requestRender(); |
588 | 599 | } |
589 | - | |
600 | + | |
590 | 601 | // Clear the depth buffer. |
591 | 602 | gl.glClear(GL11.GL_DEPTH_BUFFER_BIT); |
592 | 603 | gl.glEnable(GL11.GL_SCISSOR_TEST); |
@@ -601,7 +612,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
601 | 612 | layer.renderOpaque(this, gl); |
602 | 613 | } |
603 | 614 | } |
604 | - | |
615 | + | |
605 | 616 | // Run the blended pass. |
606 | 617 | gl.glEnable(GL11.GL_BLEND); |
607 | 618 | final ArrayList<Layer> blendedList = lists.blendedList; |
@@ -611,10 +622,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
611 | 622 | layer.renderBlended(this, gl); |
612 | 623 | } |
613 | 624 | } |
614 | - } | |
615 | - int priority = Process.getThreadPriority(Process.myTid()); | |
616 | - if (priority != Process.THREAD_PRIORITY_URGENT_DISPLAY) { | |
617 | - Log.e(TAG, "The display thread should never be lowered to priority level " + priority); | |
625 | + gl.glDisable(GL11.GL_BLEND); | |
618 | 626 | } |
619 | 627 | } |
620 | 628 |
@@ -638,6 +646,8 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
638 | 646 | |
639 | 647 | private void processTouchEvent() { |
640 | 648 | MotionEvent event = null; |
649 | + int numEvents = mTouchEventQueue.size(); | |
650 | + int i = 0; | |
641 | 651 | do { |
642 | 652 | // We look at the touch event queue and process one event at a time |
643 | 653 | synchronized (mTouchEventQueue) { |
@@ -666,7 +676,8 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
666 | 676 | mTouchEventTarget = null; |
667 | 677 | } |
668 | 678 | event.recycle(); |
669 | - } while (event != null); | |
679 | + ++i; | |
680 | + } while (event != null && i < numEvents); | |
670 | 681 | synchronized (this) { |
671 | 682 | this.notify(); |
672 | 683 | } |
@@ -697,7 +708,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
697 | 708 | } |
698 | 709 | |
699 | 710 | private Layer hitTest(float x, float y) { |
700 | - final ArrayList<Layer> hitTestList = mLists.hitTestList; | |
711 | + final ArrayList<Layer> hitTestList = sLists.hitTestList; | |
701 | 712 | for (int i = hitTestList.size() - 1; i >= 0; --i) { |
702 | 713 | final Layer layer = hitTestList.get(i); |
703 | 714 | if (layer != null && !layer.mHidden) { |
@@ -714,9 +725,9 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
714 | 725 | |
715 | 726 | private void updateLists() { |
716 | 727 | if (mRootLayer != null) { |
717 | - synchronized (mLists) { | |
718 | - mLists.clear(); | |
719 | - mRootLayer.generate(this, mLists); | |
728 | + synchronized (sLists) { | |
729 | + sLists.clear(); | |
730 | + mRootLayer.generate(this, sLists); | |
720 | 731 | } |
721 | 732 | } |
722 | 733 | } |
@@ -759,7 +770,6 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
759 | 770 | // Clear the resource texture cache. |
760 | 771 | clearCache(); |
761 | 772 | |
762 | - // Log.i(TAG, "Surface Created for " + this); | |
763 | 773 | GL11 gl = (GL11) gl1; |
764 | 774 | if (mGL == null) { |
765 | 775 | mGL = gl; |
@@ -770,14 +780,14 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
770 | 780 | } |
771 | 781 | setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); |
772 | 782 | // Increase the priority of the render thread. |
773 | - Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY); | |
783 | + Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); | |
774 | 784 | |
775 | 785 | // Disable unused state. |
776 | 786 | gl.glEnable(GL11.GL_DITHER); |
777 | 787 | gl.glDisable(GL11.GL_LIGHTING); |
778 | 788 | |
779 | 789 | // Set global state. |
780 | - gl.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST); | |
790 | + // gl.glHint(GL11.GL_PERSPECTIVE_CORRECTION_HINT, GL11.GL_NICEST); | |
781 | 791 | |
782 | 792 | // Enable textures. |
783 | 793 | gl.glEnable(GL11.GL_TEXTURE_2D); |
@@ -821,8 +831,8 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
821 | 831 | if (mRootLayer != null) { |
822 | 832 | mRootLayer.onSurfaceCreated(this, gl); |
823 | 833 | } |
824 | - synchronized (mLists) { | |
825 | - ArrayList<Layer> systemList = mLists.systemList; | |
834 | + synchronized (sLists) { | |
835 | + ArrayList<Layer> systemList = sLists.systemList; | |
826 | 836 | for (int i = systemList.size() - 1; i >= 0; --i) { |
827 | 837 | systemList.get(i).onSurfaceCreated(this, gl); |
828 | 838 | } |
@@ -915,19 +925,16 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
915 | 925 | @Override |
916 | 926 | public void surfaceDestroyed(SurfaceHolder holder) { |
917 | 927 | super.surfaceDestroyed(holder); |
918 | - // Log.i(TAG, "Surface destroyed for " + this); | |
919 | 928 | } |
920 | 929 | |
921 | 930 | @Override |
922 | 931 | protected void onAttachedToWindow() { |
923 | 932 | super.onAttachedToWindow(); |
924 | - // Log.i(TAG, "Attaching to window for " + this); | |
925 | 933 | } |
926 | 934 | |
927 | 935 | @Override |
928 | 936 | protected void onDetachedFromWindow() { |
929 | 937 | super.onDetachedFromWindow(); |
930 | - // Log.i(TAG, "Detaching from Window for " + this); | |
931 | 938 | } |
932 | 939 | |
933 | 940 | private final class TextureLoadThread extends Thread { |
@@ -935,14 +942,12 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
935 | 942 | |
936 | 943 | public TextureLoadThread() { |
937 | 944 | super("TextureLoad"); |
938 | - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); | |
939 | 945 | } |
940 | 946 | |
941 | 947 | public void run() { |
942 | - RenderView view = RenderView.this; | |
943 | - Deque<Texture> inputQueue = (mCachedTextureLoadThread == this) ? view.mLoadInputQueueCached : view.mLoadInputQueue; | |
944 | - inputQueue = (mVideoTextureLoadThread == this) ? view.mLoadInputQueueVideo : view.mLoadInputQueue; | |
945 | - Deque<Texture> outputQueue = view.mLoadOutputQueue; | |
948 | + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); | |
949 | + Deque<Texture> inputQueue = (sVideoTextureLoadThread == this) ? sLoadInputQueueVideo : ((sCachedTextureLoadThread == this) ? sLoadInputQueueCached : sLoadInputQueue); | |
950 | + Deque<Texture> outputQueue = sLoadOutputQueue; | |
946 | 951 | try { |
947 | 952 | for (;;) { |
948 | 953 | // Pop the next texture from the input queue. |
@@ -952,7 +957,7 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
952 | 957 | inputQueue.wait(); |
953 | 958 | } |
954 | 959 | } |
955 | - if (mCachedTextureLoadThread != this) | |
960 | + if (sCachedTextureLoadThread != this) | |
956 | 961 | mIsLoading = true; |
957 | 962 | // Load the texture bitmap. |
958 | 963 | load(texture); |
@@ -977,14 +982,9 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
977 | 982 | } |
978 | 983 | |
979 | 984 | public void shutdown() { |
980 | - // stop all the threads | |
981 | - for (int i = 0; i < NUM_TEXTURE_LOAD_THREADS; ++i) { | |
982 | - mTextureLoadThreads[i].interrupt(); | |
983 | - } | |
984 | - ArrayUtils.clear(mTextureLoadThreads); | |
985 | 985 | mRootLayer = null; |
986 | - synchronized (mLists) { | |
987 | - mLists.clear(); | |
986 | + synchronized (sLists) { | |
987 | + sLists.clear(); | |
988 | 988 | } |
989 | 989 | } |
990 | 990 |
@@ -996,6 +996,6 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren | ||
996 | 996 | } |
997 | 997 | |
998 | 998 | public Lists getLists() { |
999 | - return mLists; | |
999 | + return sLists; | |
1000 | 1000 | } |
1001 | 1001 | } |
@@ -20,25 +20,21 @@ public final class ReverseGeocoder extends Thread { | ||
20 | 20 | // If two points are within 50 miles of each other, use "Around Palo Alto, CA" or "Around Mountain View, CA". |
21 | 21 | // instead of directly jumping to the next level and saying "California, US". |
22 | 22 | private static final int MAX_LOCALITY_MILE_RANGE = 50; |
23 | - | |
23 | + private static final Deque<MediaSet> sQueue = new Deque<MediaSet>(); | |
24 | + private static final DiskCache sGeoCache = new DiskCache("geocoder-cache"); | |
24 | 25 | private static final String TAG = "ReverseGeocoder"; |
25 | 26 | |
26 | - private final Geocoder mGeocoder; | |
27 | + private Geocoder mGeocoder; | |
27 | 28 | private final Context mContext; |
28 | - private final Deque<MediaSet> mQueue = new Deque<MediaSet>(); | |
29 | - private final DiskCache mGeoCache = new DiskCache("geocoder-cache"); | |
30 | 29 | |
31 | 30 | public ReverseGeocoder(Context context) { |
32 | 31 | super(TAG); |
33 | 32 | mContext = context; |
34 | - mGeocoder = new Geocoder(mContext); | |
35 | - // Loading the addresses in the GeoCache. | |
36 | - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); | |
37 | 33 | start(); |
38 | 34 | } |
39 | 35 | |
40 | 36 | public void enqueue(MediaSet set) { |
41 | - Deque<MediaSet> inQueue = mQueue; | |
37 | + Deque<MediaSet> inQueue = sQueue; | |
42 | 38 | synchronized (inQueue) { |
43 | 39 | inQueue.addLast(set); |
44 | 40 | inQueue.notify(); |
@@ -47,7 +43,10 @@ public final class ReverseGeocoder extends Thread { | ||
47 | 43 | |
48 | 44 | @Override |
49 | 45 | public void run() { |
50 | - Deque<MediaSet> queue = mQueue; | |
46 | + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); | |
47 | + Deque<MediaSet> queue = sQueue; | |
48 | + mGeocoder = new Geocoder(mContext); | |
49 | + queue.clear(); | |
51 | 50 | try { |
52 | 51 | for (;;) { |
53 | 52 | // Wait for the next request. |
@@ -66,12 +65,11 @@ public final class ReverseGeocoder extends Thread { | ||
66 | 65 | } |
67 | 66 | |
68 | 67 | public void flushCache() { |
69 | - mGeoCache.flush(); | |
68 | + sGeoCache.flush(); | |
70 | 69 | } |
71 | 70 | |
72 | 71 | public void shutdown() { |
73 | 72 | flushCache(); |
74 | - mGeoCache.close(); | |
75 | 73 | this.interrupt(); |
76 | 74 | } |
77 | 75 |
@@ -134,8 +132,8 @@ public final class ReverseGeocoder extends Thread { | ||
134 | 132 | } |
135 | 133 | |
136 | 134 | // Just choose one of the localities if within a 50 mile radius. |
137 | - int distance = (int) LocationMediaFilter.toMile( | |
138 | - LocationMediaFilter.distanceBetween(setMinLatitude, setMinLongitude, setMaxLatitude, setMaxLongitude)); | |
135 | + int distance = (int) LocationMediaFilter.toMile(LocationMediaFilter.distanceBetween(setMinLatitude, setMinLongitude, | |
136 | + setMaxLatitude, setMaxLongitude)); | |
139 | 137 | if (distance < MAX_LOCALITY_MILE_RANGE) { |
140 | 138 | // Try each of the points and just return the first one to have a valid address. |
141 | 139 | Address minLatAddress = lookupAddress(setMinLatitude, set.mMinLatLongitude); |
@@ -207,11 +205,11 @@ public final class ReverseGeocoder extends Thread { | ||
207 | 205 | } |
208 | 206 | } |
209 | 207 | } |
210 | - | |
208 | + | |
211 | 209 | if (numDetails == desiredNumDetails) { |
212 | 210 | return location; |
213 | 211 | } |
214 | - | |
212 | + | |
215 | 213 | String locality = addr.getLocality(); |
216 | 214 | if (locality != null && !("null".equals(locality))) { |
217 | 215 | if (location != null && location.length() > 0) { |
@@ -221,11 +219,11 @@ public final class ReverseGeocoder extends Thread { | ||
221 | 219 | } |
222 | 220 | numDetails++; |
223 | 221 | } |
224 | - | |
222 | + | |
225 | 223 | if (numDetails == desiredNumDetails) { |
226 | 224 | return location; |
227 | 225 | } |
228 | - | |
226 | + | |
229 | 227 | String adminArea = addr.getAdminArea(); |
230 | 228 | if (adminArea != null && !("null".equals(adminArea))) { |
231 | 229 | if (location != null && location.length() > 0) { |
@@ -274,7 +272,7 @@ public final class ReverseGeocoder extends Thread { | ||
274 | 272 | private Address lookupAddress(final double latitude, final double longitude) { |
275 | 273 | try { |
276 | 274 | long locationKey = (long) (((latitude + LocationMediaFilter.LAT_MAX) * 2 * LocationMediaFilter.LAT_MAX + (longitude + LocationMediaFilter.LON_MAX)) * LocationMediaFilter.EARTH_RADIUS_METERS); |
277 | - byte[] cachedLocation = mGeoCache.get(locationKey, 0); | |
275 | + byte[] cachedLocation = sGeoCache.get(locationKey, 0); | |
278 | 276 | Address address = null; |
279 | 277 | if (cachedLocation == null || cachedLocation.length == 0) { |
280 | 278 | List<Address> addresses = mGeocoder.getFromLocation(latitude, longitude, 1); |
@@ -305,7 +303,7 @@ public final class ReverseGeocoder extends Thread { | ||
305 | 303 | Utils.writeUTF(dos, address.getUrl()); |
306 | 304 | |
307 | 305 | dos.flush(); |
308 | - mGeoCache.put(locationKey, bos.toByteArray()); | |
306 | + sGeoCache.put(locationKey, bos.toByteArray()); | |
309 | 307 | dos.close(); |
310 | 308 | } |
311 | 309 | } else { |
@@ -325,7 +323,7 @@ public final class ReverseGeocoder extends Thread { | ||
325 | 323 | } |
326 | 324 | } |
327 | 325 | if (!locale.getLanguage().equals(Locale.getDefault().getLanguage())) { |
328 | - mGeoCache.delete(locationKey); | |
326 | + sGeoCache.delete(locationKey); | |
329 | 327 | dis.close(); |
330 | 328 | return lookupAddress(latitude, longitude); |
331 | 329 | } |
@@ -25,7 +25,6 @@ public final class TimeBar extends Layer implements MediaFeed.Listener { | ||
25 | 25 | private static final int MARKER_SPACING_PIXELS = 50; |
26 | 26 | private static final float AUTO_SCROLL_MARGIN = 100f; |
27 | 27 | private static final Paint SRC_PAINT = new Paint(); |
28 | - private final Context mContext; | |
29 | 28 | private Listener mListener = null; |
30 | 29 | private MediaFeed mFeed = null; |
31 | 30 | private float mTotalWidth = 0f; |
@@ -44,7 +43,7 @@ public final class TimeBar extends Layer implements MediaFeed.Listener { | ||
44 | 43 | private final StringTexture.Config mMonthYearFormat = new StringTexture.Config(); |
45 | 44 | private final StringTexture.Config mDayFormat = new StringTexture.Config(); |
46 | 45 | private final SparseArray<StringTexture> mYearLabels = new SparseArray<StringTexture>(); |
47 | - private final StringTexture mDateUnknown; | |
46 | + private StringTexture mDateUnknown; | |
48 | 47 | private final StringTexture[] mMonthLabels = new StringTexture[12]; |
49 | 48 | private final StringTexture[] mDayLabels = new StringTexture[32]; |
50 | 49 | private final StringTexture[] mOpaqueDayLabels = new StringTexture[32]; |
@@ -63,18 +62,22 @@ public final class TimeBar extends Layer implements MediaFeed.Listener { | ||
63 | 62 | } |
64 | 63 | |
65 | 64 | TimeBar(Context context) { |
66 | - // Save the context. | |
67 | - mContext = context; | |
68 | - | |
69 | 65 | // Setup formatting for text labels. |
70 | 66 | mMonthYearFormat.fontSize = 17f * Gallery.PIXEL_DENSITY; |
71 | 67 | mMonthYearFormat.bold = true; |
72 | 68 | mMonthYearFormat.a = 0.85f; |
73 | 69 | mDayFormat.fontSize = 17f * Gallery.PIXEL_DENSITY; |
74 | 70 | mDayFormat.a = 0.61f; |
75 | - | |
71 | + regenerateStringsForContext(context); | |
72 | + Bitmap background = BitmapFactory.decodeResource(context.getResources(), R.drawable.popup); | |
73 | + mBackground = new NinePatch(background, background.getNinePatchChunk(), null); | |
74 | + mBackgroundRect = new Rect(); | |
75 | + SRC_PAINT.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); | |
76 | + } | |
77 | + | |
78 | + public void regenerateStringsForContext(Context context) { | |
76 | 79 | // Create textures for month names. |
77 | - String[] months = mContext.getResources().getStringArray(R.array.months_abbreviated); | |
80 | + String[] months = context.getResources().getStringArray(R.array.months_abbreviated); | |
78 | 81 | for (int i = 0; i < months.length; ++i) { |
79 | 82 | mMonthLabels[i] = new StringTexture(months[i], mMonthYearFormat); |
80 | 83 | } |
@@ -84,10 +87,6 @@ public final class TimeBar extends Layer implements MediaFeed.Listener { | ||
84 | 87 | mOpaqueDayLabels[i] = new StringTexture(Integer.toString(i), mMonthYearFormat); |
85 | 88 | } |
86 | 89 | mDateUnknown = new StringTexture(context.getResources().getString(R.string.date_unknown), mMonthYearFormat); |
87 | - Bitmap background = BitmapFactory.decodeResource(context.getResources(), R.drawable.popup); | |
88 | - mBackground = new NinePatch(background, background.getNinePatchChunk(), null); | |
89 | - mBackgroundRect = new Rect(); | |
90 | - SRC_PAINT.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC)); | |
91 | 90 | } |
92 | 91 | |
93 | 92 | public void setListener(Listener listener) { |
@@ -109,30 +108,6 @@ public final class TimeBar extends Layer implements MediaFeed.Listener { | ||
109 | 108 | mScroll = getScrollForPosition(mPosition); |
110 | 109 | } |
111 | 110 | |
112 | - // public long getTime() { | |
113 | - // final float x = mPosition * mTotalWidth; | |
114 | - // for (int i = 0, size = mMarkers.size(); i < size; ++i) { | |
115 | - // Marker marker = mMarkers.get(i); | |
116 | - // if (x <= marker.x) { | |
117 | - // return marker.time; | |
118 | - // } | |
119 | - // } | |
120 | - // return 0; | |
121 | - // } | |
122 | - // | |
123 | - // public void setTime(long time) { | |
124 | - // synchronized (mMarkers) { | |
125 | - // for (int i = 0, size = mMarkers.size(); i < size; ++i) { | |
126 | - // Marker marker = mMarkers.get(i); | |
127 | - // if (time <= marker.time) { | |
128 | - // mPosition = Math.max(0.0f, Math.min(1.0f, marker.x / mTotalWidth)); | |
129 | - // mScroll = getScrollForPosition(mPosition); | |
130 | - // break; | |
131 | - // } | |
132 | - // } | |
133 | - // } | |
134 | - // } | |
135 | - | |
136 | 111 | public MediaItem getItem() { |
137 | 112 | synchronized (mMarkers) { |
138 | 113 | // x is between 0 and 1.0f |
@@ -257,18 +232,18 @@ public final class TimeBar extends Layer implements MediaFeed.Listener { | ||
257 | 232 | if (month != lastMonth) { |
258 | 233 | lastMonth = month; |
259 | 234 | lastDayBlock = -1; |
260 | - marker = new Marker(mMonthLabels[month], dx, time.getTimeInMillis(), year, month, dayBlock, | |
235 | + marker = new Marker(dx, time.getTimeInMillis(), year, month, dayBlock, | |
261 | 236 | Marker.TYPE_MONTH, increment); |
262 | 237 | dx = addMarker(marker); |
263 | 238 | } else if (dayBlock != lastDayBlock) { |
264 | 239 | lastDayBlock = dayBlock; |
265 | 240 | if (dayBlock != 0) { |
266 | - marker = new Marker(mDayLabels[dayBlock], dx, time.getTimeInMillis(), year, month, dayBlock, | |
241 | + marker = new Marker(dx, time.getTimeInMillis(), year, month, dayBlock, | |
267 | 242 | Marker.TYPE_DAY, increment); |
268 | 243 | dx = addMarker(marker); |
269 | 244 | } |
270 | 245 | } else { |
271 | - marker = new Marker(mDot, dx, time.getTimeInMillis(), year, month, dayBlock, Marker.TYPE_DOT, increment); | |
246 | + marker = new Marker(dx, time.getTimeInMillis(), year, month, dayBlock, Marker.TYPE_DOT, increment); | |
272 | 247 | dx = addMarker(marker); |
273 | 248 | } |
274 | 249 | for (int k = 0; k < increment; ++k) { |
@@ -496,7 +471,7 @@ public final class TimeBar extends Layer implements MediaFeed.Listener { | ||
496 | 471 | } |
497 | 472 | |
498 | 473 | private static final class Marker { |
499 | - Marker(StringTexture texture, float x, long time, int year, int month, int day, int type, int expectedCapacity) { | |
474 | + Marker(float x, long time, int year, int month, int day, int type, int expectedCapacity) { | |
500 | 475 | this.x = x; |
501 | 476 | this.year = year; |
502 | 477 | this.month = month; |
@@ -85,7 +85,7 @@ public class UriTexture extends Texture { | ||
85 | 85 | final BitmapFactory.Options options = new BitmapFactory.Options(); |
86 | 86 | options.inScaled = false; |
87 | 87 | options.inPreferredConfig = Bitmap.Config.RGB_565; |
88 | - options.inDither = true; | |
88 | + options.inDither = false; | |
89 | 89 | long crc64 = 0; |
90 | 90 | Bitmap bitmap = null; |
91 | 91 | if (uri.startsWith(ContentResolver.SCHEME_CONTENT)) { |
@@ -121,7 +121,7 @@ public class UriTexture extends Texture { | ||
121 | 121 | int ratio = Math.max(ratioX, ratioY); |
122 | 122 | ratio = Shared.nextPowerOf2(ratio); |
123 | 123 | sampleSize = ratio; |
124 | - options.inDither = true; | |
124 | + options.inDither = false; | |
125 | 125 | options.inJustDecodeBounds = false; |
126 | 126 | options.inSampleSize = ratio; |
127 | 127 | Thread timeoutThread = new Thread("BitmapTimeoutThread") { |
@@ -207,7 +207,7 @@ public class UriTexture extends Texture { | ||
207 | 207 | final BitmapFactory.Options options = new BitmapFactory.Options(); |
208 | 208 | options.inScaled = false; |
209 | 209 | options.inPreferredConfig = Bitmap.Config.RGB_565; |
210 | - options.inDither = true; | |
210 | + options.inDither = false; | |
211 | 211 | if (crc64 != 0) { |
212 | 212 | file = createFilePathFromCrc64(crc64, maxResolution); |
213 | 213 | try { |
@@ -227,7 +227,7 @@ public class UriTexture extends Texture { | ||
227 | 227 | final BitmapFactory.Options options = new BitmapFactory.Options(); |
228 | 228 | options.inScaled = false; |
229 | 229 | options.inPreferredConfig = Bitmap.Config.RGB_565; |
230 | - options.inDither = true; | |
230 | + options.inDither = false; | |
231 | 231 | if (crc64 != 0) { |
232 | 232 | file = createFilePathFromCrc64(crc64, maxResolution); |
233 | 233 | bitmap = BitmapFactory.decodeFile(file, options); |
@@ -15,7 +15,6 @@ import android.content.Context; | ||
15 | 15 | import android.content.SyncResult; |
16 | 16 | import android.net.Uri; |
17 | 17 | import android.os.Bundle; |
18 | -import android.util.DisplayMetrics; | |
19 | 18 | import android.util.Log; |
20 | 19 | import android.util.Xml; |
21 | 20 |
@@ -30,11 +29,9 @@ public final class PicasaApi { | ||
30 | 29 | |
31 | 30 | static { |
32 | 31 | // Build the base query string using screen dimensions. |
33 | - DisplayMetrics metrics = new DisplayMetrics(); | |
34 | - int maxDimension = Math.max(metrics.widthPixels, metrics.heightPixels); | |
35 | - StringBuilder query = new StringBuilder("?imgmax=1024&max-results=1000&thumbsize="); | |
36 | - String thumbnailSize = metrics.density <= 1 ? "144u," : "144u,"; | |
37 | - String screennailSize = maxDimension <= 512 ? "512u" : "800u"; | |
32 | + final StringBuilder query = new StringBuilder("?imgmax=1024&max-results=1000&thumbsize="); | |
33 | + final String thumbnailSize = "144u,"; | |
34 | + final String screennailSize = "1024u"; | |
38 | 35 | query.append(thumbnailSize); |
39 | 36 | query.append(screennailSize); |
40 | 37 | BASE_QUERY_STRING = query.toString() + "&visibility=visible"; |
@@ -0,0 +1,43 @@ | ||
1 | +package com.cooliris.wallpaper; | |
2 | + | |
3 | +import java.io.IOException; | |
4 | +import java.net.URISyntaxException; | |
5 | + | |
6 | +import com.cooliris.cache.CacheService; | |
7 | +import com.cooliris.cache.ImageList; | |
8 | +import com.cooliris.media.UriTexture; | |
9 | +import com.cooliris.media.Util; | |
10 | + | |
11 | +import android.content.Context; | |
12 | +import android.graphics.Bitmap; | |
13 | + | |
14 | +public class RandomDataSource implements Slideshow.DataSource { | |
15 | + | |
16 | + public Bitmap getBitmapForIndex(Context context, int currentSlideshowCounter) { | |
17 | + ImageList list = CacheService.getImageList(context); | |
18 | + // Once we have the id and the thumbid, we can return a bitmap | |
19 | + // First we select a random numbers | |
20 | + if (list.ids == null) | |
21 | + return null; | |
22 | + double random = Math.random(); | |
23 | + random *= list.ids.length; | |
24 | + int index = (int) random; | |
25 | + long cacheId = list.thumbids[index]; | |
26 | + final String uri = CacheService.BASE_CONTENT_STRING_IMAGES + list.ids[index]; | |
27 | + Bitmap retVal = null; | |
28 | + try { | |
29 | + retVal = UriTexture.createFromUri(context, uri, UriTexture.MAX_RESOLUTION, UriTexture.MAX_RESOLUTION, cacheId, null); | |
30 | + if (retVal != null) { | |
31 | + retVal = Util.rotate(retVal, list.orientation[index]); | |
32 | + } | |
33 | + } catch (OutOfMemoryError e) { | |
34 | + ; | |
35 | + } catch (IOException e) { | |
36 | + ; | |
37 | + } catch (URISyntaxException e) { | |
38 | + ; | |
39 | + } | |
40 | + return retVal; | |
41 | + } | |
42 | + | |
43 | +} |
@@ -0,0 +1,225 @@ | ||
1 | +package com.cooliris.wallpaper; | |
2 | + | |
3 | +//import android.app.Service; | |
4 | +import com.cooliris.media.Vector3f; | |
5 | + | |
6 | +import android.content.Context; | |
7 | +import android.graphics.Bitmap; | |
8 | +import android.graphics.Canvas; | |
9 | +import android.graphics.Color; | |
10 | +import android.graphics.Paint; | |
11 | +import android.graphics.PorterDuffColorFilter; | |
12 | +import android.graphics.Rect; | |
13 | +import android.graphics.RectF; | |
14 | +import android.os.Handler; | |
15 | +import android.os.SystemClock; | |
16 | +import android.view.SurfaceHolder; | |
17 | +import android.view.SurfaceView; | |
18 | +import android.graphics.PorterDuff.Mode; | |
19 | + | |
20 | +public class Slideshow extends SurfaceView implements SurfaceHolder.Callback { | |
21 | + public Slideshow(Context context) { | |
22 | + super(context); | |
23 | + SurfaceHolder holder = getHolder(); | |
24 | + holder.addCallback(this); | |
25 | + } | |
26 | + | |
27 | + public static final int SLIDESHOW_DURATION = 5000; | |
28 | + | |
29 | + public interface DataSource { | |
30 | + /** | |
31 | + * | |
32 | + * @param currentSlideshowCounter | |
33 | + * @return | |
34 | + */ | |
35 | + Bitmap getBitmapForIndex(Context context, int currentSlideshowCounter); | |
36 | + } | |
37 | + | |
38 | + private final Handler mHandler = new Handler(); | |
39 | + private final Runnable mDrawFrame = new Runnable() { | |
40 | + public void run() { | |
41 | + drawFrame(); | |
42 | + } | |
43 | + }; | |
44 | + private static final Paint sPaint = new Paint(); | |
45 | + static { | |
46 | + sPaint.setFilterBitmap(true); | |
47 | + sPaint.setDither(true); | |
48 | + } | |
49 | + private boolean mVisible = true; | |
50 | + private DataSource mSource; | |
51 | + private int mCurrentSlideshowCounter; | |
52 | + private Bitmap mBitmap; | |
53 | + private Rect mRect; | |
54 | + private RectF mFrameRect; | |
55 | + private static final Vector3f sGrow = new Vector3f(); | |
56 | + private Bitmap mQueuedBitmap; | |
57 | + private Rect mQueuedRect; | |
58 | + private RectF mQueuedFrameRect; | |
59 | + private static final Vector3f sQueuedGrow = new Vector3f(); | |
60 | + | |
61 | + private long mPrevTime; | |
62 | + private long mTimeElapsed; | |
63 | + | |
64 | + public void setDataSource(DataSource source) { | |
65 | + mSource = source; | |
66 | + } | |
67 | + | |
68 | + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { | |
69 | + mHandler.post(mDrawFrame); | |
70 | + if (mBitmap != null) { | |
71 | + mRect = getRectToFitBitmap(mBitmap.getWidth(), mBitmap.getHeight(), width, height); | |
72 | + mFrameRect.right = width; | |
73 | + mFrameRect.bottom = height; | |
74 | + } | |
75 | + if (mQueuedBitmap != null) { | |
76 | + mQueuedRect = getRectToFitBitmap(mQueuedBitmap.getWidth(), mQueuedBitmap.getHeight(), width, height); | |
77 | + mQueuedFrameRect.right = width; | |
78 | + mQueuedFrameRect.bottom = height; | |
79 | + } | |
80 | + } | |
81 | + | |
82 | + public void surfaceCreated(SurfaceHolder holder) { | |
83 | + // We may need to make calls to super once this is a subclass of WallpaperService. | |
84 | + mHandler.post(mDrawFrame); | |
85 | + } | |
86 | + | |
87 | + public void surfaceDestroyed(SurfaceHolder holder) { | |
88 | + | |
89 | + } | |
90 | + | |
91 | + public void drawFrame() { | |
92 | + final SurfaceHolder holder = getHolder(); | |
93 | + Rect frame = holder.getSurfaceFrame(); | |
94 | + final Paint paint = sPaint; | |
95 | + Canvas c = null; | |
96 | + try { | |
97 | + c = holder.lockCanvas(); | |
98 | + if (c != null) { | |
99 | + long now = SystemClock.uptimeMillis(); | |
100 | + long delta = now - mPrevTime; | |
101 | + if (delta > 50) | |
102 | + delta = 50; | |
103 | + mTimeElapsed += delta; | |
104 | + mPrevTime = now; | |
105 | + performSetup(frame.width(), frame.height()); | |
106 | + // We draw the source bitmap | |
107 | + if (mBitmap != null) { | |
108 | + if (mTimeElapsed > SLIDESHOW_DURATION) { | |
109 | + float alpha = ((float)(mTimeElapsed - SLIDESHOW_DURATION)) / 2000.0f; | |
110 | + paint.setColorFilter(null); | |
111 | + if (alpha < 1.0f) { | |
112 | + //int val = (int)(255 * (1.0f - alpha)); | |
113 | + //int srcColor = Color.argb(val, 0, 0, 0); | |
114 | + //PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(srcColor, Mode.SRC_IN); | |
115 | + //paint.setColorFilter(null); | |
116 | + } | |
117 | + c.drawBitmap(mBitmap, mRect, mFrameRect, paint); | |
118 | + if (alpha < 1.0f) { | |
119 | + int val = (int)(255 * alpha); | |
120 | + int srcColor = Color.argb(val, 0, 0, 0); | |
121 | + PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(srcColor, Mode.DST_IN); | |
122 | + paint.setColorFilter(colorFilter); | |
123 | + } | |
124 | + | |
125 | + c.drawBitmap(mQueuedBitmap, mQueuedRect, mQueuedFrameRect, paint); | |
126 | + performUpdate(mQueuedFrameRect, sQueuedGrow, delta); | |
127 | + if (alpha >= 1.0f) { | |
128 | + // We switch the image. | |
129 | + mBitmap.recycle(); | |
130 | + mRect = mQueuedRect; | |
131 | + mBitmap = mQueuedBitmap; | |
132 | + mFrameRect = mQueuedFrameRect; | |
133 | + sGrow.set(sQueuedGrow); | |
134 | + mQueuedBitmap = null; | |
135 | + mQueuedRect = null; | |
136 | + mQueuedFrameRect = null; | |
137 | + mTimeElapsed = 0; | |
138 | + } | |
139 | + } else { | |
140 | + paint.setColorFilter(null); | |
141 | + c.drawBitmap(mBitmap, mRect, mFrameRect, paint); | |
142 | + } | |
143 | + performUpdate(mFrameRect, sGrow, delta); | |
144 | + } | |
145 | + | |
146 | + } | |
147 | + } finally { | |
148 | + if (c != null) | |
149 | + holder.unlockCanvasAndPost(c); | |
150 | + } | |
151 | + mHandler.removeCallbacks(mDrawFrame); | |
152 | + if (mVisible) { | |
153 | + mHandler.postDelayed(mDrawFrame, 20); | |
154 | + } | |
155 | + } | |
156 | + | |
157 | + private void performUpdate(RectF rect, Vector3f grow, long delta) { | |
158 | + float timeElapsed = ((float)(delta)) / 1000.0f; | |
159 | + float amountToGrowX = timeElapsed * (rect.width() / 30.0f); | |
160 | + float amountToGrowY = amountToGrowX * (rect.height() / rect.width()); | |
161 | + rect.top -= amountToGrowY * grow.x; | |
162 | + rect.left -= amountToGrowX * grow.y; | |
163 | + | |
164 | + rect.bottom += amountToGrowY * (1 - grow.x); | |
165 | + rect.right += amountToGrowX * (1 - grow.y); | |
166 | + } | |
167 | + | |
168 | + private void performSetup(int viewWidth, int viewHeight) { | |
169 | + if (mBitmap == null) { | |
170 | + mBitmap = getRandomBitmap(); | |
171 | + if (mBitmap != null) { | |
172 | + mRect = getRectToFitBitmap(mBitmap.getWidth(), mBitmap.getHeight(), viewWidth, viewHeight); | |
173 | + mFrameRect = new RectF(); | |
174 | + mFrameRect.right = viewWidth; | |
175 | + mFrameRect.bottom = viewHeight; | |
176 | + sGrow.set((float)Math.random(), (float)Math.random(), 0); | |
177 | + } | |
178 | + } | |
179 | + if (mQueuedBitmap == null) { | |
180 | + mQueuedBitmap = getRandomBitmap(); | |
181 | + if (mQueuedBitmap == null) { | |
182 | + mQueuedBitmap = mBitmap; | |
183 | + } | |
184 | + if (mQueuedBitmap != null) { | |
185 | + mQueuedRect = getRectToFitBitmap(mQueuedBitmap.getWidth(), mQueuedBitmap.getHeight(), viewWidth, viewHeight); | |
186 | + mQueuedFrameRect = new RectF(); | |
187 | + mQueuedFrameRect.right = viewWidth; | |
188 | + mQueuedFrameRect.bottom = viewHeight; | |
189 | + sQueuedGrow.set((float)Math.random(), (float)Math.random(), 0); | |
190 | + } | |
191 | + } | |
192 | + } | |
193 | + | |
194 | + private Rect getRectToFitBitmap(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) { | |
195 | + Rect rect = new Rect(); | |
196 | + float viewAspect = (float)viewHeight / viewWidth; | |
197 | + float newWidth = bitmapWidth * viewAspect; | |
198 | + if (bitmapHeight < newWidth) { | |
199 | + // Vertically constrained. | |
200 | + newWidth = bitmapHeight / viewAspect; | |
201 | + rect.set((int)(bitmapWidth/2 - newWidth/2), 0, (int)(bitmapWidth/2 + newWidth/2), bitmapHeight); | |
202 | + } else { | |
203 | + // Horizontally constrained | |
204 | + float newHeight = bitmapWidth * viewAspect; | |
205 | + rect.set(0, (int)(bitmapHeight/2 - newHeight/2), bitmapWidth, (int)(bitmapHeight/2 + newHeight/2)); | |
206 | + } | |
207 | + return rect; | |
208 | + } | |
209 | + | |
210 | + private Bitmap getRandomBitmap() { | |
211 | + if (mSource != null) { | |
212 | + return mSource.getBitmapForIndex(getContext(), mCurrentSlideshowCounter++); | |
213 | + } | |
214 | + return null; | |
215 | + } | |
216 | + | |
217 | + public void onVisibilityChanged(boolean visible) { | |
218 | + mVisible = visible; | |
219 | + if (!visible) { | |
220 | + mHandler.removeCallbacks(mDrawFrame); | |
221 | + } | |
222 | + drawFrame(); | |
223 | + } | |
224 | + | |
225 | +} |