Updates to 3D gallery. Build 1203.
diff --git a/src.zip b/src.zip
deleted file mode 100644
index ddc6415..0000000
--- a/src.zip
+++ /dev/null
Binary files differ
diff --git a/src/com/cooliris/cache/BootReceiver.java b/src/com/cooliris/cache/BootReceiver.java
index 311f3da..dae5355 100644
--- a/src/com/cooliris/cache/BootReceiver.java
+++ b/src/com/cooliris/cache/BootReceiver.java
@@ -1,19 +1,25 @@
package com.cooliris.cache;
-import com.cooliris.media.Gallery;
+import com.cooliris.media.LocalDataSource;
import com.cooliris.media.SingleDataSource;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
+import android.database.ContentObserver;
import android.net.Uri;
+import android.os.Handler;
+import android.provider.MediaStore.Images;
+import android.provider.MediaStore.Video;
import android.util.Log;
public class BootReceiver extends BroadcastReceiver {
- private static final String TAG = "BootReceiver";
+ private static final String TAG = "BootReceiver";
+ private final Handler mHandler = new Handler();
@Override
- public void onReceive(Context context, Intent intent) {
+ public void onReceive(final Context context, Intent intent) {
final String action = intent.getAction();
Log.i(TAG, "Got intent with action " + action);
if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) {
@@ -29,7 +35,21 @@
CacheService.markDirty(context);
}
} else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
- Gallery.NEEDS_REFRESH = true;
+ // We add special listeners for the MediaProvider
+ final Handler handler = mHandler;
+ final ContentObserver localObserver = new ContentObserver(handler) {
+ public void onChange(boolean selfChange) {
+ if (!LocalDataSource.sObserverActive) {
+ CacheService.senseDirty(context, null);
+ }
+ }
+ };
+ // Start listening perpetually.
+ Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
+ Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
+ ContentResolver cr = context.getContentResolver();
+ cr.registerContentObserver(uriImages, false, localObserver);
+ cr.registerContentObserver(uriVideos, false, localObserver);
}
}
}
diff --git a/src/com/cooliris/cache/CacheService.java b/src/com/cooliris/cache/CacheService.java
index f3e610f..d54f9fa 100644
--- a/src/com/cooliris/cache/CacheService.java
+++ b/src/com/cooliris/cache/CacheService.java
@@ -24,6 +24,7 @@
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
+import android.database.MergeCursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
@@ -53,1026 +54,1153 @@
import com.cooliris.media.Utils;
public final class CacheService extends IntentService {
- public static final String ACTION_CACHE = "com.cooliris.cache.action.CACHE";
- public static final DiskCache sAlbumCache = new DiskCache("local-album-cache");
+ public static final String ACTION_CACHE = "com.cooliris.cache.action.CACHE";
+ public static final DiskCache sAlbumCache = new DiskCache("local-album-cache");
+ public static final DiskCache sMetaAlbumCache = new DiskCache("local-meta-album-cache");
- private static final String TAG = "CacheService";
- private static ImageList sList = null;
+ private static final String TAG = "CacheService";
+ private static ImageList sList = null;
- // Wait 2 seconds to start the thumbnailer so that the application can load without any overheads.
- private static final int THUMBNAILER_WAIT_IN_MS = 2000;
- private static final int DEFAULT_THUMBNAIL_WIDTH = 128;
- private static final int DEFAULT_THUMBNAIL_HEIGHT = 96;
+ // Wait 2 seconds to start the thumbnailer so that the application can load
+ // without any overheads.
+ private static final int THUMBNAILER_WAIT_IN_MS = 2000;
+ private static final int DEFAULT_THUMBNAIL_WIDTH = 128;
+ private static final int DEFAULT_THUMBNAIL_HEIGHT = 96;
- public static final String DEFAULT_IMAGE_SORT_ORDER = Images.ImageColumns.DATE_TAKEN + " ASC, "
- + Images.ImageColumns.DATE_ADDED + " ASC";
- public static final String DEFAULT_VIDEO_SORT_ORDER = Video.VideoColumns.DATE_TAKEN + " ASC, " + Video.VideoColumns.DATE_ADDED
- + " ASC";
- public static final String DEFAULT_BUCKET_SORT_ORDER = "upper(" + Images.ImageColumns.BUCKET_DISPLAY_NAME + ") ASC";
+ public static final String DEFAULT_IMAGE_SORT_ORDER = Images.ImageColumns.DATE_TAKEN + " ASC, "
+ + Images.ImageColumns.DATE_ADDED + " ASC";
+ public static final String DEFAULT_VIDEO_SORT_ORDER = Video.VideoColumns.DATE_TAKEN + " ASC, " + Video.VideoColumns.DATE_ADDED
+ + " ASC";
+ public static final String DEFAULT_BUCKET_SORT_ORDER = "upper(" + Images.ImageColumns.BUCKET_DISPLAY_NAME + ") ASC";
- // Must preserve order between these indices and the order of the terms in BUCKET_PROJECTION_IMAGES, BUCKET_PROJECTION_VIDEOS.
- // Not using SortedHashMap for efficieny reasons.
- public static final int BUCKET_ID_INDEX = 0;
- public static final int BUCKET_NAME_INDEX = 1;
- public static final String[] BUCKET_PROJECTION_IMAGES = new String[] { Images.ImageColumns.BUCKET_ID,
- Images.ImageColumns.BUCKET_DISPLAY_NAME };
+ // Must preserve order between these indices and the order of the terms in
+ // BUCKET_PROJECTION_IMAGES, BUCKET_PROJECTION_VIDEOS.
+ // Not using SortedHashMap for efficieny reasons.
+ public static final int BUCKET_ID_INDEX = 0;
+ public static final int BUCKET_NAME_INDEX = 1;
+ public static final String[] BUCKET_PROJECTION_IMAGES = new String[] { Images.ImageColumns.BUCKET_ID,
+ Images.ImageColumns.BUCKET_DISPLAY_NAME };
- public static final String[] BUCKET_PROJECTION_VIDEOS = new String[] { Video.VideoColumns.BUCKET_ID,
- Video.VideoColumns.BUCKET_DISPLAY_NAME };
+ public static final String[] BUCKET_PROJECTION_VIDEOS = new String[] { Video.VideoColumns.BUCKET_ID,
+ Video.VideoColumns.BUCKET_DISPLAY_NAME };
- // Must preserve order between these indices and the order of the terms in THUMBNAIL_PROJECTION.
- public static final int THUMBNAIL_ID_INDEX = 0;
- public static final int THUMBNAIL_DATE_MODIFIED_INDEX = 1;
- public static final int THUMBNAIL_DATA_INDEX = 2;
- public static final int THUMBNAIL_ORIENTATION_INDEX = 2;
- public static final String[] THUMBNAIL_PROJECTION = new String[] { Images.ImageColumns._ID, Images.ImageColumns.DATE_MODIFIED,
- Images.ImageColumns.DATA, Images.ImageColumns.ORIENTATION };
+ // Must preserve order between these indices and the order of the terms in
+ // THUMBNAIL_PROJECTION.
+ public static final int THUMBNAIL_ID_INDEX = 0;
+ public static final int THUMBNAIL_DATE_MODIFIED_INDEX = 1;
+ public static final int THUMBNAIL_DATA_INDEX = 2;
+ public static final int THUMBNAIL_ORIENTATION_INDEX = 2;
+ public static final String[] THUMBNAIL_PROJECTION = new String[] { Images.ImageColumns._ID, Images.ImageColumns.DATE_MODIFIED,
+ Images.ImageColumns.DATA, Images.ImageColumns.ORIENTATION };
- // Must preserve order between these indices and the order of the terms in INITIAL_PROJECTION_IMAGES and
- // INITIAL_PROJECTION_VIDEOS.
- public static final int MEDIA_ID_INDEX = 0;
- public static final int MEDIA_CAPTION_INDEX = 1;
- public static final int MEDIA_MIME_TYPE_INDEX = 2;
- public static final int MEDIA_LATITUDE_INDEX = 3;
- public static final int MEDIA_LONGITUDE_INDEX = 4;
- public static final int MEDIA_DATE_TAKEN_INDEX = 5;
- public static final int MEDIA_DATE_ADDED_INDEX = 6;
- public static final int MEDIA_DATE_MODIFIED_INDEX = 7;
- public static final int MEDIA_DATA_INDEX = 8;
- public static final int MEDIA_ORIENTATION_OR_DURATION_INDEX = 9;
- public static final int MEDIA_BUCKET_ID_INDEX = 10;
- public static final String[] PROJECTION_IMAGES = new String[] { Images.ImageColumns._ID, Images.ImageColumns.TITLE,
- Images.ImageColumns.MIME_TYPE, Images.ImageColumns.LATITUDE, Images.ImageColumns.LONGITUDE,
- Images.ImageColumns.DATE_TAKEN, Images.ImageColumns.DATE_ADDED, Images.ImageColumns.DATE_MODIFIED,
- Images.ImageColumns.DATA, Images.ImageColumns.ORIENTATION, Images.ImageColumns.BUCKET_ID };
+ public static final String[] SENSE_PROJECTION = new String[] { Images.ImageColumns.BUCKET_ID,
+ "MAX(" + Images.ImageColumns.DATE_ADDED + ")" };
- private static final String[] PROJECTION_VIDEOS = new String[] { Video.VideoColumns._ID, Video.VideoColumns.TITLE,
- Video.VideoColumns.MIME_TYPE, Video.VideoColumns.LATITUDE, Video.VideoColumns.LONGITUDE, Video.VideoColumns.DATE_TAKEN,
- Video.VideoColumns.DATE_ADDED, Video.VideoColumns.DATE_MODIFIED, Video.VideoColumns.DATA, Video.VideoColumns.DURATION,
- Video.VideoColumns.BUCKET_ID };
+ // Must preserve order between these indices and the order of the terms in
+ // INITIAL_PROJECTION_IMAGES and
+ // INITIAL_PROJECTION_VIDEOS.
+ public static final int MEDIA_ID_INDEX = 0;
+ public static final int MEDIA_CAPTION_INDEX = 1;
+ public static final int MEDIA_MIME_TYPE_INDEX = 2;
+ public static final int MEDIA_LATITUDE_INDEX = 3;
+ public static final int MEDIA_LONGITUDE_INDEX = 4;
+ public static final int MEDIA_DATE_TAKEN_INDEX = 5;
+ public static final int MEDIA_DATE_ADDED_INDEX = 6;
+ public static final int MEDIA_DATE_MODIFIED_INDEX = 7;
+ public static final int MEDIA_DATA_INDEX = 8;
+ public static final int MEDIA_ORIENTATION_OR_DURATION_INDEX = 9;
+ public static final int MEDIA_BUCKET_ID_INDEX = 10;
+ public static final String[] PROJECTION_IMAGES = new String[] { Images.ImageColumns._ID, Images.ImageColumns.TITLE,
+ Images.ImageColumns.MIME_TYPE, Images.ImageColumns.LATITUDE, Images.ImageColumns.LONGITUDE,
+ Images.ImageColumns.DATE_TAKEN, Images.ImageColumns.DATE_ADDED, Images.ImageColumns.DATE_MODIFIED,
+ Images.ImageColumns.DATA, Images.ImageColumns.ORIENTATION, Images.ImageColumns.BUCKET_ID };
- public static final String BASE_CONTENT_STRING_IMAGES = (Images.Media.EXTERNAL_CONTENT_URI).toString() + "/";
- public static final String BASE_CONTENT_STRING_VIDEOS = (Video.Media.EXTERNAL_CONTENT_URI).toString() + "/";
- private static final AtomicReference<Thread> CACHE_THREAD = new AtomicReference<Thread>();
- private static final AtomicReference<Thread> THUMBNAIL_THREAD = new AtomicReference<Thread>();
+ private static final String[] PROJECTION_VIDEOS = new String[] { Video.VideoColumns._ID, Video.VideoColumns.TITLE,
+ Video.VideoColumns.MIME_TYPE, Video.VideoColumns.LATITUDE, Video.VideoColumns.LONGITUDE, Video.VideoColumns.DATE_TAKEN,
+ Video.VideoColumns.DATE_ADDED, Video.VideoColumns.DATE_MODIFIED, Video.VideoColumns.DATA, Video.VideoColumns.DURATION,
+ Video.VideoColumns.BUCKET_ID };
- // Special indices in the Albumcache.
- private static final int ALBUM_CACHE_METADATA_INDEX = -1;
- private static final int ALBUM_CACHE_DIRTY_INDEX = -2;
- private static final int ALBUM_CACHE_INCOMPLETE_INDEX = -3;
- private static final int ALBUM_CACHE_DIRTY_BUCKET_INDEX = -4;
- private static final int ALBUM_CACHE_LOCALE_INDEX = -5;
+ public static final String BASE_CONTENT_STRING_IMAGES = (Images.Media.EXTERNAL_CONTENT_URI).toString() + "/";
+ public static final String BASE_CONTENT_STRING_VIDEOS = (Video.Media.EXTERNAL_CONTENT_URI).toString() + "/";
+ private static final AtomicReference<Thread> CACHE_THREAD = new AtomicReference<Thread>();
+ private static final AtomicReference<Thread> THUMBNAIL_THREAD = new AtomicReference<Thread>();
- private static final DateFormat mDateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
- private static final DateFormat mAltDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
- private static final byte[] sDummyData = new byte[] { 1 };
- private static boolean QUEUE_DIRTY_SET;
- private static boolean QUEUE_DIRTY_ALL;
+ // Special indices in the Albumcache.
+ private static final int ALBUM_CACHE_METADATA_INDEX = -1;
+ private static final int ALBUM_CACHE_DIRTY_INDEX = -2;
+ private static final int ALBUM_CACHE_INCOMPLETE_INDEX = -3;
+ private static final int ALBUM_CACHE_DIRTY_BUCKET_INDEX = -4;
+ private static final int ALBUM_CACHE_LOCALE_INDEX = -5;
- public static final String getCachePath(final String subFolderName) {
- return Environment.getExternalStorageDirectory() + "/Android/data/com.cooliris.media/cache/" + subFolderName;
- }
+ private static final DateFormat mDateFormat = new SimpleDateFormat("yyyy:MM:dd HH:mm:ss");
+ private static final DateFormat mAltDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ private static final byte[] sDummyData = new byte[] { 1 };
+ private static boolean QUEUE_DIRTY_SET;
+ private static boolean QUEUE_DIRTY_ALL;
+ private static boolean QUEUE_DIRTY_SENSE;
- public static final void startCache(final Context context, final boolean checkthumbnails) {
- final Locale locale = getLocaleForAlbumCache();
- final Locale defaultLocale = Locale.getDefault();
- if (locale == null || !locale.equals(defaultLocale)) {
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(defaultLocale);
- }
- final Intent intent = new Intent(ACTION_CACHE, null, context, CacheService.class);
- intent.putExtra("checkthumbnails", checkthumbnails);
- context.startService(intent);
- }
+ public interface Observer {
+ void onChange(long[] bucketIds);
+ }
- public static final boolean isCacheReady(final boolean onlyMediaSets) {
- if (onlyMediaSets) {
- return (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null && sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0) == null);
- } else {
- return (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null && sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0) == null && sAlbumCache
- .get(ALBUM_CACHE_INCOMPLETE_INDEX, 0) == null);
- }
- }
+ public static final String getCachePath(final String subFolderName) {
+ return Environment.getExternalStorageDirectory() + "/Android/data/com.cooliris.media/cache/" + subFolderName;
+ }
- public static final boolean isCacheReady(final long setId) {
- final boolean isReady = (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null
- && sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0) == null && sAlbumCache.get(ALBUM_CACHE_INCOMPLETE_INDEX, 0) == null);
- if (!isReady) {
- return isReady;
- }
- // Also, we need to check if this setId is dirty.
- final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0);
- if (existingData != null && existingData.length > 0) {
- final long[] ids = toLongArray(existingData);
- final int numIds = ids.length;
- for (int i = 0; i < numIds; ++i) {
- if (ids[i] == setId) {
- return false;
- }
- }
- }
- return true;
- }
+ public static final void startCache(final Context context, final boolean checkthumbnails) {
+ final Locale locale = getLocaleForAlbumCache();
+ final Locale defaultLocale = Locale.getDefault();
+ if (locale == null || !locale.equals(defaultLocale)) {
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(defaultLocale);
+ }
+ final Intent intent = new Intent(ACTION_CACHE, null, context, CacheService.class);
+ intent.putExtra("checkthumbnails", checkthumbnails);
+ context.startService(intent);
+ }
- public static final boolean isPresentInCache(final long setId) {
- return sAlbumCache.get(setId, 0) != null;
- }
+ public static final boolean isCacheReady(final boolean onlyMediaSets) {
+ if (onlyMediaSets) {
+ return (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null && sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0) == null);
+ } else {
+ return (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null && sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0) == null && sAlbumCache
+ .get(ALBUM_CACHE_INCOMPLETE_INDEX, 0) == null);
+ }
+ }
- public static final void markDirty(final Context context) {
- sList = null;
- sAlbumCache.put(ALBUM_CACHE_DIRTY_INDEX, sDummyData);
- if (CACHE_THREAD.get() == null) {
- restartThread(CACHE_THREAD, "CacheRefresh", new Runnable() {
- public void run() {
- refresh(context);
- }
- });
- } else {
- QUEUE_DIRTY_ALL = true;
- }
- }
+ public static final boolean isCacheReady(final long setId) {
+ final boolean isReady = (sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0) != null
+ && sAlbumCache.get(ALBUM_CACHE_DIRTY_INDEX, 0) == null && sAlbumCache.get(ALBUM_CACHE_INCOMPLETE_INDEX, 0) == null);
+ if (!isReady) {
+ return isReady;
+ }
+ // Also, we need to check if this setId is dirty.
+ final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0);
+ if (existingData != null && existingData.length > 0) {
+ final long[] ids = toLongArray(existingData);
+ final int numIds = ids.length;
+ for (int i = 0; i < numIds; ++i) {
+ if (ids[i] == setId) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
- public static final void markDirtyImmediate(final long id) {
- sList = null;
- byte[] data = longToByteArray(id);
- final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0);
- if (existingData != null && existingData.length > 0) {
- final long[] ids = toLongArray(existingData);
- final int numIds = ids.length;
- for (int i = 0; i < numIds; ++i) {
- if (ids[i] == id) {
- return;
- }
- }
- // Add this to the existing keys and concatenate the byte arrays.
- data = concat(data, existingData);
- }
- sAlbumCache.put(ALBUM_CACHE_DIRTY_BUCKET_INDEX, data);
- }
+ public static final boolean isPresentInCache(final long setId) {
+ return sAlbumCache.get(setId, 0) != null;
+ }
- public static final void markDirty(final Context context, final long id) {
- markDirtyImmediate(id);
- if (CACHE_THREAD.get() == null) {
- restartThread(CACHE_THREAD, "CacheRefreshDirtySets", new Runnable() {
- public void run() {
- refreshDirtySets(context);
- }
- });
- } else {
- QUEUE_DIRTY_SET = true;
- }
- }
+ public static final void senseDirty(final Context context, final Observer observer) {
+ if (CACHE_THREAD.get() == null) {
+ QUEUE_DIRTY_SENSE = false;
+ QUEUE_DIRTY_ALL = false;
+ QUEUE_DIRTY_SET = false;
+ restartThread(CACHE_THREAD, "CacheRefresh", new Runnable() {
+ public void run() {
+ Log.i(TAG, "Computing dirty sets.");
+ long ids[] = computeDirtySets(context);
+ if (ids != null && observer != null) {
+ observer.onChange(ids);
+ }
+ if (ids.length > 0) {
+ sList = null;
+ }
+ Log.i(TAG, "Done computing dirty sets for num " + ids.length);
+ }
+ });
+ } else {
+ QUEUE_DIRTY_SENSE = true;
+ }
+ }
- public static final boolean setHasItems(final ContentResolver cr, final long setId) {
- final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
- final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
- final StringBuffer whereString = new StringBuffer(Images.ImageColumns.BUCKET_ID + "=" + setId);
- final Cursor cursorImages = cr.query(uriImages, BUCKET_PROJECTION_IMAGES, whereString.toString(), null, null);
- if (cursorImages != null && cursorImages.getCount() > 0) {
- cursorImages.close();
- return true;
- }
- final Cursor cursorVideos = cr.query(uriVideos, BUCKET_PROJECTION_VIDEOS, whereString.toString(), null, null);
- if (cursorVideos != null && cursorVideos.getCount() > 0) {
- cursorVideos.close();
- return true;
- }
- return false;
- }
+ public static final void markDirty(final Context context) {
+ sList = null;
+ sAlbumCache.put(ALBUM_CACHE_DIRTY_INDEX, sDummyData);
+ if (CACHE_THREAD.get() == null) {
+ QUEUE_DIRTY_SENSE = false;
+ QUEUE_DIRTY_ALL = false;
+ QUEUE_DIRTY_SET = false;
+ restartThread(CACHE_THREAD, "CacheRefresh", new Runnable() {
+ public void run() {
+ refresh(context);
+ }
+ });
+ } else {
+ QUEUE_DIRTY_ALL = true;
+ }
+ }
- public static final void loadMediaSets(final MediaFeed feed, final DataSource source, final boolean includeImages,
- final boolean includeVideos) {
- int timeElapsed = 0;
- while (!isCacheReady(true) && timeElapsed < 10000) {
- try {
- Thread.sleep(300);
- } catch (InterruptedException e) {
- return;
- }
- timeElapsed += 300;
- }
- final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0);
- if (albumData != null && albumData.length > 0) {
- final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
- try {
- final int numAlbums = dis.readInt();
- Log.i(TAG, "Loading " + numAlbums + " albums.");
- for (int i = 0; i < numAlbums; ++i) {
- final long setId = dis.readLong();
- final String name = Utils.readUTF(dis);
- final boolean hasImages = dis.readBoolean();
- final boolean hasVideos = dis.readBoolean();
- MediaSet mediaSet = feed.getMediaSet(setId);
- if (mediaSet == null) {
- mediaSet = feed.addMediaSet(setId, source);
- }
- if ((includeImages && hasImages) || (includeVideos && hasVideos)) {
- mediaSet.mName = name;
- mediaSet.mHasImages = hasImages;
- mediaSet.mHasVideos = hasVideos;
- mediaSet.mPicasaAlbumId = Shared.INVALID;
- mediaSet.generateTitle(true);
- }
- }
- } catch (IOException e) {
- Log.e(TAG, "Error loading albums.");
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
- }
- } else {
- Log.d(TAG, "No albums found.");
- }
- }
+ public static final void markDirtyImmediate(final long id) {
+ if (id == Shared.INVALID) {
+ return;
+ }
+ sList = null;
+ byte[] data = longToByteArray(id);
+ final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0);
+ if (existingData != null && existingData.length > 0) {
+ final long[] ids = toLongArray(existingData);
+ final int numIds = ids.length;
+ for (int i = 0; i < numIds; ++i) {
+ if (ids[i] == id) {
+ return;
+ }
+ }
+ // Add this to the existing keys and concatenate the byte arrays.
+ data = concat(data, existingData);
+ }
+ sAlbumCache.put(ALBUM_CACHE_DIRTY_BUCKET_INDEX, data);
+ }
- public static final void loadMediaSet(final MediaFeed feed, final DataSource source, final long bucketId) {
- int timeElapsed = 0;
- while (!isCacheReady(false) && timeElapsed < 10000) {
- try {
- Thread.sleep(300);
- } catch (InterruptedException e) {
- return;
- }
- timeElapsed += 300;
- }
- final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0);
- if (albumData != null && albumData.length > 0) {
- DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
- try {
- final int numAlbums = dis.readInt();
- for (int i = 0; i < numAlbums; ++i) {
- final long setId = dis.readLong();
- MediaSet mediaSet = null;
- if (setId == bucketId) {
- mediaSet = feed.getMediaSet(setId);
- if (mediaSet == null) {
- mediaSet = feed.addMediaSet(setId, source);
- }
- } else {
- mediaSet = new MediaSet();
- }
- mediaSet.mName = Utils.readUTF(dis);
- if (setId == bucketId) {
- mediaSet.mPicasaAlbumId = Shared.INVALID;
- mediaSet.generateTitle(true);
- return;
- }
- }
- } catch (IOException e) {
- Log.e(TAG, "Error finding album " + bucketId);
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
- }
- } else {
- Log.d(TAG, "No album found for album id " + bucketId);
- }
- }
+ public static final void markDirty(final Context context, final long id) {
+ markDirtyImmediate(id);
+ if (CACHE_THREAD.get() == null) {
+ QUEUE_DIRTY_SET = false;
+ restartThread(CACHE_THREAD, "CacheRefreshDirtySets", new Runnable() {
+ public void run() {
+ refreshDirtySets(context);
+ }
+ });
+ } else {
+ QUEUE_DIRTY_SET = true;
+ }
+ }
- public static final void loadMediaItemsIntoMediaFeed(final MediaFeed feed, final MediaSet set, final int rangeStart,
- final int rangeEnd, final boolean includeImages, final boolean includeVideos) {
- int timeElapsed = 0;
- byte[] albumData = null;
- while (!isCacheReady(set.mId) && timeElapsed < 30000) {
- try {
- Thread.sleep(300);
- } catch (InterruptedException e) {
- return;
- }
- timeElapsed += 300;
- }
- albumData = sAlbumCache.get(set.mId, 0);
- if (albumData != null && set.mNumItemsLoaded < set.getNumExpectedItems()) {
- final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
- try {
- final int numItems = dis.readInt();
- Log.i(TAG, "Loading Set Id " + set.mId + " with " + numItems + " items.");
- set.setNumExpectedItems(numItems);
- set.mMinTimestamp = dis.readLong();
- set.mMaxTimestamp = dis.readLong();
- for (int i = 0; i < numItems; ++i) {
- final MediaItem item = new MediaItem();
- // Must preserve order with method that writes to cache.
- item.mId = dis.readLong();
- item.mCaption = Utils.readUTF(dis);
- item.mMimeType = Utils.readUTF(dis);
- item.setMediaType(dis.readInt());
- item.mLatitude = dis.readDouble();
- item.mLongitude = dis.readDouble();
- item.mDateTakenInMs = dis.readLong();
- item.mTriedRetrievingExifDateTaken = dis.readBoolean();
- item.mDateAddedInSec = dis.readLong();
- item.mDateModifiedInSec = dis.readLong();
- item.mDurationInSec = dis.readInt();
- item.mRotation = (float) dis.readInt();
- item.mFilePath = Utils.readUTF(dis);
- int itemMediaType = item.getMediaType();
- if ((itemMediaType == MediaItem.MEDIA_TYPE_IMAGE && includeImages)
- || (itemMediaType == MediaItem.MEDIA_TYPE_VIDEO && includeVideos)) {
- String baseUri = (itemMediaType == MediaItem.MEDIA_TYPE_IMAGE) ? BASE_CONTENT_STRING_IMAGES
- : BASE_CONTENT_STRING_VIDEOS;
- item.mContentUri = baseUri + item.mId;
- feed.addItemToMediaSet(item, set);
- }
- }
- dis.close();
- } catch (IOException e) {
- Log.e(TAG, "Error loading items for album " + set.mName);
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
- }
- } else {
- Log.d(TAG, "No items found for album " + set.mName);
- }
- set.updateNumExpectedItems();
- set.generateTitle(true);
- }
+ public static final boolean setHasItems(final ContentResolver cr, final long setId) {
+ final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
+ final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
+ final StringBuffer whereString = new StringBuffer(Images.ImageColumns.BUCKET_ID + "=" + setId);
+ final Cursor cursorImages = cr.query(uriImages, BUCKET_PROJECTION_IMAGES, whereString.toString(), null, null);
+ if (cursorImages != null && cursorImages.getCount() > 0) {
+ cursorImages.close();
+ return true;
+ }
+ final Cursor cursorVideos = cr.query(uriVideos, BUCKET_PROJECTION_VIDEOS, whereString.toString(), null, null);
+ if (cursorVideos != null && cursorVideos.getCount() > 0) {
+ cursorVideos.close();
+ return true;
+ }
+ return false;
+ }
- public static final void populateVideoItemFromCursor(final MediaItem item, final ContentResolver cr, final Cursor cursor,
- final String baseUri) {
- item.setMediaType(MediaItem.MEDIA_TYPE_VIDEO);
- populateMediaItemFromCursor(item, cr, cursor, baseUri);
- }
+ public static final void loadMediaSets(final MediaFeed feed, final DataSource source, final boolean includeImages,
+ final boolean includeVideos) {
+ int timeElapsed = 0;
+ while (!isCacheReady(true) && timeElapsed < 10000) {
+ try {
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+ return;
+ }
+ timeElapsed += 300;
+ }
+ final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0);
+ if (albumData != null && albumData.length > 0) {
+ final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
+ try {
+ final int numAlbums = dis.readInt();
+ for (int i = 0; i < numAlbums; ++i) {
+ final long setId = dis.readLong();
+ final String name = Utils.readUTF(dis);
+ final boolean hasImages = dis.readBoolean();
+ final boolean hasVideos = dis.readBoolean();
+ MediaSet mediaSet = feed.getMediaSet(setId);
+ if (mediaSet == null) {
+ mediaSet = feed.addMediaSet(setId, source);
+ }
+ if ((includeImages && hasImages) || (includeVideos && hasVideos)) {
+ mediaSet.mName = name;
+ mediaSet.mHasImages = hasImages;
+ mediaSet.mHasVideos = hasVideos;
+ mediaSet.mPicasaAlbumId = Shared.INVALID;
+ mediaSet.generateTitle(true);
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error loading albums.");
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+ }
+ } else {
+ Log.d(TAG, "No albums found.");
+ }
+ }
- public static final void populateMediaItemFromCursor(final MediaItem item, final ContentResolver cr, final Cursor cursor,
- final String baseUri) {
- item.mId = cursor.getLong(CacheService.MEDIA_ID_INDEX);
- // item.mCaption = cursor.getString(CacheService.MEDIA_CAPTION_INDEX);
- item.mMimeType = cursor.getString(CacheService.MEDIA_MIME_TYPE_INDEX);
- item.mLatitude = cursor.getDouble(CacheService.MEDIA_LATITUDE_INDEX);
- item.mLongitude = cursor.getDouble(CacheService.MEDIA_LONGITUDE_INDEX);
- item.mDateTakenInMs = cursor.getLong(CacheService.MEDIA_DATE_TAKEN_INDEX);
- item.mDateAddedInSec = cursor.getLong(CacheService.MEDIA_DATE_ADDED_INDEX);
- item.mDateModifiedInSec = cursor.getLong(CacheService.MEDIA_DATE_MODIFIED_INDEX);
- if (item.mDateTakenInMs == item.mDateModifiedInSec) {
- item.mDateTakenInMs = item.mDateModifiedInSec * 1000;
- }
- item.mFilePath = cursor.getString(CacheService.MEDIA_DATA_INDEX);
- if (baseUri != null)
- item.mContentUri = baseUri + item.mId;
- final int itemMediaType = item.getMediaType();
- // Check to see if a new date taken is available.
- final long dateTaken = fetchDateTaken(item);
- if (dateTaken != -1L && item.mContentUri != null) {
- item.mDateTakenInMs = dateTaken;
- final ContentValues values = new ContentValues();
- if (itemMediaType == MediaItem.MEDIA_TYPE_VIDEO) {
- values.put(Video.VideoColumns.DATE_TAKEN, item.mDateTakenInMs);
- } else {
- values.put(Images.ImageColumns.DATE_TAKEN, item.mDateTakenInMs);
- }
- cr.update(Uri.parse(item.mContentUri), values, null, null);
- }
+ public static final void loadMediaSet(final MediaFeed feed, final DataSource source, final long bucketId) {
+ int timeElapsed = 0;
+ while (!isCacheReady(false) && timeElapsed < 10000) {
+ try {
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+ return;
+ }
+ timeElapsed += 300;
+ }
+ final byte[] albumData = sAlbumCache.get(ALBUM_CACHE_METADATA_INDEX, 0);
+ if (albumData != null && albumData.length > 0) {
+ DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
+ try {
+ final int numAlbums = dis.readInt();
+ for (int i = 0; i < numAlbums; ++i) {
+ final long setId = dis.readLong();
+ MediaSet mediaSet = null;
+ if (setId == bucketId) {
+ mediaSet = feed.getMediaSet(setId);
+ if (mediaSet == null) {
+ mediaSet = feed.addMediaSet(setId, source);
+ }
+ } else {
+ mediaSet = new MediaSet();
+ }
+ mediaSet.mName = Utils.readUTF(dis);
+ if (setId == bucketId) {
+ mediaSet.mPicasaAlbumId = Shared.INVALID;
+ mediaSet.generateTitle(true);
+ return;
+ }
+ }
+ } catch (IOException e) {
+ Log.e(TAG, "Error finding album " + bucketId);
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+ }
+ } else {
+ Log.d(TAG, "No album found for album id " + bucketId);
+ }
+ }
- final int orientationDurationValue = cursor.getInt(CacheService.MEDIA_ORIENTATION_OR_DURATION_INDEX);
- if (itemMediaType == MediaItem.MEDIA_TYPE_IMAGE) {
- item.mRotation = orientationDurationValue;
- } else {
- item.mDurationInSec = orientationDurationValue;
- }
- }
+ public static final void loadMediaItemsIntoMediaFeed(final MediaFeed feed, final MediaSet set, final int rangeStart,
+ final int rangeEnd, final boolean includeImages, final boolean includeVideos) {
+ int timeElapsed = 0;
+ byte[] albumData = null;
+ while (!isCacheReady(set.mId) && timeElapsed < 30000) {
+ try {
+ Thread.sleep(300);
+ } catch (InterruptedException e) {
+ return;
+ }
+ timeElapsed += 300;
+ }
+ albumData = sAlbumCache.get(set.mId, 0);
+ if (albumData != null && set.mNumItemsLoaded < set.getNumExpectedItems()) {
+ final DataInputStream dis = new DataInputStream(new BufferedInputStream(new ByteArrayInputStream(albumData), 256));
+ try {
+ final int numItems = dis.readInt();
+ set.setNumExpectedItems(numItems);
+ set.mMinTimestamp = dis.readLong();
+ set.mMaxTimestamp = dis.readLong();
+ for (int i = 0; i < numItems; ++i) {
+ final MediaItem item = new MediaItem();
+ // Must preserve order with method that writes to cache.
+ item.mId = dis.readLong();
+ item.mCaption = Utils.readUTF(dis);
+ item.mMimeType = Utils.readUTF(dis);
+ item.setMediaType(dis.readInt());
+ item.mLatitude = dis.readDouble();
+ item.mLongitude = dis.readDouble();
+ item.mDateTakenInMs = dis.readLong();
+ item.mTriedRetrievingExifDateTaken = dis.readBoolean();
+ item.mDateAddedInSec = dis.readLong();
+ item.mDateModifiedInSec = dis.readLong();
+ item.mDurationInSec = dis.readInt();
+ item.mRotation = (float) dis.readInt();
+ item.mFilePath = Utils.readUTF(dis);
+ int itemMediaType = item.getMediaType();
+ if ((itemMediaType == MediaItem.MEDIA_TYPE_IMAGE && includeImages)
+ || (itemMediaType == MediaItem.MEDIA_TYPE_VIDEO && includeVideos)) {
+ String baseUri = (itemMediaType == MediaItem.MEDIA_TYPE_IMAGE) ? BASE_CONTENT_STRING_IMAGES
+ : BASE_CONTENT_STRING_VIDEOS;
+ item.mContentUri = baseUri + item.mId;
+ feed.addItemToMediaSet(item, set);
+ }
+ }
+ dis.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Error loading items for album " + set.mName);
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+ }
+ } else {
+ Log.d(TAG, "No items found for album " + set.mName);
+ }
+ set.updateNumExpectedItems();
+ set.generateTitle(true);
+ }
- // Returns -1 if we failed to examine EXIF information or EXIF parsing failed.
- public static final long fetchDateTaken(final MediaItem item) {
- if (!item.isDateTakenValid() && !item.mTriedRetrievingExifDateTaken
- && (item.mFilePath.endsWith(".jpg") || item.mFilePath.endsWith(".jpeg"))) {
- try {
- Log.i(TAG, "Parsing date taken from exif");
- final ExifInterface exif = new ExifInterface(item.mFilePath);
- final String dateTakenStr = exif.getAttribute(ExifInterface.TAG_DATETIME);
- if (dateTakenStr != null) {
- try {
- final Date dateTaken = mDateFormat.parse(dateTakenStr);
- return dateTaken.getTime();
- } catch (ParseException pe) {
- try {
- final Date dateTaken = mAltDateFormat.parse(dateTakenStr);
- return dateTaken.getTime();
- } catch (ParseException pe2) {
- Log.i(TAG, "Unable to parse date out of string - " + dateTakenStr);
- }
- }
- }
- } catch (Exception e) {
- Log.i(TAG, "Error reading Exif information, probably not a jpeg.");
- }
+ public static final void populateVideoItemFromCursor(final MediaItem item, final ContentResolver cr, final Cursor cursor,
+ final String baseUri) {
+ item.setMediaType(MediaItem.MEDIA_TYPE_VIDEO);
+ populateMediaItemFromCursor(item, cr, cursor, baseUri);
+ }
- // Ensures that we only try retrieving EXIF date taken once.
- item.mTriedRetrievingExifDateTaken = true;
- }
- return -1L;
- }
+ public static final void populateMediaItemFromCursor(final MediaItem item, final ContentResolver cr, final Cursor cursor,
+ final String baseUri) {
+ item.mId = cursor.getLong(CacheService.MEDIA_ID_INDEX);
+ item.mCaption = cursor.getString(CacheService.MEDIA_CAPTION_INDEX);
+ item.mMimeType = cursor.getString(CacheService.MEDIA_MIME_TYPE_INDEX);
+ item.mLatitude = cursor.getDouble(CacheService.MEDIA_LATITUDE_INDEX);
+ item.mLongitude = cursor.getDouble(CacheService.MEDIA_LONGITUDE_INDEX);
+ item.mDateTakenInMs = cursor.getLong(CacheService.MEDIA_DATE_TAKEN_INDEX);
+ item.mDateAddedInSec = cursor.getLong(CacheService.MEDIA_DATE_ADDED_INDEX);
+ item.mDateModifiedInSec = cursor.getLong(CacheService.MEDIA_DATE_MODIFIED_INDEX);
+ if (item.mDateTakenInMs == item.mDateModifiedInSec) {
+ item.mDateTakenInMs = item.mDateModifiedInSec * 1000;
+ }
+ item.mFilePath = cursor.getString(CacheService.MEDIA_DATA_INDEX);
+ if (baseUri != null)
+ item.mContentUri = baseUri + item.mId;
+ final int itemMediaType = item.getMediaType();
+ // Check to see if a new date taken is available.
+ final long dateTaken = fetchDateTaken(item);
+ if (dateTaken != -1L && item.mContentUri != null) {
+ item.mDateTakenInMs = dateTaken;
+ final ContentValues values = new ContentValues();
+ if (itemMediaType == MediaItem.MEDIA_TYPE_VIDEO) {
+ values.put(Video.VideoColumns.DATE_TAKEN, item.mDateTakenInMs);
+ } else {
+ values.put(Images.ImageColumns.DATE_TAKEN, item.mDateTakenInMs);
+ }
+ cr.update(Uri.parse(item.mContentUri), values, null, null);
+ }
- public static final byte[] queryThumbnail(final Context context, final long thumbId, final long origId, final boolean isVideo,
- final long timestamp) {
- final DiskCache thumbnailCache = (isVideo) ? LocalDataSource.sThumbnailCacheVideo : LocalDataSource.sThumbnailCache;
- return queryThumbnail(context, thumbId, origId, isVideo, thumbnailCache, timestamp);
- }
+ final int orientationDurationValue = cursor.getInt(CacheService.MEDIA_ORIENTATION_OR_DURATION_INDEX);
+ if (itemMediaType == MediaItem.MEDIA_TYPE_IMAGE) {
+ item.mRotation = orientationDurationValue;
+ } else {
+ item.mDurationInSec = orientationDurationValue;
+ }
+ }
- public static final ImageList getImageList(final Context context) {
- if (sList != null)
- return sList;
- ImageList list = new ImageList();
- final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
- final ContentResolver cr = context.getContentResolver();
- final Cursor cursorImages = cr.query(uriImages, THUMBNAIL_PROJECTION, null, null, null);
- if (cursorImages != null && cursorImages.moveToFirst()) {
- final int size = cursorImages.getCount();
- final long[] ids = new long[size];
- final long[] thumbnailIds = new long[size];
- final long[] timestamp = new long[size];
- final int[] orientation = new int[size];
- int ctr = 0;
- do {
- if (Thread.interrupted()) {
- break;
- }
- ids[ctr] = cursorImages.getLong(THUMBNAIL_ID_INDEX);
- timestamp[ctr] = cursorImages.getLong(THUMBNAIL_DATE_MODIFIED_INDEX);
- thumbnailIds[ctr] = Utils.Crc64Long(cursorImages.getString(THUMBNAIL_DATA_INDEX));
- orientation[ctr] = cursorImages.getInt(THUMBNAIL_ORIENTATION_INDEX);
- ++ctr;
- } while (cursorImages.moveToNext());
- cursorImages.close();
- list.ids = ids;
- list.thumbids = thumbnailIds;
- list.timestamp = timestamp;
- list.orientation = orientation;
- }
- if (sList == null) {
- sList = list;
- }
- return list;
- }
+ // Returns -1 if we failed to examine EXIF information or EXIF parsing
+ // failed.
+ public static final long fetchDateTaken(final MediaItem item) {
+ if (!item.isDateTakenValid() && !item.mTriedRetrievingExifDateTaken
+ && (item.mFilePath.endsWith(".jpg") || item.mFilePath.endsWith(".jpeg"))) {
+ try {
+ Log.i(TAG, "Parsing date taken from exif");
+ final ExifInterface exif = new ExifInterface(item.mFilePath);
+ final String dateTakenStr = exif.getAttribute(ExifInterface.TAG_DATETIME);
+ if (dateTakenStr != null) {
+ try {
+ final Date dateTaken = mDateFormat.parse(dateTakenStr);
+ return dateTaken.getTime();
+ } catch (ParseException pe) {
+ try {
+ final Date dateTaken = mAltDateFormat.parse(dateTakenStr);
+ return dateTaken.getTime();
+ } catch (ParseException pe2) {
+ Log.i(TAG, "Unable to parse date out of string - " + dateTakenStr);
+ }
+ }
+ }
+ } catch (Exception e) {
+ Log.i(TAG, "Error reading Exif information, probably not a jpeg.");
+ }
- private static final byte[] queryThumbnail(final Context context, final long thumbId, final long origId, final boolean isVideo,
- final DiskCache thumbnailCache, final long timestamp) {
- if (!((Gallery) context).isPaused()) {
- final Thread thumbnailThread = THUMBNAIL_THREAD.getAndSet(null);
- if (thumbnailThread != null) {
- thumbnailThread.interrupt();
- }
- }
- byte[] bitmap = thumbnailCache.get(thumbId, timestamp);
- if (bitmap == null) {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- final long time = SystemClock.uptimeMillis();
- bitmap = buildThumbnailForId(context, thumbnailCache, thumbId, origId, isVideo, DEFAULT_THUMBNAIL_WIDTH,
- DEFAULT_THUMBNAIL_HEIGHT);
- Log.i(TAG, "Built thumbnail and screennail for " + origId + " in " + (SystemClock.uptimeMillis() - time));
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- }
- return bitmap;
- }
+ // Ensures that we only try retrieving EXIF date taken once.
+ item.mTriedRetrievingExifDateTaken = true;
+ }
+ return -1L;
+ }
- private static final void buildThumbnails(final Context context) {
- Log.i(TAG, "Preparing DiskCache for all thumbnails.");
- ImageList list = getImageList(context);
- final int size = (list.ids == null) ? 0 : list.ids.length;
- final long[] ids = list.ids;
- final long[] timestamp = list.timestamp;
- final long[] thumbnailIds = list.thumbids;
- final DiskCache thumbnailCache = LocalDataSource.sThumbnailCache;
- for (int i = 0; i < size; ++i) {
- if (Thread.interrupted()) {
- return;
- }
- final long id = ids[i];
- final long timeModifiedInSec = timestamp[i];
- final long thumbnailId = thumbnailIds[i];
- if (!thumbnailCache.isDataAvailable(thumbnailId, timeModifiedInSec * 1000)) {
- buildThumbnailForId(context, thumbnailCache, thumbnailId, id, false, DEFAULT_THUMBNAIL_WIDTH,
- DEFAULT_THUMBNAIL_HEIGHT);
- }
- }
- Log.i(TAG, "DiskCache ready for all thumbnails.");
- }
+ public static final byte[] queryThumbnail(final Context context, final long thumbId, final long origId, final boolean isVideo,
+ final long timestamp) {
+ final DiskCache thumbnailCache = (isVideo) ? LocalDataSource.sThumbnailCacheVideo : LocalDataSource.sThumbnailCache;
+ return queryThumbnail(context, thumbId, origId, isVideo, thumbnailCache, timestamp);
+ }
- private static final byte[] buildThumbnailForId(final Context context, final DiskCache thumbnailCache, final long thumbId,
- final long origId, final boolean isVideo, final int thumbnailWidth, final int thumbnailHeight) {
- if (origId == Shared.INVALID) {
- return null;
- }
- try {
- Bitmap bitmap = null;
- Thread.sleep(1);
- if (!isVideo) {
- final String uriString = BASE_CONTENT_STRING_IMAGES + origId;
- UriTexture.invalidateCache(thumbId, 1024);
- try {
- bitmap = UriTexture.createFromUri(context, uriString, 1024, 1024, thumbId, null);
- } catch (IOException e) {
- return null;
- } catch (URISyntaxException e) {
- return null;
- }
- } else {
- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- new Thread() {
- public void run() {
- try {
- Thread.sleep(5000);
- } catch (InterruptedException e) {
- ;
- }
- try {
- MediaStore.Video.Thumbnails.cancelThumbnailRequest(context.getContentResolver(), origId);
- } catch (Exception e) {
- ;
- }
- }
- }.start();
- bitmap = MediaStore.Video.Thumbnails.getThumbnail(context.getContentResolver(), origId,
- MediaStore.Video.Thumbnails.MICRO_KIND, null);
- }
- if (bitmap == null) {
- return null;
- }
- final byte[] retVal = writeBitmapToCache(thumbnailCache, thumbId, origId, bitmap, thumbnailWidth, thumbnailHeight);
- return retVal;
- } catch (InterruptedException e) {
- return null;
- }
- }
+ public static final ImageList getImageList(final Context context) {
+ if (sList != null)
+ return sList;
+ ImageList list = new ImageList();
+ final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
+ final ContentResolver cr = context.getContentResolver();
+ final Cursor cursorImages = cr.query(uriImages, THUMBNAIL_PROJECTION, null, null, null);
+ if (cursorImages != null && cursorImages.moveToFirst()) {
+ final int size = cursorImages.getCount();
+ final long[] ids = new long[size];
+ final long[] thumbnailIds = new long[size];
+ final long[] timestamp = new long[size];
+ final int[] orientation = new int[size];
+ int ctr = 0;
+ do {
+ if (Thread.interrupted()) {
+ break;
+ }
+ ids[ctr] = cursorImages.getLong(THUMBNAIL_ID_INDEX);
+ timestamp[ctr] = cursorImages.getLong(THUMBNAIL_DATE_MODIFIED_INDEX);
+ thumbnailIds[ctr] = Utils.Crc64Long(cursorImages.getString(THUMBNAIL_DATA_INDEX));
+ orientation[ctr] = cursorImages.getInt(THUMBNAIL_ORIENTATION_INDEX);
+ ++ctr;
+ } while (cursorImages.moveToNext());
+ cursorImages.close();
+ list.ids = ids;
+ list.thumbids = thumbnailIds;
+ list.timestamp = timestamp;
+ list.orientation = orientation;
+ }
+ if (sList == null) {
+ sList = list;
+ }
+ return list;
+ }
- public static final byte[] writeBitmapToCache(final DiskCache thumbnailCache, final long thumbId, final long origId,
- final Bitmap bitmap, final int thumbnailWidth, final int thumbnailHeight) {
- final int width = bitmap.getWidth();
- final int height = bitmap.getHeight();
- // Detect faces to find the focal point, otherwise fall back to the image center.
- int focusX = width / 2;
- int focusY = height / 2;
- // We have commented out face detection since it slows down the generation of the thumbnail and screennail.
+ private static final byte[] queryThumbnail(final Context context, final long thumbId, final long origId, final boolean isVideo,
+ final DiskCache thumbnailCache, final long timestamp) {
+ if (!((Gallery) context).isPaused()) {
+ final Thread thumbnailThread = THUMBNAIL_THREAD.getAndSet(null);
+ if (thumbnailThread != null) {
+ thumbnailThread.interrupt();
+ }
+ }
+ byte[] bitmap = thumbnailCache.get(thumbId, timestamp);
+ if (bitmap == null) {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ final long time = SystemClock.uptimeMillis();
+ bitmap = buildThumbnailForId(context, thumbnailCache, thumbId, origId, isVideo, DEFAULT_THUMBNAIL_WIDTH,
+ DEFAULT_THUMBNAIL_HEIGHT);
+ Log.i(TAG, "Built thumbnail and screennail for " + origId + " in " + (SystemClock.uptimeMillis() - time));
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ }
+ return bitmap;
+ }
- // final FaceDetector faceDetector = new FaceDetector(width, height, 1);
- // final FaceDetector.Face[] faces = new FaceDetector.Face[1];
- // final int numFaces = faceDetector.findFaces(bitmap, faces);
- // if (numFaces > 0 && faces[0].confidence() >= FaceDetector.Face.CONFIDENCE_THRESHOLD) {
- // final PointF midPoint = new PointF();
- // faces[0].getMidPoint(midPoint);
- // focusX = (int) midPoint.x;
- // focusY = (int) midPoint.y;
- // }
+ private static final void buildThumbnails(final Context context) {
+ Log.i(TAG, "Preparing DiskCache for all thumbnails.");
+ ImageList list = getImageList(context);
+ final int size = (list.ids == null) ? 0 : list.ids.length;
+ final long[] ids = list.ids;
+ final long[] timestamp = list.timestamp;
+ final long[] thumbnailIds = list.thumbids;
+ final DiskCache thumbnailCache = LocalDataSource.sThumbnailCache;
+ for (int i = 0; i < size; ++i) {
+ if (Thread.interrupted()) {
+ return;
+ }
+ final long id = ids[i];
+ final long timeModifiedInSec = timestamp[i];
+ final long thumbnailId = thumbnailIds[i];
+ if (!thumbnailCache.isDataAvailable(thumbnailId, timeModifiedInSec * 1000)) {
+ buildThumbnailForId(context, thumbnailCache, thumbnailId, id, false, DEFAULT_THUMBNAIL_WIDTH,
+ DEFAULT_THUMBNAIL_HEIGHT);
+ }
+ }
+ Log.i(TAG, "DiskCache ready for all thumbnails.");
+ }
- // Crop to thumbnail aspect ratio biased towards the focus point.
- int cropX;
- int cropY;
- int cropWidth;
- int cropHeight;
- float scaleFactor;
- if (thumbnailWidth * height < thumbnailHeight * width) {
- // Vertically constrained.
- cropWidth = thumbnailWidth * height / thumbnailHeight;
- cropX = Math.max(0, Math.min(focusX - cropWidth / 2, width - cropWidth));
- cropY = 0;
- cropHeight = height;
- scaleFactor = (float) thumbnailHeight / height;
- } else {
- // Horizontally constrained.
- cropHeight = thumbnailHeight * width / thumbnailWidth;
- cropY = Math.max(0, Math.min(focusY - cropHeight / 2, height - cropHeight));
- cropX = 0;
- cropWidth = width;
- scaleFactor = (float) thumbnailWidth / width;
- }
- final Bitmap finalBitmap = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.RGB_565);
- final Canvas canvas = new Canvas(finalBitmap);
- final Paint paint = new Paint();
- paint.setFilterBitmap(true);
- canvas.drawColor(0);
- canvas.drawBitmap(bitmap, new Rect(cropX, cropY, cropX + cropWidth, cropY + cropHeight), new Rect(0, 0, thumbnailWidth,
- thumbnailHeight), paint);
- bitmap.recycle();
+ private static final byte[] buildThumbnailForId(final Context context, final DiskCache thumbnailCache, final long thumbId,
+ final long origId, final boolean isVideo, final int thumbnailWidth, final int thumbnailHeight) {
+ if (origId == Shared.INVALID) {
+ return null;
+ }
+ try {
+ Bitmap bitmap = null;
+ Thread.sleep(1);
+ if (!isVideo) {
+ final String uriString = BASE_CONTENT_STRING_IMAGES + origId;
+ UriTexture.invalidateCache(thumbId, 1024);
+ try {
+ bitmap = UriTexture.createFromUri(context, uriString, 1024, 1024, thumbId, null);
+ } catch (IOException e) {
+ return null;
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ } else {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
+ new Thread() {
+ public void run() {
+ try {
+ Thread.sleep(5000);
+ } catch (InterruptedException e) {
+ ;
+ }
+ try {
+ MediaStore.Video.Thumbnails.cancelThumbnailRequest(context.getContentResolver(), origId);
+ } catch (Exception e) {
+ ;
+ }
+ }
+ }.start();
+ bitmap = MediaStore.Video.Thumbnails.getThumbnail(context.getContentResolver(), origId,
+ MediaStore.Video.Thumbnails.MICRO_KIND, null);
+ }
+ if (bitmap == null) {
+ return null;
+ }
+ final byte[] retVal = writeBitmapToCache(thumbnailCache, thumbId, origId, bitmap, thumbnailWidth, thumbnailHeight);
+ return retVal;
+ } catch (InterruptedException e) {
+ return null;
+ }
+ }
- // Store (long thumbnailId, short focusX, short focusY, JPEG data).
- final ByteArrayOutputStream cacheOutput = new ByteArrayOutputStream(16384);
- final DataOutputStream dataOutput = new DataOutputStream(cacheOutput);
- byte[] retVal = null;
- try {
- dataOutput.writeLong(origId);
- dataOutput.writeShort((int) ((focusX - cropX) * scaleFactor));
- dataOutput.writeShort((int) ((focusY - cropY) * scaleFactor));
- dataOutput.flush();
- finalBitmap.compress(Bitmap.CompressFormat.JPEG, 80, cacheOutput);
- retVal = cacheOutput.toByteArray();
- synchronized (thumbnailCache) {
- thumbnailCache.put(thumbId, retVal);
- }
- cacheOutput.close();
- } catch (Exception e) {
- ;
- }
- return retVal;
- }
+ public static final byte[] writeBitmapToCache(final DiskCache thumbnailCache, final long thumbId, final long origId,
+ final Bitmap bitmap, final int thumbnailWidth, final int thumbnailHeight) {
+ final int width = bitmap.getWidth();
+ final int height = bitmap.getHeight();
+ // Detect faces to find the focal point, otherwise fall back to the
+ // image center.
+ int focusX = width / 2;
+ int focusY = height / 2;
+ // We have commented out face detection since it slows down the
+ // generation of the thumbnail and screennail.
- public CacheService() {
- super("CacheService");
- }
+ // final FaceDetector faceDetector = new FaceDetector(width, height, 1);
+ // final FaceDetector.Face[] faces = new FaceDetector.Face[1];
+ // final int numFaces = faceDetector.findFaces(bitmap, faces);
+ // if (numFaces > 0 && faces[0].confidence() >=
+ // FaceDetector.Face.CONFIDENCE_THRESHOLD) {
+ // final PointF midPoint = new PointF();
+ // faces[0].getMidPoint(midPoint);
+ // focusX = (int) midPoint.x;
+ // focusY = (int) midPoint.y;
+ // }
- @Override
- protected void onHandleIntent(final Intent intent) {
- Log.i(TAG, "Starting CacheService");
- if (Environment.getExternalStorageState() == Environment.MEDIA_BAD_REMOVAL) {
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
- }
- Locale locale = getLocaleForAlbumCache();
- if (locale != null && locale.equals(Locale.getDefault())) {
- // The cache is in the same locale as the system locale.
- if (!isCacheReady(false)) {
- // The albums and their items have not yet been cached, we need to run the service.
- startNewCacheThread();
- } else {
- startNewCacheThreadForDirtySets();
- }
- } else {
- // The locale has changed, we need to regenerate the strings.
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
- startNewCacheThread();
- }
- if (intent.getBooleanExtra("checkthumbnails", false)) {
- startNewThumbnailThread(this);
- } else {
- final Thread existingThread = THUMBNAIL_THREAD.getAndSet(null);
- if (existingThread != null) {
- existingThread.interrupt();
- }
- }
- }
+ // Crop to thumbnail aspect ratio biased towards the focus point.
+ int cropX;
+ int cropY;
+ int cropWidth;
+ int cropHeight;
+ float scaleFactor;
+ if (thumbnailWidth * height < thumbnailHeight * width) {
+ // Vertically constrained.
+ cropWidth = thumbnailWidth * height / thumbnailHeight;
+ cropX = Math.max(0, Math.min(focusX - cropWidth / 2, width - cropWidth));
+ cropY = 0;
+ cropHeight = height;
+ scaleFactor = (float) thumbnailHeight / height;
+ } else {
+ // Horizontally constrained.
+ cropHeight = thumbnailHeight * width / thumbnailWidth;
+ cropY = Math.max(0, Math.min(focusY - cropHeight / 2, height - cropHeight));
+ cropX = 0;
+ cropWidth = width;
+ scaleFactor = (float) thumbnailWidth / width;
+ }
+ final Bitmap finalBitmap = Bitmap.createBitmap(thumbnailWidth, thumbnailHeight, Bitmap.Config.RGB_565);
+ final Canvas canvas = new Canvas(finalBitmap);
+ final Paint paint = new Paint();
+ paint.setFilterBitmap(true);
+ canvas.drawColor(0);
+ canvas.drawBitmap(bitmap, new Rect(cropX, cropY, cropX + cropWidth, cropY + cropHeight), new Rect(0, 0, thumbnailWidth,
+ thumbnailHeight), paint);
+ bitmap.recycle();
- private static final void putLocaleForAlbumCache(final Locale locale) {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- final DataOutputStream dos = new DataOutputStream(bos);
- try {
- Utils.writeUTF(dos, locale.getCountry());
- Utils.writeUTF(dos, locale.getLanguage());
- Utils.writeUTF(dos, locale.getVariant());
- dos.flush();
- bos.flush();
- final byte[] data = bos.toByteArray();
- sAlbumCache.put(ALBUM_CACHE_LOCALE_INDEX, data);
- sAlbumCache.flush();
- dos.close();
- bos.close();
- } catch (IOException e) {
- // Could not write locale to cache.
- Log.i(TAG, "Error writing locale to cache.");
- ;
- }
- }
+ // Store (long thumbnailId, short focusX, short focusY, JPEG data).
+ final ByteArrayOutputStream cacheOutput = new ByteArrayOutputStream(16384);
+ final DataOutputStream dataOutput = new DataOutputStream(cacheOutput);
+ byte[] retVal = null;
+ try {
+ dataOutput.writeLong(origId);
+ dataOutput.writeShort((int) ((focusX - cropX) * scaleFactor));
+ dataOutput.writeShort((int) ((focusY - cropY) * scaleFactor));
+ dataOutput.flush();
+ finalBitmap.compress(Bitmap.CompressFormat.JPEG, 80, cacheOutput);
+ retVal = cacheOutput.toByteArray();
+ synchronized (thumbnailCache) {
+ thumbnailCache.put(thumbId, retVal);
+ }
+ cacheOutput.close();
+ } catch (Exception e) {
+ ;
+ }
+ return retVal;
+ }
- private static final Locale getLocaleForAlbumCache() {
- final byte[] data = sAlbumCache.get(ALBUM_CACHE_LOCALE_INDEX, 0);
- if (data != null && data.length > 0) {
- ByteArrayInputStream bis = new ByteArrayInputStream(data);
- DataInputStream dis = new DataInputStream(bis);
- try {
- String country = Utils.readUTF(dis);
- if (country == null)
- country = "";
- String language = Utils.readUTF(dis);
- if (language == null)
- language = "";
- String variant = Utils.readUTF(dis);
- if (variant == null)
- variant = "";
- final Locale locale = new Locale(language, country, variant);
- dis.close();
- bis.close();
- return locale;
- } catch (IOException e) {
- // Could not read locale in cache.
- Log.i(TAG, "Error reading locale from cache.");
- return null;
- }
- }
- return null;
- }
+ public CacheService() {
+ super("CacheService");
+ }
- private static final void restartThread(final AtomicReference<Thread> threadRef, final String name, final Runnable action) {
- // Create a new thread.
- final Thread newThread = new Thread() {
- public void run() {
- try {
- action.run();
- } finally {
- threadRef.compareAndSet(this, null);
- }
- }
- };
- newThread.setName(name);
- newThread.start();
+ @Override
+ protected void onHandleIntent(final Intent intent) {
+ Log.i(TAG, "Starting CacheService");
+ if (Environment.getExternalStorageState() == Environment.MEDIA_BAD_REMOVAL) {
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+ }
+ Locale locale = getLocaleForAlbumCache();
+ if (locale != null && locale.equals(Locale.getDefault())) {
+ // The cache is in the same locale as the system locale.
+ if (!isCacheReady(false)) {
+ // The albums and their items have not yet been cached, we need
+ // to run the service.
+ startNewCacheThread();
+ } else {
+ startNewCacheThreadForDirtySets();
+ }
+ } else {
+ // The locale has changed, we need to regenerate the strings.
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+ startNewCacheThread();
+ }
+ if (intent.getBooleanExtra("checkthumbnails", false)) {
+ startNewThumbnailThread(this);
+ } else {
+ final Thread existingThread = THUMBNAIL_THREAD.getAndSet(null);
+ if (existingThread != null) {
+ existingThread.interrupt();
+ }
+ }
+ }
- // Interrupt any existing thread.
- final Thread existingThread = threadRef.getAndSet(newThread);
- if (existingThread != null) {
- existingThread.interrupt();
- }
- }
+ private static final void putLocaleForAlbumCache(final Locale locale) {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final DataOutputStream dos = new DataOutputStream(bos);
+ try {
+ Utils.writeUTF(dos, locale.getCountry());
+ Utils.writeUTF(dos, locale.getLanguage());
+ Utils.writeUTF(dos, locale.getVariant());
+ dos.flush();
+ bos.flush();
+ final byte[] data = bos.toByteArray();
+ sAlbumCache.put(ALBUM_CACHE_LOCALE_INDEX, data);
+ sAlbumCache.flush();
+ dos.close();
+ bos.close();
+ } catch (IOException e) {
+ // Could not write locale to cache.
+ Log.i(TAG, "Error writing locale to cache.");
+ ;
+ }
+ }
- public static final void startNewThumbnailThread(final Context context) {
- restartThread(THUMBNAIL_THREAD, "ThumbnailRefresh", new Runnable() {
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- try {
- // It is an optimization to prevent the thumbnailer from running while the application loads
- Thread.sleep(THUMBNAILER_WAIT_IN_MS);
- } catch (InterruptedException e) {
- return;
- }
- CacheService.buildThumbnails(context);
- }
- });
- }
+ private static final Locale getLocaleForAlbumCache() {
+ final byte[] data = sAlbumCache.get(ALBUM_CACHE_LOCALE_INDEX, 0);
+ if (data != null && data.length > 0) {
+ ByteArrayInputStream bis = new ByteArrayInputStream(data);
+ DataInputStream dis = new DataInputStream(bis);
+ try {
+ String country = Utils.readUTF(dis);
+ if (country == null)
+ country = "";
+ String language = Utils.readUTF(dis);
+ if (language == null)
+ language = "";
+ String variant = Utils.readUTF(dis);
+ if (variant == null)
+ variant = "";
+ final Locale locale = new Locale(language, country, variant);
+ dis.close();
+ bis.close();
+ return locale;
+ } catch (IOException e) {
+ // Could not read locale in cache.
+ Log.i(TAG, "Error reading locale from cache.");
+ return null;
+ }
+ }
+ return null;
+ }
- private void startNewCacheThread() {
- restartThread(CACHE_THREAD, "CacheRefresh", new Runnable() {
- public void run() {
- refresh(CacheService.this);
- }
- });
- }
+ private static final void restartThread(final AtomicReference<Thread> threadRef, final String name, final Runnable action) {
+ // Create a new thread.
+ final Thread newThread = new Thread() {
+ public void run() {
+ try {
+ action.run();
+ } finally {
+ threadRef.compareAndSet(this, null);
+ }
+ }
+ };
+ newThread.setName(name);
+ newThread.start();
- private void startNewCacheThreadForDirtySets() {
- restartThread(CACHE_THREAD, "CacheRefreshDirtySets", new Runnable() {
- public void run() {
- refreshDirtySets(CacheService.this);
- }
- });
- }
+ // Interrupt any existing thread.
+ final Thread existingThread = threadRef.getAndSet(newThread);
+ if (existingThread != null) {
+ existingThread.interrupt();
+ }
+ }
- private static final byte[] concat(final byte[] A, final byte[] B) {
- final byte[] C = (byte[]) new byte[A.length + B.length];
- System.arraycopy(A, 0, C, 0, A.length);
- System.arraycopy(B, 0, C, A.length, B.length);
- return C;
- }
+ public static final void startNewThumbnailThread(final Context context) {
+ restartThread(THUMBNAIL_THREAD, "ThumbnailRefresh", new Runnable() {
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ try {
+ // It is an optimization to prevent the thumbnailer from
+ // running while the application loads
+ Thread.sleep(THUMBNAILER_WAIT_IN_MS);
+ } catch (InterruptedException e) {
+ return;
+ }
+ CacheService.buildThumbnails(context);
+ }
+ });
+ }
- private static final long[] toLongArray(final byte[] data) {
- final ByteBuffer bBuffer = ByteBuffer.wrap(data);
- final LongBuffer lBuffer = bBuffer.asLongBuffer();
- final int numLongs = lBuffer.capacity();
- final long[] retVal = new long[numLongs];
- for (int i = 0; i < numLongs; ++i) {
- retVal[i] = lBuffer.get(i);
- }
- return retVal;
- }
+ private void startNewCacheThread() {
+ restartThread(CACHE_THREAD, "CacheRefresh", new Runnable() {
+ public void run() {
+ refresh(CacheService.this);
+ }
+ });
+ }
- private static final byte[] longToByteArray(final long l) {
- final byte[] bArray = new byte[8];
- final ByteBuffer bBuffer = ByteBuffer.wrap(bArray);
- final LongBuffer lBuffer = bBuffer.asLongBuffer();
- lBuffer.put(0, l);
- return bArray;
- }
+ private void startNewCacheThreadForDirtySets() {
+ restartThread(CACHE_THREAD, "CacheRefreshDirtySets", new Runnable() {
+ public void run() {
+ refreshDirtySets(CacheService.this);
+ }
+ });
+ }
- private final static void refresh(final Context context) {
- // First we build the album cache.
- // This is the meta-data about the albums / buckets on the SD card.
- Log.i(TAG, "Refreshing cache.");
- int priority = Process.getThreadPriority(Process.myTid());
- Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE);
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
+ private static final byte[] concat(final byte[] A, final byte[] B) {
+ final byte[] C = (byte[]) new byte[A.length + B.length];
+ System.arraycopy(A, 0, C, 0, A.length);
+ System.arraycopy(B, 0, C, A.length, B.length);
+ return C;
+ }
- final ArrayList<MediaSet> sets = new ArrayList<MediaSet>();
- LongSparseArray<MediaSet> acceleratedSets = new LongSparseArray<MediaSet>();
- Log.i(TAG, "Building albums.");
- final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build();
- final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build();
- final ContentResolver cr = context.getContentResolver();
+ private static final long toLong(final byte[] data) {
+ // 8 bytes for a long
+ if (data == null || data.length < 8)
+ return 0;
+ final ByteBuffer bBuffer = ByteBuffer.wrap(data);
+ final LongBuffer lBuffer = bBuffer.asLongBuffer();
+ final int numLongs = lBuffer.capacity();
+ return lBuffer.get(0);
+ }
- final Cursor cursorImages = cr.query(uriImages, BUCKET_PROJECTION_IMAGES, null, null, DEFAULT_BUCKET_SORT_ORDER);
- final Cursor cursorVideos = cr.query(uriVideos, BUCKET_PROJECTION_VIDEOS, null, null, DEFAULT_BUCKET_SORT_ORDER);
- Cursor[] cursors = new Cursor[2];
- cursors[0] = cursorImages;
- cursors[1] = cursorVideos;
- final SortCursor sortCursor = new SortCursor(cursors, Images.ImageColumns.BUCKET_DISPLAY_NAME, SortCursor.TYPE_STRING, true);
- try {
- if (sortCursor != null && sortCursor.moveToFirst()) {
- sets.ensureCapacity(sortCursor.getCount());
- acceleratedSets = new LongSparseArray<MediaSet>(sortCursor.getCount());
- MediaSet cameraSet = new MediaSet();
- cameraSet.mId = LocalDataSource.CAMERA_BUCKET_ID;
- cameraSet.mName = context.getResources().getString(R.string.camera);
- sets.add(cameraSet);
- acceleratedSets.put(cameraSet.mId, cameraSet);
- do {
- if (Thread.interrupted()) {
- return;
- }
- long setId = sortCursor.getLong(BUCKET_ID_INDEX);
- MediaSet mediaSet = findSet(setId, acceleratedSets);
- if (mediaSet == null) {
- mediaSet = new MediaSet();
- mediaSet.mId = setId;
- mediaSet.mName = sortCursor.getString(BUCKET_NAME_INDEX);
- sets.add(mediaSet);
- acceleratedSets.put(setId, mediaSet);
- }
- mediaSet.mHasImages |= (sortCursor.getCurrentCursorIndex() == 0);
- mediaSet.mHasVideos |= (sortCursor.getCurrentCursorIndex() == 1);
- } while (sortCursor.moveToNext());
- sortCursor.close();
- }
- } finally {
- if (sortCursor != null)
- sortCursor.close();
- }
+ private static final long[] toLongArray(final byte[] data) {
+ final ByteBuffer bBuffer = ByteBuffer.wrap(data);
+ final LongBuffer lBuffer = bBuffer.asLongBuffer();
+ final int numLongs = lBuffer.capacity();
+ final long[] retVal = new long[numLongs];
+ for (int i = 0; i < numLongs; ++i) {
+ retVal[i] = lBuffer.get(i);
+ }
+ return retVal;
+ }
- sAlbumCache.put(ALBUM_CACHE_INCOMPLETE_INDEX, sDummyData);
- writeSetsToCache(sets);
- Log.i(TAG, "Done building albums.");
- // Now we must cache the items contained in every album / bucket.
- populateMediaItemsForSets(context, sets, acceleratedSets, false);
- sAlbumCache.delete(ALBUM_CACHE_INCOMPLETE_INDEX);
- Process.setThreadPriority(priority);
- if (QUEUE_DIRTY_ALL) {
- QUEUE_DIRTY_ALL = false;
- refresh(context);
- }
- }
+ private static final byte[] longToByteArray(final long l) {
+ final byte[] bArray = new byte[8];
+ final ByteBuffer bBuffer = ByteBuffer.wrap(bArray);
+ final LongBuffer lBuffer = bBuffer.asLongBuffer();
+ lBuffer.put(0, l);
+ return bArray;
+ }
- private final static void refreshDirtySets(final Context context) {
- final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0);
- if (existingData != null && existingData.length > 0) {
- final long[] ids = toLongArray(existingData);
- final int numIds = ids.length;
- if (numIds > 0) {
- final ArrayList<MediaSet> sets = new ArrayList<MediaSet>(numIds);
- final LongSparseArray<MediaSet> acceleratedSets = new LongSparseArray<MediaSet>(numIds);
- for (int i = 0; i < numIds; ++i) {
- final MediaSet set = new MediaSet();
- set.mId = ids[i];
- sets.add(set);
- acceleratedSets.put(set.mId, set);
- }
- Log.i(TAG, "Refreshing dirty albums");
- populateMediaItemsForSets(context, sets, acceleratedSets, true);
- }
- }
- if (QUEUE_DIRTY_SET) {
- QUEUE_DIRTY_SET = false;
- refreshDirtySets(context);
- } else {
- sAlbumCache.delete(ALBUM_CACHE_DIRTY_BUCKET_INDEX);
- }
- }
+ private final static void refresh(final Context context) {
+ // First we build the album cache.
+ // This is the meta-data about the albums / buckets on the SD card.
+ Log.i(TAG, "Refreshing cache.");
+ int priority = Process.getThreadPriority(Process.myTid());
+ Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE);
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
- private final static void populateMediaItemsForSets(final Context context, final ArrayList<MediaSet> sets,
- final LongSparseArray<MediaSet> acceleratedSets, boolean useWhere) {
- if (sets == null || sets.size() == 0 || Thread.interrupted()) {
- return;
- }
- Log.i(TAG, "Building items.");
- final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
- final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
- final ContentResolver cr = context.getContentResolver();
+ final ArrayList<MediaSet> sets = new ArrayList<MediaSet>();
+ LongSparseArray<MediaSet> acceleratedSets = new LongSparseArray<MediaSet>();
+ Log.i(TAG, "Building albums.");
+ final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build();
+ final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build();
+ final ContentResolver cr = context.getContentResolver();
- String whereClause = null;
- if (useWhere) {
- int numSets = sets.size();
- StringBuffer whereString = new StringBuffer(Images.ImageColumns.BUCKET_ID + " in (");
- for (int i = 0; i < numSets; ++i) {
- whereString.append(sets.get(i).mId);
- if (i != numSets - 1) {
- whereString.append(",");
- }
- }
- whereString.append(")");
- whereClause = whereString.toString();
- Log.i(TAG, "Updating dirty albums where " + whereClause);
- }
+ final Cursor cursorImages = cr.query(uriImages, BUCKET_PROJECTION_IMAGES, null, null, DEFAULT_BUCKET_SORT_ORDER);
+ final Cursor cursorVideos = cr.query(uriVideos, BUCKET_PROJECTION_VIDEOS, null, null, DEFAULT_BUCKET_SORT_ORDER);
+ Cursor[] cursors = new Cursor[2];
+ cursors[0] = cursorImages;
+ cursors[1] = cursorVideos;
+ final SortCursor sortCursor = new SortCursor(cursors, Images.ImageColumns.BUCKET_DISPLAY_NAME, SortCursor.TYPE_STRING, true);
+ try {
+ if (sortCursor != null && sortCursor.moveToFirst()) {
+ sets.ensureCapacity(sortCursor.getCount());
+ acceleratedSets = new LongSparseArray<MediaSet>(sortCursor.getCount());
+ MediaSet cameraSet = new MediaSet();
+ cameraSet.mId = LocalDataSource.CAMERA_BUCKET_ID;
+ cameraSet.mName = context.getResources().getString(R.string.camera);
+ sets.add(cameraSet);
+ acceleratedSets.put(cameraSet.mId, cameraSet);
+ do {
+ if (Thread.interrupted()) {
+ return;
+ }
+ long setId = sortCursor.getLong(BUCKET_ID_INDEX);
+ MediaSet mediaSet = findSet(setId, acceleratedSets);
+ if (mediaSet == null) {
+ mediaSet = new MediaSet();
+ mediaSet.mId = setId;
+ mediaSet.mName = sortCursor.getString(BUCKET_NAME_INDEX);
+ sets.add(mediaSet);
+ acceleratedSets.put(setId, mediaSet);
+ }
+ mediaSet.mHasImages |= (sortCursor.getCurrentCursorIndex() == 0);
+ mediaSet.mHasVideos |= (sortCursor.getCurrentCursorIndex() == 1);
+ } while (sortCursor.moveToNext());
+ sortCursor.close();
+ }
+ } finally {
+ if (sortCursor != null)
+ sortCursor.close();
+ }
- final Cursor cursorImages = cr.query(uriImages, PROJECTION_IMAGES, whereClause, null, DEFAULT_IMAGE_SORT_ORDER);
- final Cursor cursorVideos = cr.query(uriVideos, PROJECTION_VIDEOS, whereClause, null, DEFAULT_VIDEO_SORT_ORDER);
- final Cursor[] cursors = new Cursor[2];
- cursors[0] = cursorImages;
- cursors[1] = cursorVideos;
- final SortCursor sortCursor = new SortCursor(cursors, Images.ImageColumns.DATE_TAKEN, SortCursor.TYPE_NUMERIC, true);
- if (Thread.interrupted()) {
- return;
- }
- try {
- if (sortCursor != null && sortCursor.moveToFirst()) {
- final int count = sortCursor.getCount();
- final int numSets = sets.size();
- final int approximateCountPerSet = count / numSets;
- for (int i = 0; i < numSets; ++i) {
- final MediaSet set = sets.get(i);
- set.getItems().clear();
- set.setNumExpectedItems(approximateCountPerSet);
- }
- do {
- if (Thread.interrupted()) {
- return;
- }
- final MediaItem item = new MediaItem();
- final boolean isVideo = (sortCursor.getCurrentCursorIndex() == 1);
- if (isVideo) {
- populateVideoItemFromCursor(item, cr, sortCursor, CacheService.BASE_CONTENT_STRING_VIDEOS);
- } else {
- populateMediaItemFromCursor(item, cr, sortCursor, CacheService.BASE_CONTENT_STRING_IMAGES);
- }
- final long setId = sortCursor.getLong(MEDIA_BUCKET_ID_INDEX);
- final MediaSet set = findSet(setId, acceleratedSets);
- if (set != null) {
- set.getItems().add(item);
- }
- } while (sortCursor.moveToNext());
- }
- } finally {
- if (sortCursor != null) sortCursor.close();
- }
- if (sets.size() > 0) {
- writeItemsToCache(sets);
- Log.i(TAG, "Done building items.");
- }
- }
+ sAlbumCache.put(ALBUM_CACHE_INCOMPLETE_INDEX, sDummyData);
+ writeSetsToCache(sets);
+ Log.i(TAG, "Done building albums.");
+ // Now we must cache the items contained in every album / bucket.
+ populateMediaItemsForSets(context, sets, acceleratedSets, false);
+ sAlbumCache.delete(ALBUM_CACHE_INCOMPLETE_INDEX);
+ Process.setThreadPriority(priority);
- private static final void writeSetsToCache(final ArrayList<MediaSet> sets) {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- final int numSets = sets.size();
- final DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(bos, 256));
- try {
- dos.writeInt(numSets);
- for (int i = 0; i < numSets; ++i) {
- if (Thread.interrupted()) {
- return;
- }
- final MediaSet set = sets.get(i);
- dos.writeLong(set.mId);
- Utils.writeUTF(dos, set.mName);
- dos.writeBoolean(set.mHasImages);
- dos.writeBoolean(set.mHasVideos);
- }
- dos.flush();
- sAlbumCache.put(ALBUM_CACHE_METADATA_INDEX, bos.toByteArray());
- dos.close();
- if (numSets == 0) {
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
- }
- sAlbumCache.flush();
- } catch (IOException e) {
- Log.e(TAG, "Error writing albums to diskcache.");
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
- }
- }
+ // Complete any queued dirty requests
+ processQueuedDirty(context);
+ }
- private static final void writeItemsToCache(final ArrayList<MediaSet> sets) {
- final int numSets = sets.size();
- for (int i = 0; i < numSets; ++i) {
- if (Thread.interrupted()) {
- return;
- }
- writeItemsForASet(sets.get(i));
- }
- sAlbumCache.flush();
- }
+ private final static void refreshDirtySets(final Context context) {
+ final byte[] existingData = sAlbumCache.get(ALBUM_CACHE_DIRTY_BUCKET_INDEX, 0);
+ if (existingData != null && existingData.length > 0) {
+ final long[] ids = toLongArray(existingData);
+ final int numIds = ids.length;
+ if (numIds > 0) {
+ final ArrayList<MediaSet> sets = new ArrayList<MediaSet>(numIds);
+ final LongSparseArray<MediaSet> acceleratedSets = new LongSparseArray<MediaSet>(numIds);
+ for (int i = 0; i < numIds; ++i) {
+ final MediaSet set = new MediaSet();
+ set.mId = ids[i];
+ sets.add(set);
+ acceleratedSets.put(set.mId, set);
+ }
+ Log.i(TAG, "Refreshing dirty albums");
+ populateMediaItemsForSets(context, sets, acceleratedSets, true);
+ }
+ }
+ processQueuedDirty(context);
+ sAlbumCache.delete(ALBUM_CACHE_DIRTY_BUCKET_INDEX);
+ }
- private static final void writeItemsForASet(final MediaSet set) {
- final ByteArrayOutputStream bos = new ByteArrayOutputStream();
- final DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(bos, 256));
- try {
- final ArrayList<MediaItem> items = set.getItems();
- final int numItems = items.size();
- dos.writeInt(numItems);
- dos.writeLong(set.mMinTimestamp);
- dos.writeLong(set.mMaxTimestamp);
- for (int i = 0; i < numItems; ++i) {
- MediaItem item = items.get(i);
- if (set.mId == LocalDataSource.CAMERA_BUCKET_ID || set.mId == LocalDataSource.DOWNLOAD_BUCKET_ID) {
- // Reverse the display order for the camera bucket - want the latest first.
- item = items.get(numItems - i - 1);
- }
- dos.writeLong(item.mId);
- Utils.writeUTF(dos, item.mCaption);
- Utils.writeUTF(dos, item.mMimeType);
- dos.writeInt(item.getMediaType());
- dos.writeDouble(item.mLatitude);
- dos.writeDouble(item.mLongitude);
- dos.writeLong(item.mDateTakenInMs);
- dos.writeBoolean(item.mTriedRetrievingExifDateTaken);
- dos.writeLong(item.mDateAddedInSec);
- dos.writeLong(item.mDateModifiedInSec);
- dos.writeInt(item.mDurationInSec);
- dos.writeInt((int) item.mRotation);
- Utils.writeUTF(dos, item.mFilePath);
- }
- dos.flush();
- sAlbumCache.put(set.mId, bos.toByteArray());
- dos.close();
- } catch (IOException e) {
- Log.e(TAG, "Error writing to diskcache for set " + set.mName);
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
- }
- }
+ private static final long[] computeDirtySets(final Context context) {
+ final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build();
+ final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build();
+ final ContentResolver cr = context.getContentResolver();
- private static final MediaSet findSet(final long id, final LongSparseArray<MediaSet> acceleratedTable) {
- // This is the accelerated lookup table for the MediaSet based on set id.
- return acceleratedTable.get(id);
- }
+ final Cursor cursorImages = cr.query(uriImages, SENSE_PROJECTION, null, null, null);
+ final Cursor cursorVideos = cr.query(uriVideos, SENSE_PROJECTION, null, null, null);
+ Cursor[] cursors = new Cursor[2];
+ cursors[0] = cursorImages;
+ cursors[1] = cursorVideos;
+ final MergeCursor cursor = new MergeCursor(cursors);
+ long[] retVal = null;
+ try {
+ if (cursor.moveToFirst()) {
+ retVal = new long[cursor.getCount()];
+ int ctr = 0;
+ boolean allDirty = false;
+ do {
+ long setId = cursor.getLong(0);
+ retVal[ctr++] = setId;
+ byte[] data = sMetaAlbumCache.get(setId, 0);
+ if (data == null) {
+ // We need to refresh everything.
+ markDirty(context);
+ allDirty = true;
+ }
+ if (!allDirty) {
+ long maxAdded = cursor.getLong(1);
+ long oldMaxAdded = toLong(data);
+ if (maxAdded > oldMaxAdded) {
+ markDirty(context, setId);
+ }
+ }
+ } while (cursor.moveToNext());
+ }
+ } finally {
+ cursor.close();
+ }
+ processQueuedDirty(context);
+ return retVal;
+ }
+
+ private static final void processQueuedDirty(final Context context) {
+ if (QUEUE_DIRTY_SENSE) {
+ QUEUE_DIRTY_SENSE = false;
+ QUEUE_DIRTY_ALL = false;
+ QUEUE_DIRTY_SET = false;
+ computeDirtySets(context);
+ } else if (QUEUE_DIRTY_ALL) {
+ QUEUE_DIRTY_ALL = false;
+ QUEUE_DIRTY_SET = false;
+ QUEUE_DIRTY_SENSE = false;
+ refresh(context);
+ } else if (QUEUE_DIRTY_SET) {
+ QUEUE_DIRTY_SET = false;
+ // We don't mark QUEUE_DIRTY_SENSE because a set outside the dirty
+ // sets might have gotten modified.
+ refreshDirtySets(context);
+ }
+ }
+
+ private final static void populateMediaItemsForSets(final Context context, final ArrayList<MediaSet> sets,
+ final LongSparseArray<MediaSet> acceleratedSets, boolean useWhere) {
+ if (sets == null || sets.size() == 0 || Thread.interrupted()) {
+ return;
+ }
+ Log.i(TAG, "Building items.");
+ final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
+ final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
+ final ContentResolver cr = context.getContentResolver();
+
+ String whereClause = null;
+ if (useWhere) {
+ int numSets = sets.size();
+ StringBuffer whereString = new StringBuffer(Images.ImageColumns.BUCKET_ID + " in (");
+ for (int i = 0; i < numSets; ++i) {
+ whereString.append(sets.get(i).mId);
+ if (i != numSets - 1) {
+ whereString.append(",");
+ }
+ }
+ whereString.append(")");
+ whereClause = whereString.toString();
+ Log.i(TAG, "Updating dirty albums where " + whereClause);
+ }
+
+ final Cursor cursorImages = cr.query(uriImages, PROJECTION_IMAGES, whereClause, null, DEFAULT_IMAGE_SORT_ORDER);
+ final Cursor cursorVideos = cr.query(uriVideos, PROJECTION_VIDEOS, whereClause, null, DEFAULT_VIDEO_SORT_ORDER);
+ final Cursor[] cursors = new Cursor[2];
+ cursors[0] = cursorImages;
+ cursors[1] = cursorVideos;
+ final SortCursor sortCursor = new SortCursor(cursors, Images.ImageColumns.DATE_TAKEN, SortCursor.TYPE_NUMERIC, true);
+ if (Thread.interrupted()) {
+ return;
+ }
+ try {
+ if (sortCursor != null && sortCursor.moveToFirst()) {
+ final int count = sortCursor.getCount();
+ final int numSets = sets.size();
+ final int approximateCountPerSet = count / numSets;
+ for (int i = 0; i < numSets; ++i) {
+ final MediaSet set = sets.get(i);
+ set.getItems().clear();
+ set.setNumExpectedItems(approximateCountPerSet);
+ }
+ do {
+ if (Thread.interrupted()) {
+ return;
+ }
+ final MediaItem item = new MediaItem();
+ final boolean isVideo = (sortCursor.getCurrentCursorIndex() == 1);
+ if (isVideo) {
+ populateVideoItemFromCursor(item, cr, sortCursor, CacheService.BASE_CONTENT_STRING_VIDEOS);
+ } else {
+ populateMediaItemFromCursor(item, cr, sortCursor, CacheService.BASE_CONTENT_STRING_IMAGES);
+ }
+ final long setId = sortCursor.getLong(MEDIA_BUCKET_ID_INDEX);
+ final MediaSet set = findSet(setId, acceleratedSets);
+ if (set != null) {
+ set.getItems().add(item);
+ }
+ } while (sortCursor.moveToNext());
+ }
+ } finally {
+ if (sortCursor != null)
+ sortCursor.close();
+ }
+ if (sets.size() > 0) {
+ writeItemsToCache(sets);
+ Log.i(TAG, "Done building items.");
+ }
+ }
+
+ private static final void writeSetsToCache(final ArrayList<MediaSet> sets) {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final int numSets = sets.size();
+ final DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(bos, 256));
+ try {
+ dos.writeInt(numSets);
+ for (int i = 0; i < numSets; ++i) {
+ if (Thread.interrupted()) {
+ return;
+ }
+ final MediaSet set = sets.get(i);
+ dos.writeLong(set.mId);
+ Utils.writeUTF(dos, set.mName);
+ dos.writeBoolean(set.mHasImages);
+ dos.writeBoolean(set.mHasVideos);
+ }
+ dos.flush();
+ sAlbumCache.put(ALBUM_CACHE_METADATA_INDEX, bos.toByteArray());
+ dos.close();
+ if (numSets == 0) {
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+ }
+ sAlbumCache.flush();
+ } catch (IOException e) {
+ Log.e(TAG, "Error writing albums to diskcache.");
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+ }
+ }
+
+ private static final void writeItemsToCache(final ArrayList<MediaSet> sets) {
+ final int numSets = sets.size();
+ for (int i = 0; i < numSets; ++i) {
+ if (Thread.interrupted()) {
+ return;
+ }
+ writeItemsForASet(sets.get(i));
+ }
+ writeMetaAlbumCache(sets);
+ sAlbumCache.flush();
+ }
+
+ private static final void writeMetaAlbumCache(ArrayList<MediaSet> sets) {
+ final int numSets = sets.size();
+ for (int i = 0; i < numSets; ++i) {
+ final MediaSet set = sets.get(i);
+ byte[] data = longToByteArray(set.mMaxAddedTimestamp);
+ sMetaAlbumCache.put(set.mId, data);
+ }
+ sMetaAlbumCache.flush();
+ }
+
+ private static final void writeItemsForASet(final MediaSet set) {
+ final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ final DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(bos, 256));
+ try {
+ final ArrayList<MediaItem> items = set.getItems();
+ final int numItems = items.size();
+ dos.writeInt(numItems);
+ dos.writeLong(set.mMinTimestamp);
+ dos.writeLong(set.mMaxTimestamp);
+ for (int i = 0; i < numItems; ++i) {
+ MediaItem item = items.get(i);
+ if (set.mId == LocalDataSource.CAMERA_BUCKET_ID || set.mId == LocalDataSource.DOWNLOAD_BUCKET_ID) {
+ // Reverse the display order for the camera bucket - want
+ // the latest first.
+ item = items.get(numItems - i - 1);
+ }
+ dos.writeLong(item.mId);
+ Utils.writeUTF(dos, item.mCaption);
+ Utils.writeUTF(dos, item.mMimeType);
+ dos.writeInt(item.getMediaType());
+ dos.writeDouble(item.mLatitude);
+ dos.writeDouble(item.mLongitude);
+ dos.writeLong(item.mDateTakenInMs);
+ dos.writeBoolean(item.mTriedRetrievingExifDateTaken);
+ dos.writeLong(item.mDateAddedInSec);
+ dos.writeLong(item.mDateModifiedInSec);
+ dos.writeInt(item.mDurationInSec);
+ dos.writeInt((int) item.mRotation);
+ Utils.writeUTF(dos, item.mFilePath);
+ }
+ dos.flush();
+ sAlbumCache.put(set.mId, bos.toByteArray());
+ dos.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Error writing to diskcache for set " + set.mName);
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+ }
+ }
+
+ private static final MediaSet findSet(final long id, final LongSparseArray<MediaSet> acceleratedTable) {
+ // This is the accelerated lookup table for the MediaSet based on set
+ // id.
+ return acceleratedTable.get(id);
+ }
}
diff --git a/src/com/cooliris/media/BackgroundLayer.java b/src/com/cooliris/media/BackgroundLayer.java
index 234e916..fef6bba 100644
--- a/src/com/cooliris/media/BackgroundLayer.java
+++ b/src/com/cooliris/media/BackgroundLayer.java
@@ -21,7 +21,7 @@
private static final int ADAPTIVE_BACKGROUND_WIDTH = 256;
private static final int ADAPTIVE_BACKGROUND_HEIGHT = 128;
- BackgroundLayer(GridLayer layer) {
+ public BackgroundLayer(GridLayer layer) {
mGridLayer = layer;
}
diff --git a/src/com/cooliris/media/ConcatenatedDataSource.java b/src/com/cooliris/media/ConcatenatedDataSource.java
index f09b151..3a719b3 100644
--- a/src/com/cooliris/media/ConcatenatedDataSource.java
+++ b/src/com/cooliris/media/ConcatenatedDataSource.java
@@ -2,6 +2,7 @@
import java.util.ArrayList;
+
import android.util.Log;
public final class ConcatenatedDataSource implements DataSource {
diff --git a/src/com/cooliris/media/DataSource.java b/src/com/cooliris/media/DataSource.java
index c05eacf..90b6df2 100644
--- a/src/com/cooliris/media/DataSource.java
+++ b/src/com/cooliris/media/DataSource.java
@@ -2,6 +2,7 @@
import java.util.ArrayList;
+
public interface DataSource {
// Load the sets to be displayed.
void loadMediaSets(final MediaFeed feed);
diff --git a/src/com/cooliris/media/FlatLocalDataSource.java b/src/com/cooliris/media/FlatLocalDataSource.java
deleted file mode 100644
index 87caca5..0000000
--- a/src/com/cooliris/media/FlatLocalDataSource.java
+++ /dev/null
@@ -1,35 +0,0 @@
-//package com.cooliris.media;
-//
-//// Deprecated class. Need to remove from perforce
-//
-//import java.util.ArrayList;
-//
-//public class FlatLocalDataSource implements MediaFeed.DataSource {
-// private final boolean mIncludeImages;
-// private final boolean mIncludeVideos;
-//
-// public FlatLocalDataSource(boolean includeImages, boolean includeVideos) {
-// mIncludeImages = includeImages;
-// mIncludeVideos = includeVideos;
-// }
-//
-// public DiskCache getThumbnailCache() {
-// return LocalDataSource.sThumbnailCache;
-// }
-//
-// public void loadItemsForSet(MediaFeed feed, MediaSet parentSet, int rangeStart, int rangeEnd) {
-// // TODO Auto-generated method stub
-//
-// }
-//
-// public void loadMediaSets(MediaFeed feed) {
-// MediaSet set = feed.addMediaSet(0, this);
-// set.name = "Local Media";
-// }
-//
-// public boolean performOperation(int operation, ArrayList<MediaBucket> mediaBuckets, Object data) {
-// // TODO Auto-generated method stub
-// return false;
-// }
-//
-//}
diff --git a/src/com/cooliris/media/Gallery.java b/src/com/cooliris/media/Gallery.java
index 2a2a170..46fc3dd 100644
--- a/src/com/cooliris/media/Gallery.java
+++ b/src/com/cooliris/media/Gallery.java
@@ -2,6 +2,7 @@
import java.io.IOException;
import java.net.URISyntaxException;
+import java.util.HashMap;
import java.util.TimeZone;
import android.app.Activity;
@@ -27,349 +28,365 @@
import com.cooliris.wallpaper.Slideshow;
public final class Gallery extends Activity {
- public static final TimeZone CURRENT_TIME_ZONE = TimeZone.getDefault();
- public static float PIXEL_DENSITY = 0.0f;
- public static boolean NEEDS_REFRESH = true;
+ public static final TimeZone CURRENT_TIME_ZONE = TimeZone.getDefault();
+ public static float PIXEL_DENSITY = 0.0f;
+ public static final int CROP_MSG_INTERNAL = 100;
- private static final String TAG = "Gallery";
- public static final int CROP_MSG_INTERNAL = 100;
- private static final int CROP_MSG = 10;
- private RenderView mRenderView = null;
- private GridLayer mGridLayer;
- private final Handler mHandler = new Handler();
- private ReverseGeocoder mReverseGeocoder;
- private boolean mPause;
- private MediaScannerConnection mConnection;
- private WakeLock mWakeLock;
- private static final boolean TEST_WALLPAPER = false;
+ private static final String TAG = "Gallery";
+ private static final int CROP_MSG = 10;
+ private RenderView mRenderView = null;
+ private GridLayer mGridLayer;
+ private final Handler mHandler = new Handler();
+ private ReverseGeocoder mReverseGeocoder;
+ private boolean mPause;
+ private MediaScannerConnection mConnection;
+ private WakeLock mWakeLock;
+ private HashMap<String, Boolean> mAccountsEnabled;
+ private static final boolean TEST_WALLPAPER = false;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- final boolean imageManagerHasStorage = ImageManager.quickHasStorage();
- if (TEST_WALLPAPER || (isViewIntent() && getIntent().getData().equals(Images.Media.EXTERNAL_CONTENT_URI))) {
- if (!imageManagerHasStorage) {
- Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
- finish();
- } else {
- PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow.All");
- mWakeLock.acquire();
- Slideshow slideshow = new Slideshow(this);
- slideshow.setDataSource(new RandomDataSource());
- setContentView(slideshow);
- }
- return;
- }
- boolean isCacheReady = CacheService.isCacheReady(false);
- CacheService.startCache(this, false);
- if (PIXEL_DENSITY == 0.0f) {
- DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
- PIXEL_DENSITY = metrics.density;
- }
- mReverseGeocoder = new ReverseGeocoder(this);
- mRenderView = new RenderView(this);
- mGridLayer = new GridLayer(this, (int) (96.0f * PIXEL_DENSITY), (int) (72.0f * PIXEL_DENSITY), new GridLayoutInterface(4),
- mRenderView);
- mRenderView.setRootLayer(mGridLayer);
- setContentView(mRenderView);
- if (!isPickIntent() && !isViewIntent()) {
- PicasaDataSource picasaDataSource = new PicasaDataSource(this);
- if (imageManagerHasStorage) {
- LocalDataSource localDataSource = new LocalDataSource(this);
- ConcatenatedDataSource combinedDataSource = new ConcatenatedDataSource(localDataSource, picasaDataSource);
- mGridLayer.setDataSource(combinedDataSource);
- } else {
- mGridLayer.setDataSource(picasaDataSource);
- }
- if (!imageManagerHasStorage) {
- Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
- } else {
- if (!isCacheReady) {
- Toast.makeText(this, getResources().getString(R.string.loading_new), Toast.LENGTH_LONG).show();
- } else {
- // Toast.makeText(this, getResources().getString(R.string.initializing), Toast.LENGTH_SHORT).show();
- }
- }
- } else if (!isViewIntent()) {
- Intent intent = getIntent();
- if (intent != null) {
- String type = intent.resolveType(this);
- boolean includeImages = isImageType(type);
- boolean includeVideos = isVideoType(type);
- LocalDataSource localDataSource = new LocalDataSource(this);
- ((LocalDataSource) localDataSource).setMimeFilter(!includeImages, !includeVideos);
- if (includeImages) {
- PicasaDataSource picasaDataSource = new PicasaDataSource(this);
- if (imageManagerHasStorage) {
- ConcatenatedDataSource combinedDataSource = new ConcatenatedDataSource(localDataSource, picasaDataSource);
- mGridLayer.setDataSource(combinedDataSource);
- } else {
- mGridLayer.setDataSource(picasaDataSource);
- }
- } else {
- mGridLayer.setDataSource(localDataSource);
- }
- mGridLayer.setPickIntent(true);
- if (!imageManagerHasStorage) {
- Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
- } else {
- Toast.makeText(this, getResources().getString(R.string.pick_prompt), Toast.LENGTH_LONG).show();
- }
- }
- } else {
- // View intent for images.
- Uri uri = getIntent().getData();
- boolean slideshow = getIntent().getBooleanExtra("slideshow", false);
- SingleDataSource localDataSource = new SingleDataSource(this, uri.toString(), slideshow);
- PicasaDataSource picasaDataSource = new PicasaDataSource(this);
- ConcatenatedDataSource combinedDataSource = new ConcatenatedDataSource(localDataSource, picasaDataSource);
- mGridLayer.setDataSource(combinedDataSource);
- mGridLayer.setViewIntent(true, Utils.getBucketNameFromUri(uri));
- if (SingleDataSource.isSingleImageMode(uri.toString())) {
- mGridLayer.setSingleImage(false);
- } else if (slideshow) {
- mGridLayer.setSingleImage(true);
- mGridLayer.startSlideshow();
- }
- // Toast.makeText(this, getResources().getString(R.string.initializing), Toast.LENGTH_SHORT).show();
- }
- Log.i(TAG, "onCreate");
- }
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final boolean imageManagerHasStorage = ImageManager.quickHasStorage();
+ if (TEST_WALLPAPER || (isViewIntent() && getIntent().getData().equals(Images.Media.EXTERNAL_CONTENT_URI))) {
+ if (!imageManagerHasStorage) {
+ Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
+ finish();
+ } else {
+ PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow.All");
+ mWakeLock.acquire();
+ Slideshow slideshow = new Slideshow(this);
+ slideshow.setDataSource(new RandomDataSource());
+ setContentView(slideshow);
+ }
+ return;
+ }
+ final boolean isCacheReady = CacheService.isCacheReady(false);
+ CacheService.startCache(this, false);
+ if (PIXEL_DENSITY == 0.0f) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ PIXEL_DENSITY = metrics.density;
+ }
+ mReverseGeocoder = new ReverseGeocoder(this);
+ mRenderView = new RenderView(this);
+ mGridLayer = new GridLayer(this, (int) (96.0f * PIXEL_DENSITY), (int) (72.0f * PIXEL_DENSITY), new GridLayoutInterface(4),
+ mRenderView);
+ mRenderView.setRootLayer(mGridLayer);
+ setContentView(mRenderView);
+
+ // Creating the DataSource objects
+ final PicasaDataSource picasaDataSource = new PicasaDataSource(this);
+ final LocalDataSource localDataSource = new LocalDataSource(this);
+ final ConcatenatedDataSource combinedDataSource = new ConcatenatedDataSource(localDataSource, picasaDataSource);
+
+ // Depending upon the intent, we assign the right dataSource.
+ if (!isPickIntent() && !isViewIntent()) {
+ if (imageManagerHasStorage) {
+ mGridLayer.setDataSource(combinedDataSource);
+ } else {
+ mGridLayer.setDataSource(picasaDataSource);
+ }
+ if (!imageManagerHasStorage) {
+ Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
+ } else if (!isCacheReady) {
+ Toast.makeText(this, getResources().getString(R.string.loading_new), Toast.LENGTH_LONG).show();
+ }
+ } else if (!isViewIntent()) {
+ final Intent intent = getIntent();
+ if (intent != null) {
+ final String type = intent.resolveType(this);
+ boolean includeImages = isImageType(type);
+ boolean includeVideos = isVideoType(type);
+ ((LocalDataSource) localDataSource).setMimeFilter(!includeImages, !includeVideos);
+ if (includeImages) {
+ if (imageManagerHasStorage) {
+ mGridLayer.setDataSource(combinedDataSource);
+ } else {
+ mGridLayer.setDataSource(picasaDataSource);
+ }
+ } else {
+ mGridLayer.setDataSource(localDataSource);
+ }
+ mGridLayer.setPickIntent(true);
+ if (!imageManagerHasStorage) {
+ Toast.makeText(this, getResources().getString(R.string.no_sd_card), Toast.LENGTH_LONG).show();
+ } else {
+ Toast.makeText(this, getResources().getString(R.string.pick_prompt), Toast.LENGTH_LONG).show();
+ }
+ }
+ } else {
+ // View intent for images.
+ Uri uri = getIntent().getData();
+ boolean slideshow = getIntent().getBooleanExtra("slideshow", false);
+ final SingleDataSource singleDataSource = new SingleDataSource(this, uri.toString(), slideshow);
+ final ConcatenatedDataSource singleCombinedDataSource = new ConcatenatedDataSource(singleDataSource, picasaDataSource);
+ mGridLayer.setDataSource(singleCombinedDataSource);
+ mGridLayer.setViewIntent(true, Utils.getBucketNameFromUri(uri));
+ if (SingleDataSource.isSingleImageMode(uri.toString())) {
+ mGridLayer.setSingleImage(false);
+ } else if (slideshow) {
+ mGridLayer.setSingleImage(true);
+ mGridLayer.startSlideshow();
+ }
+ }
+ // We record the set of enabled accounts for picasa.
+ mAccountsEnabled = PicasaDataSource.getAccountStatus(this);
+ Log.i(TAG, "onCreate");
+ }
- public ReverseGeocoder getReverseGeocoder() {
- return mReverseGeocoder;
- }
+ public ReverseGeocoder getReverseGeocoder() {
+ return mReverseGeocoder;
+ }
- public Handler getHandler() {
- return mHandler;
- }
+ public Handler getHandler() {
+ return mHandler;
+ }
- @Override
- public void onRestart() {
- super.onRestart();
- }
+ @Override
+ public void onRestart() {
+ super.onRestart();
+ }
- @Override
- public void onStart() {
- super.onStart();
- }
+ @Override
+ public void onStart() {
+ super.onStart();
+ }
- @Override
- public void onResume() {
- super.onResume();
- if (mRenderView != null)
- mRenderView.onResume();
- if (NEEDS_REFRESH) {
- NEEDS_REFRESH = false;
- CacheService.markDirtyImmediate(LocalDataSource.CAMERA_BUCKET_ID);
- CacheService.markDirtyImmediate(LocalDataSource.DOWNLOAD_BUCKET_ID);
- CacheService.startCache(this, false);
- }
- mPause = false;
- }
+ @Override
+ public void onResume() {
+ super.onResume();
+ if (mRenderView != null)
+ mRenderView.onResume();
+ if (mPause) {
+ // We check to see if the authenticated accounts have changed, and
+ // if so, reload the datasource.
+ HashMap<String, Boolean> accountsEnabled = PicasaDataSource.getAccountStatus(this);
+ String[] keys = new String[accountsEnabled.size()];
+ keys = accountsEnabled.keySet().toArray(keys);
+ int numKeys = keys.length;
+ for (int i = 0; i < numKeys; ++i) {
+ String key = keys[i];
+ boolean newValue = accountsEnabled.get(key).booleanValue();
+ boolean oldValue = false;
+ Boolean oldValObj = mAccountsEnabled.get(key);
+ if (oldValObj != null) {
+ oldValue = oldValObj.booleanValue();
+ }
+ if (oldValue != newValue) {
+ // Reload the datasource.
+ mGridLayer.setDataSource(mGridLayer.getDataSource());
+ break;
+ }
+ }
+ mAccountsEnabled = accountsEnabled;
+ mPause = false;
+ }
+ }
- @Override
- public void onPause() {
- super.onPause();
- if (mRenderView != null)
- mRenderView.onPause();
- mPause = true;
- }
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mRenderView != null)
+ mRenderView.onPause();
+ mPause = true;
+ }
- public boolean isPaused() {
- return mPause;
- }
+ public boolean isPaused() {
+ return mPause;
+ }
- @Override
- public void onStop() {
- super.onStop();
- if (mGridLayer != null)
- mGridLayer.stop();
- if (mReverseGeocoder != null) {
- mReverseGeocoder.flushCache();
- }
- LocalDataSource.sThumbnailCache.flush();
- LocalDataSource.sThumbnailCacheVideo.flush();
- PicasaDataSource.sThumbnailCache.flush();
- CacheService.startCache(this, true);
- }
+ @Override
+ public void onStop() {
+ super.onStop();
+ if (mGridLayer != null)
+ mGridLayer.stop();
+ if (mReverseGeocoder != null) {
+ mReverseGeocoder.flushCache();
+ }
+ LocalDataSource.sThumbnailCache.flush();
+ LocalDataSource.sThumbnailCacheVideo.flush();
+ PicasaDataSource.sThumbnailCache.flush();
+ CacheService.startCache(this, true);
+ }
- @Override
- public void onDestroy() {
- // Force GLThread to exit.
- setContentView(R.layout.main);
- if (mGridLayer != null) {
- DataSource dataSource = mGridLayer.getDataSource();
- if (dataSource != null) {
- dataSource.shutdown();
- }
- mGridLayer.shutdown();
- }
- if (mWakeLock != null) {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- mWakeLock = null;
- }
- if (mReverseGeocoder != null)
- mReverseGeocoder.shutdown();
- if (mRenderView != null) {
- mRenderView.shutdown();
- mRenderView = null;
- }
- mGridLayer = null;
- super.onDestroy();
- Log.i(TAG, "onDestroy");
- }
+ @Override
+ public void onDestroy() {
+ // Force GLThread to exit.
+ setContentView(R.layout.main);
+ if (mGridLayer != null) {
+ DataSource dataSource = mGridLayer.getDataSource();
+ if (dataSource != null) {
+ dataSource.shutdown();
+ }
+ mGridLayer.shutdown();
+ }
+ if (mWakeLock != null) {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ mWakeLock = null;
+ }
+ if (mReverseGeocoder != null)
+ mReverseGeocoder.shutdown();
+ if (mRenderView != null) {
+ mRenderView.shutdown();
+ mRenderView = null;
+ }
+ mGridLayer = null;
+ super.onDestroy();
+ Log.i(TAG, "onDestroy");
+ }
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- if (mGridLayer != null) {
- mGridLayer.markDirty(30);
- }
- if (mRenderView != null)
- mRenderView.requestRender();
- Log.i(TAG, "onConfigurationChanged");
- }
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mGridLayer != null) {
+ mGridLayer.markDirty(30);
+ }
+ if (mRenderView != null)
+ mRenderView.requestRender();
+ Log.i(TAG, "onConfigurationChanged");
+ }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (mRenderView != null) {
- return mRenderView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
- } else {
- return super.onKeyDown(keyCode, event);
- }
- }
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (mRenderView != null) {
+ return mRenderView.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event);
+ } else {
+ return super.onKeyDown(keyCode, event);
+ }
+ }
- private boolean isPickIntent() {
- String action = getIntent().getAction();
- return (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action));
- }
+ private boolean isPickIntent() {
+ String action = getIntent().getAction();
+ return (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action));
+ }
- private boolean isViewIntent() {
- String action = getIntent().getAction();
- return Intent.ACTION_VIEW.equals(action);
- }
+ private boolean isViewIntent() {
+ String action = getIntent().getAction();
+ return Intent.ACTION_VIEW.equals(action);
+ }
- private boolean isImageType(String type) {
- return type.equals("vnd.android.cursor.dir/image") || type.equals("image/*");
- }
+ private boolean isImageType(String type) {
+ return type.equals("vnd.android.cursor.dir/image") || type.equals("image/*");
+ }
- private boolean isVideoType(String type) {
- return type.equals("vnd.android.cursor.dir/video") || type.equals("video/*");
- }
+ private boolean isVideoType(String type) {
+ return type.equals("vnd.android.cursor.dir/video") || type.equals("video/*");
+ }
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- switch (requestCode) {
- case CROP_MSG: {
- if (resultCode == RESULT_OK) {
- setResult(resultCode, data);
- finish();
- }
- break;
- }
- case CROP_MSG_INTERNAL: {
- // We cropped an image, we must try to set the focus of the camera to that image.
- if (resultCode == RESULT_OK) {
- String contentUri = data.getAction();
- if (mGridLayer != null) {
- mGridLayer.focusItem(contentUri);
- }
- }
- break;
- }
- }
- }
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case CROP_MSG: {
+ if (resultCode == RESULT_OK) {
+ setResult(resultCode, data);
+ finish();
+ }
+ break;
+ }
+ case CROP_MSG_INTERNAL: {
+ // We cropped an image, we must try to set the focus of the camera
+ // to that image.
+ if (resultCode == RESULT_OK) {
+ String contentUri = data.getAction();
+ if (mGridLayer != null) {
+ mGridLayer.focusItem(contentUri);
+ }
+ }
+ break;
+ }
+ }
+ }
- @Override
- public void onLowMemory() {
- if (mRenderView != null) {
- mRenderView.handleLowMemory();
- }
- }
+ @Override
+ public void onLowMemory() {
+ if (mRenderView != null) {
+ mRenderView.handleLowMemory();
+ }
+ }
- public void launchCropperOrFinish(final MediaItem item) {
- final Bundle myExtras = getIntent().getExtras();
- String cropValue = myExtras != null ? myExtras.getString("crop") : null;
- final String contentUri = item.mContentUri;
- if (cropValue != null) {
- Bundle newExtras = new Bundle();
- if (cropValue.equals("circle")) {
- newExtras.putString("circleCrop", "true");
- }
- Intent cropIntent = new Intent();
- cropIntent.setData(Uri.parse(contentUri));
- cropIntent.setClass(this, CropImage.class);
- cropIntent.putExtras(newExtras);
- // Pass through any extras that were passed in.
- cropIntent.putExtras(myExtras);
- startActivityForResult(cropIntent, CROP_MSG);
- } else {
- if (contentUri.startsWith("http://")) {
- // This is a http uri, we must save it locally first and generate a content uri from it.
- final ProgressDialog dialog = ProgressDialog.show(this, this.getResources().getString(R.string.initializing),
- getResources().getString(R.string.running_face_detection), true, false);
- if (contentUri != null) {
- MediaScannerConnection.MediaScannerConnectionClient client = new MediaScannerConnection.MediaScannerConnectionClient() {
- public void onMediaScannerConnected() {
- if (mConnection != null) {
- try {
- final String path = UriTexture.writeHttpDataInDirectory(Gallery.this, contentUri,
- LocalDataSource.DOWNLOAD_BUCKET_NAME);
- if (path != null) {
- mConnection.scanFile(path, item.mMimeType);
- } else {
- shutdown("");
- }
- } catch (Exception e) {
- shutdown("");
- }
- }
- }
+ public void launchCropperOrFinish(final MediaItem item) {
+ final Bundle myExtras = getIntent().getExtras();
+ String cropValue = myExtras != null ? myExtras.getString("crop") : null;
+ final String contentUri = item.mContentUri;
+ if (cropValue != null) {
+ Bundle newExtras = new Bundle();
+ if (cropValue.equals("circle")) {
+ newExtras.putString("circleCrop", "true");
+ }
+ Intent cropIntent = new Intent();
+ cropIntent.setData(Uri.parse(contentUri));
+ cropIntent.setClass(this, CropImage.class);
+ cropIntent.putExtras(newExtras);
+ // Pass through any extras that were passed in.
+ cropIntent.putExtras(myExtras);
+ startActivityForResult(cropIntent, CROP_MSG);
+ } else {
+ if (contentUri.startsWith("http://")) {
+ // This is a http uri, we must save it locally first and
+ // generate a content uri from it.
+ final ProgressDialog dialog = ProgressDialog.show(this, this.getResources().getString(R.string.initializing),
+ getResources().getString(R.string.running_face_detection), true, false);
+ if (contentUri != null) {
+ MediaScannerConnection.MediaScannerConnectionClient client = new MediaScannerConnection.MediaScannerConnectionClient() {
+ public void onMediaScannerConnected() {
+ if (mConnection != null) {
+ try {
+ final String path = UriTexture.writeHttpDataInDirectory(Gallery.this, contentUri,
+ LocalDataSource.DOWNLOAD_BUCKET_NAME);
+ if (path != null) {
+ mConnection.scanFile(path, item.mMimeType);
+ } else {
+ shutdown("");
+ }
+ } catch (Exception e) {
+ shutdown("");
+ }
+ }
+ }
- public void onScanCompleted(String path, Uri uri) {
- shutdown(uri.toString());
- }
+ public void onScanCompleted(String path, Uri uri) {
+ shutdown(uri.toString());
+ }
- public void shutdown(String uri) {
- dialog.dismiss();
- performReturn(myExtras, uri.toString());
- if (mConnection != null) {
- mConnection.disconnect();
- }
- }
- };
- MediaScannerConnection connection = new MediaScannerConnection(Gallery.this, client);
- connection.connect();
- mConnection = connection;
- }
- } else {
- performReturn(myExtras, contentUri);
- }
- }
- }
+ public void shutdown(String uri) {
+ dialog.dismiss();
+ performReturn(myExtras, uri.toString());
+ if (mConnection != null) {
+ mConnection.disconnect();
+ }
+ }
+ };
+ MediaScannerConnection connection = new MediaScannerConnection(Gallery.this, client);
+ connection.connect();
+ mConnection = connection;
+ }
+ } else {
+ performReturn(myExtras, contentUri);
+ }
+ }
+ }
- private void performReturn(Bundle myExtras, String contentUri) {
- Intent result = new Intent(null, Uri.parse(contentUri));
- if (myExtras != null && myExtras.getBoolean("return-data")) {
- // The size of a transaction should be below 100K.
- Bitmap bitmap = null;
- try {
- bitmap = UriTexture.createFromUri(this, contentUri, 1024, 1024, 0, null);
- } catch (IOException e) {
- ;
- } catch (URISyntaxException e) {
- ;
- }
- if (bitmap != null) {
- result.putExtra("data", bitmap);
- }
- }
- setResult(RESULT_OK, result);
- finish();
- }
+ private void performReturn(Bundle myExtras, String contentUri) {
+ Intent result = new Intent(null, Uri.parse(contentUri));
+ if (myExtras != null && myExtras.getBoolean("return-data")) {
+ // The size of a transaction should be below 100K.
+ Bitmap bitmap = null;
+ try {
+ bitmap = UriTexture.createFromUri(this, contentUri, 1024, 1024, 0, null);
+ } catch (IOException e) {
+ ;
+ } catch (URISyntaxException e) {
+ ;
+ }
+ if (bitmap != null) {
+ result.putExtra("data", bitmap);
+ }
+ }
+ setResult(RESULT_OK, result);
+ finish();
+ }
}
diff --git a/src/com/cooliris/media/GridCameraManager.java b/src/com/cooliris/media/GridCameraManager.java
index 0e43ef3..b4eb1c2 100644
--- a/src/com/cooliris/media/GridCameraManager.java
+++ b/src/com/cooliris/media/GridCameraManager.java
@@ -1,5 +1,6 @@
package com.cooliris.media;
+
public final class GridCameraManager {
private final GridCamera mCamera;
private static final Pool<Vector3f> sPool;
diff --git a/src/com/cooliris/media/GridInputProcessor.java b/src/com/cooliris/media/GridInputProcessor.java
index c7050cb..94a15d8 100644
--- a/src/com/cooliris/media/GridInputProcessor.java
+++ b/src/com/cooliris/media/GridInputProcessor.java
@@ -182,6 +182,9 @@
layer.setZoomValue(1.0f);
}
if (keyCode == KeyEvent.KEYCODE_MENU) {
+ if (mLayer.getFeed() != null && mLayer.getFeed().isSingleImageMode()) {
+ return true;
+ }
if (layer.getHud().getMode() == HudLayer.MODE_NORMAL)
layer.enterSelectionMode();
else
diff --git a/src/com/cooliris/media/GridLayer.java b/src/com/cooliris/media/GridLayer.java
index dc2b09f..8cd05c2 100644
--- a/src/com/cooliris/media/GridLayer.java
+++ b/src/com/cooliris/media/GridLayer.java
@@ -7,1426 +7,1437 @@
import android.opengl.GLU;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.content.Context;
public final class GridLayer extends RootLayer implements MediaFeed.Listener, TimeBar.Listener {
- public static final int STATE_MEDIA_SETS = 0;
- public static final int STATE_GRID_VIEW = 1;
- public static final int STATE_FULL_SCREEN = 2;
- public static final int STATE_TIMELINE = 3;
+ public static final int STATE_MEDIA_SETS = 0;
+ public static final int STATE_GRID_VIEW = 1;
+ public static final int STATE_FULL_SCREEN = 2;
+ public static final int STATE_TIMELINE = 3;
- public static final int ANCHOR_LEFT = 0;
- public static final int ANCHOR_RIGHT = 1;
- public static final int ANCHOR_CENTER = 2;
+ public static final int ANCHOR_LEFT = 0;
+ public static final int ANCHOR_RIGHT = 1;
+ public static final int ANCHOR_CENTER = 2;
- public static final int MAX_ITEMS_PER_SLOT = 12;
- public static final int MAX_DISPLAYED_ITEMS_PER_SLOT = 4;
- public static final int MAX_DISPLAY_SLOTS = 96;
- public static final int MAX_ITEMS_DRAWABLE = MAX_ITEMS_PER_SLOT * MAX_DISPLAY_SLOTS;
+ public static final int MAX_ITEMS_PER_SLOT = 12;
+ public static final int MAX_DISPLAYED_ITEMS_PER_SLOT = 4;
+ public static final int MAX_DISPLAY_SLOTS = 96;
+ public static final int MAX_ITEMS_DRAWABLE = MAX_ITEMS_PER_SLOT * MAX_DISPLAY_SLOTS;
- private static final float SLIDESHOW_TRANSITION_TIME = 3.5f;
+ private static final float SLIDESHOW_TRANSITION_TIME = 3.5f;
- private static HudLayer sHud;
- private int mState;
- private static final IndexRange sBufferedVisibleRange = new IndexRange();
- private static final IndexRange sVisibleRange = new IndexRange();
- private static final IndexRange sPreviousDataRange = new IndexRange();
- private static final IndexRange sCompleteRange = new IndexRange();
-
- private static final Pool<Vector3f> sTempVec;
- private static final Pool<Vector3f> sTempVecAlt;
- static {
- Vector3f[] vectorPool = new Vector3f[128];
- int length = vectorPool.length;
- for (int i = 0; i < length; ++i) {
- vectorPool[i] = new Vector3f();
- }
- Vector3f[] vectorPoolRenderThread = new Vector3f[128];
- length = vectorPoolRenderThread.length;
- for (int i = 0; i < length; ++i) {
- vectorPoolRenderThread[i] = new Vector3f();
- }
- sTempVec = new Pool<Vector3f>(vectorPool);
- sTempVecAlt = new Pool<Vector3f>(vectorPoolRenderThread);
- }
-
- private static final ArrayList<MediaItem> sTempList = new ArrayList<MediaItem>();
- private static final MediaItem[] sTempHash = new MediaItem[64];
-
- private static final Vector3f sDeltaAnchorPositionUncommited = new Vector3f();
- private static Vector3f sDeltaAnchorPosition = new Vector3f();
+ private static HudLayer sHud;
+ private int mState;
+ private static final IndexRange sBufferedVisibleRange = new IndexRange();
+ private static final IndexRange sVisibleRange = new IndexRange();
+ private static final IndexRange sPreviousDataRange = new IndexRange();
+ private static final IndexRange sCompleteRange = new IndexRange();
- // The display primitives.
- private GridDrawables mDrawables;
- private float mSelectedAlpha = 0.0f;
- private float mTargetAlpha = 0.0f;
+ private static final Pool<Vector3f> sTempVec;
+ private static final Pool<Vector3f> sTempVecAlt;
+ static {
+ Vector3f[] vectorPool = new Vector3f[128];
+ int length = vectorPool.length;
+ for (int i = 0; i < length; ++i) {
+ vectorPool[i] = new Vector3f();
+ }
+ Vector3f[] vectorPoolRenderThread = new Vector3f[128];
+ length = vectorPoolRenderThread.length;
+ for (int i = 0; i < length; ++i) {
+ vectorPoolRenderThread[i] = new Vector3f();
+ }
+ sTempVec = new Pool<Vector3f>(vectorPool);
+ sTempVecAlt = new Pool<Vector3f>(vectorPoolRenderThread);
+ }
- private GridCamera mCamera;
- private GridCameraManager mCameraManager;
- private GridDrawManager mDrawManager;
- private GridInputProcessor mInputProcessor;
+ private static final ArrayList<MediaItem> sTempList = new ArrayList<MediaItem>();
+ private static final MediaItem[] sTempHash = new MediaItem[64];
- private boolean mFeedAboutToChange;
- private boolean mPerformingLayoutChange;
- private boolean mFeedChanged;
+ private static final Vector3f sDeltaAnchorPositionUncommited = new Vector3f();
+ private static Vector3f sDeltaAnchorPosition = new Vector3f();
- private final LayoutInterface mLayoutInterface;
- private static final LayoutInterface sfullScreenLayoutInterface = new GridLayoutInterface(1);
-
- private MediaFeed mMediaFeed;
- private boolean mInAlbum = false;
- private int mCurrentExpandedSlot;
+ // The display primitives.
+ private GridDrawables mDrawables;
+ private float mSelectedAlpha = 0.0f;
+ private float mTargetAlpha = 0.0f;
- private static final DisplayList sDisplayList = new DisplayList();
- private static final DisplayItem[] sDisplayItems = new DisplayItem[MAX_ITEMS_DRAWABLE];
- private static final DisplaySlot[] sDisplaySlots = new DisplaySlot[MAX_DISPLAY_SLOTS];
- private static ArrayList<MediaItem> sVisibleItems;
-
- private float mTimeElapsedSinceTransition;
- private BackgroundLayer mBackground;
- private boolean mLocationFilter;
- private float mZoomValue = 1.0f;
- private float mCurrentFocusItemWidth = 1.0f;
- private float mCurrentFocusItemHeight = 1.0f;
- private float mTimeElapsedSinceGridViewReady = 0.0f;
+ private GridCamera mCamera;
+ private GridCameraManager mCameraManager;
+ private GridDrawManager mDrawManager;
+ private GridInputProcessor mInputProcessor;
- private boolean mSlideshowMode;
- private boolean mNoDeleteMode = false;
- private float mTimeElapsedSinceView;
- private static final MediaBucketList sBucketList = new MediaBucketList();
- private float mTimeElapsedSinceStackViewReady;
+ private boolean mFeedAboutToChange;
+ private boolean mPerformingLayoutChange;
+ private boolean mFeedChanged;
- private Context mContext;
- private RenderView mView;
- private boolean mPickIntent;
- private boolean mViewIntent;
- private WakeLock mWakeLock;
- private int mStartMemoryRange;
- private int mFramesDirty;
- private String mRequestFocusContentUri;
- private int mFrameCount;
+ private final LayoutInterface mLayoutInterface;
+ private static final LayoutInterface sfullScreenLayoutInterface = new GridLayoutInterface(1);
- public GridLayer(Context context, int itemWidth, int itemHeight, LayoutInterface layoutInterface, RenderView view) {
- mBackground = new BackgroundLayer(this);
- mContext = context;
- mView = view;
-
- DisplaySlot[] displaySlots = sDisplaySlots;
- for (int i = 0; i < MAX_DISPLAY_SLOTS; ++i) {
- DisplaySlot slot = new DisplaySlot();
- displaySlots[i] = slot;
- }
- mLayoutInterface = layoutInterface;
- mCamera = new GridCamera(0, 0, itemWidth, itemHeight);
- mDrawables = new GridDrawables(itemWidth, itemHeight);
- sBufferedVisibleRange.set(Shared.INVALID, Shared.INVALID);
- sVisibleRange.set(Shared.INVALID, Shared.INVALID);
- sCompleteRange.set(Shared.INVALID, Shared.INVALID);
- sPreviousDataRange.set(Shared.INVALID, Shared.INVALID);
- sDeltaAnchorPosition.set(0, 0, 0);
- sDeltaAnchorPositionUncommited.set(0, 0, 0);
- sBucketList.clear();
-
- sVisibleItems = new ArrayList<MediaItem>();
- if (sHud == null) {
- sHud = new HudLayer(context);
- }
- sHud.setContext(context);
- sHud.setGridLayer(this);
- sHud.getPathBar().clear();
- sHud.setGridLayer(this);
- sHud.getTimeBar().setListener(this);
- sHud.getPathBar().pushLabel(R.drawable.icon_home_small, context.getResources().getString(R.string.app_name),
- new Runnable() {
- public void run() {
- if (sHud.getAlpha() == 1.0f) {
- if (!mFeedAboutToChange) {
- setState(STATE_MEDIA_SETS);
- }
- } else {
- sHud.setAlpha(1.0f);
- }
- }
- });
- mCameraManager = new GridCameraManager(mCamera);
- mDrawManager = new GridDrawManager(context, mCamera, mDrawables, sDisplayList, sDisplayItems, sDisplaySlots);
- mInputProcessor = new GridInputProcessor(context, mCamera, this, mView, sTempVec, sDisplayItems);
- setState(STATE_MEDIA_SETS);
- }
+ private MediaFeed mMediaFeed;
+ private boolean mInAlbum = false;
+ private int mCurrentExpandedSlot;
- public HudLayer getHud() {
- return sHud;
- }
+ private static final DisplayList sDisplayList = new DisplayList();
+ private static final DisplayItem[] sDisplayItems = new DisplayItem[MAX_ITEMS_DRAWABLE];
+ private static final DisplaySlot[] sDisplaySlots = new DisplaySlot[MAX_DISPLAY_SLOTS];
+ private static ArrayList<MediaItem> sVisibleItems;
- public void shutdown() {
- if (mMediaFeed != null) {
- mMediaFeed.shutdown();
- }
- mContext = null;
- mBackground = null;
- sBucketList.clear();
- mCameraManager = null;
- mDrawManager = null;
- mView = null;
- }
+ private float mTimeElapsedSinceTransition;
+ private BackgroundLayer mBackground;
+ private boolean mLocationFilter;
+ private float mZoomValue = 1.0f;
+ private float mCurrentFocusItemWidth = 1.0f;
+ private float mCurrentFocusItemHeight = 1.0f;
+ private float mTimeElapsedSinceGridViewReady = 0.0f;
- public void stop() {
- endSlideshow();
- mBackground.clear();
- handleLowMemory();
- }
+ private boolean mSlideshowMode;
+ private boolean mNoDeleteMode = false;
+ private float mTimeElapsedSinceView;
+ private static final MediaBucketList sBucketList = new MediaBucketList();
+ private float mTimeElapsedSinceStackViewReady;
- @Override
- public void generate(RenderView view, RenderView.Lists lists) {
- lists.updateList.add(this);
- lists.opaqueList.add(this);
- mBackground.generate(view, lists);
- lists.blendedList.add(this);
- lists.hitTestList.add(this);
- sHud.generate(view, lists);
- }
+ private Context mContext;
+ private RenderView mView;
+ private boolean mPickIntent;
+ private boolean mViewIntent;
+ private WakeLock mWakeLock;
+ private int mStartMemoryRange;
+ private int mFramesDirty;
+ private String mRequestFocusContentUri;
+ private int mFrameCount;
+ private boolean mNeedsInit;
- @Override
- protected void onSizeChanged() {
- sHud.setSize(mWidth, mHeight);
- sHud.setAlpha(1.0f);
- mBackground.setSize(mWidth, mHeight);
- mTimeElapsedSinceTransition = 0.0f;
- if (mView != null) {
- mView.requestRender();
- }
- }
+ public GridLayer(Context context, int itemWidth, int itemHeight, LayoutInterface layoutInterface, RenderView view) {
+ mBackground = new BackgroundLayer(this);
+ mContext = context;
+ mView = view;
+ mNeedsInit = true;
- public int getState() {
- return mState;
- }
+ DisplaySlot[] displaySlots = sDisplaySlots;
+ for (int i = 0; i < MAX_DISPLAY_SLOTS; ++i) {
+ DisplaySlot slot = new DisplaySlot();
+ displaySlots[i] = slot;
+ }
+ mLayoutInterface = layoutInterface;
+ mCamera = new GridCamera(0, 0, itemWidth, itemHeight);
+ mDrawables = new GridDrawables(itemWidth, itemHeight);
+ sBufferedVisibleRange.set(Shared.INVALID, Shared.INVALID);
+ sVisibleRange.set(Shared.INVALID, Shared.INVALID);
+ sCompleteRange.set(Shared.INVALID, Shared.INVALID);
+ sPreviousDataRange.set(Shared.INVALID, Shared.INVALID);
+ sDeltaAnchorPosition.set(0, 0, 0);
+ sDeltaAnchorPositionUncommited.set(0, 0, 0);
+ sBucketList.clear();
- public void setState(int state) {
- boolean feedUnchanged = false;
- if (mState == state) {
- feedUnchanged = true;
- }
- GridLayoutInterface layoutInterface = (GridLayoutInterface) mLayoutInterface;
- GridLayoutInterface oldLayout = (GridLayoutInterface) sfullScreenLayoutInterface;
- oldLayout.mNumRows = layoutInterface.mNumRows;
- oldLayout.mSpacingX = layoutInterface.mSpacingX;
- oldLayout.mSpacingY = layoutInterface.mSpacingY;
- GridCamera camera = mCamera;
- int numMaxRows = (camera.mHeight >= camera.mWidth) ? 4 : 3;
- MediaFeed feed = mMediaFeed;
- boolean performLayout = true;
- mZoomValue = 1.0f;
- float yStretch = camera.mDefaultAspectRatio / camera.mAspectRatio;
- if (yStretch < 1.0f) {
- yStretch = 1.0f;
- }
- switch (state) {
- case STATE_GRID_VIEW:
- mTimeElapsedSinceGridViewReady = 0.0f;
- if (feed != null && feedUnchanged == false) {
- boolean updatedData = feed.restorePreviousClusteringState();
- if (updatedData) {
- performLayout = false;
- }
- }
- layoutInterface.mNumRows = numMaxRows;
- layoutInterface.mSpacingX = (int) (10 * Gallery.PIXEL_DENSITY);
- layoutInterface.mSpacingY = (int) (10 * Gallery.PIXEL_DENSITY);
- if (mState == STATE_MEDIA_SETS) {
- // Entering album.
- mInAlbum = true;
- MediaSet set = feed.getCurrentSet();
- int icon = mDrawables.getIconForSet(set, true);
- if (set != null) {
- sHud.getPathBar().pushLabel(icon, set.mNoCountTitleString, new Runnable() {
- public void run() {
- if (mFeedAboutToChange) {
- return;
- }
- if (sHud.getAlpha() == 1.0f) {
- disableLocationFiltering();
- mInputProcessor.clearSelection();
- setState(STATE_GRID_VIEW);
- } else {
- sHud.setAlpha(1.0f);
- }
- }
- });
- }
- }
- if (mState == STATE_FULL_SCREEN) {
- sHud.getPathBar().popLabel();
- }
- break;
- case STATE_TIMELINE:
- mTimeElapsedSinceStackViewReady = 0.0f;
- if (feed != null && feedUnchanged == false) {
- feed.performClustering();
- performLayout = false;
- }
- disableLocationFiltering();
- layoutInterface.mNumRows = numMaxRows - 1;
- layoutInterface.mSpacingX = (int) (100 * Gallery.PIXEL_DENSITY);
- layoutInterface.mSpacingY = (int) (70 * Gallery.PIXEL_DENSITY * yStretch);
- break;
- case STATE_FULL_SCREEN:
- layoutInterface.mNumRows = 1;
- layoutInterface.mSpacingX = (int) (40 * Gallery.PIXEL_DENSITY);
- layoutInterface.mSpacingY = (int) (40 * Gallery.PIXEL_DENSITY);
- if (mState != STATE_FULL_SCREEN) {
- sHud.getPathBar().pushLabel(R.drawable.ic_fs_details, "", new Runnable() {
- public void run() {
- if (sHud.getAlpha() == 1.0f) {
- sHud.swapFullscreenLabel();
- }
- sHud.setAlpha(1.0f);
- }
- });
- }
- break;
- case STATE_MEDIA_SETS:
- mTimeElapsedSinceStackViewReady = 0.0f;
- if (feed != null && feedUnchanged == false) {
- feed.restorePreviousClusteringState();
- feed.expandMediaSet(Shared.INVALID);
- performLayout = false;
- }
- disableLocationFiltering();
- mInputProcessor.clearSelection();
- layoutInterface.mNumRows = numMaxRows - 1;
- layoutInterface.mSpacingX = (int) (100 * Gallery.PIXEL_DENSITY);
- layoutInterface.mSpacingY = (int) (70 * Gallery.PIXEL_DENSITY * yStretch);
- if (mInAlbum) {
- if (mState == STATE_FULL_SCREEN) {
- sHud.getPathBar().popLabel();
- }
- sHud.getPathBar().popLabel();
- mInAlbum = false;
- }
- break;
- }
- mState = state;
- sHud.onGridStateChanged();
- if (performLayout && mFeedAboutToChange == false) {
- onLayout(Shared.INVALID, Shared.INVALID, oldLayout);
- }
- if (state != STATE_FULL_SCREEN) {
- mCamera.moveYTo(0);
- mCamera.moveZTo(0);
- }
- }
+ sVisibleItems = new ArrayList<MediaItem>();
+ if (sHud == null) {
+ sHud = new HudLayer(context);
+ }
+ sHud.setContext(context);
+ sHud.setGridLayer(this);
+ sHud.getPathBar().clear();
+ sHud.setGridLayer(this);
+ sHud.getTimeBar().setListener(this);
+ sHud.getPathBar().pushLabel(R.drawable.icon_home_small, context.getResources().getString(R.string.app_name),
+ new Runnable() {
+ public void run() {
+ if (sHud.getAlpha() == 1.0f) {
+ if (!mFeedAboutToChange) {
+ setState(STATE_MEDIA_SETS);
+ }
+ } else {
+ sHud.setAlpha(1.0f);
+ }
+ }
+ });
+ mCameraManager = new GridCameraManager(mCamera);
+ mDrawManager = new GridDrawManager(context, mCamera, mDrawables, sDisplayList, sDisplayItems, sDisplaySlots);
+ mInputProcessor = new GridInputProcessor(context, mCamera, this, mView, sTempVec, sDisplayItems);
+ }
- protected void enableLocationFiltering(String label) {
- if (mLocationFilter == false) {
- mLocationFilter = true;
- sHud.getPathBar().pushLabel(R.drawable.icon_location_small, label, new Runnable() {
- public void run() {
- if (sHud.getAlpha() == 1.0f) {
- if (mState == STATE_FULL_SCREEN) {
- mInputProcessor.clearSelection();
- setState(STATE_GRID_VIEW);
- } else {
- disableLocationFiltering();
- }
- } else {
- sHud.setAlpha(1.0f);
- }
- }
- });
- }
- }
+ public HudLayer getHud() {
+ return sHud;
+ }
- protected void disableLocationFiltering() {
- if (mLocationFilter) {
- mLocationFilter = false;
- mMediaFeed.removeFilter();
- sHud.getPathBar().popLabel();
- }
- }
+ public void shutdown() {
+ if (mMediaFeed != null) {
+ mMediaFeed.shutdown();
+ }
+ mContext = null;
+ mBackground = null;
+ sBucketList.clear();
+ mView = null;
+ }
- boolean goBack() {
- if (mFeedAboutToChange) {
- return false;
- }
- int state = mState;
- if (mInputProcessor.getCurrentSelectedSlot() == Shared.INVALID) {
- if (mLocationFilter) {
- disableLocationFiltering();
- setState(STATE_TIMELINE);
- return true;
- }
- }
- switch (state) {
- case STATE_GRID_VIEW:
- setState(STATE_MEDIA_SETS);
- break;
- case STATE_TIMELINE:
- setState(STATE_GRID_VIEW);
- break;
- case STATE_FULL_SCREEN:
- setState(STATE_GRID_VIEW);
- mInputProcessor.clearSelection();
- break;
- default:
- return false;
- }
- return true;
- }
+ public void stop() {
+ endSlideshow();
+ mBackground.clear();
+ handleLowMemory();
+ }
- public void endSlideshow() {
- mSlideshowMode = false;
- if (mWakeLock != null) {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- mWakeLock = null;
- }
- sHud.setAlpha(1.0f);
- }
+ @Override
+ public void generate(RenderView view, RenderView.Lists lists) {
+ lists.updateList.add(this);
+ lists.opaqueList.add(this);
+ mBackground.generate(view, lists);
+ lists.blendedList.add(this);
+ lists.hitTestList.add(this);
+ sHud.generate(view, lists);
+ }
- @Override
- public void onSensorChanged(RenderView view, SensorEvent event) {
- mInputProcessor.onSensorChanged(view, event, mState);
- }
+ @Override
+ protected void onSizeChanged() {
+ sHud.setSize(mWidth, mHeight);
+ sHud.setAlpha(1.0f);
+ mBackground.setSize(mWidth, mHeight);
+ mTimeElapsedSinceTransition = 0.0f;
+ if (mView != null) {
+ mView.requestRender();
+ }
+ }
- public DataSource getDataSource() {
- if (mMediaFeed != null)
- return mMediaFeed.getDataSource();
- return null;
- }
+ public int getState() {
+ return mState;
+ }
- public void setDataSource(DataSource dataSource) {
- MediaFeed feed = mMediaFeed;
- if (feed != null) {
- feed.shutdown();
- sDisplayList.clear();
- mBackground.clear();
- }
- mMediaFeed = new MediaFeed(mContext, dataSource, this);
- mMediaFeed.start();
- }
+ public void setState(int state) {
+ boolean feedUnchanged = false;
+ if (mState == state) {
+ feedUnchanged = true;
+ }
+ GridLayoutInterface layoutInterface = (GridLayoutInterface) mLayoutInterface;
+ GridLayoutInterface oldLayout = (GridLayoutInterface) sfullScreenLayoutInterface;
+ oldLayout.mNumRows = layoutInterface.mNumRows;
+ oldLayout.mSpacingX = layoutInterface.mSpacingX;
+ oldLayout.mSpacingY = layoutInterface.mSpacingY;
+ GridCamera camera = mCamera;
+ int numMaxRows = (camera.mHeight >= camera.mWidth) ? 4 : 3;
+ MediaFeed feed = mMediaFeed;
+ boolean performLayout = true;
+ mZoomValue = 1.0f;
+ float yStretch = camera.mDefaultAspectRatio / camera.mAspectRatio;
+ if (yStretch < 1.0f) {
+ yStretch = 1.0f;
+ }
+ switch (state) {
+ case STATE_GRID_VIEW:
+ mTimeElapsedSinceGridViewReady = 0.0f;
+ if (feed != null && feedUnchanged == false) {
+ boolean updatedData = feed.restorePreviousClusteringState();
+ if (updatedData) {
+ performLayout = false;
+ }
+ }
+ layoutInterface.mNumRows = numMaxRows;
+ layoutInterface.mSpacingX = (int) (10 * Gallery.PIXEL_DENSITY);
+ layoutInterface.mSpacingY = (int) (10 * Gallery.PIXEL_DENSITY);
+ if (mState == STATE_MEDIA_SETS) {
+ // Entering album.
+ mInAlbum = true;
+ MediaSet set = feed.getCurrentSet();
+ int icon = mDrawables.getIconForSet(set, true);
+ if (set != null) {
+ sHud.getPathBar().pushLabel(icon, set.mNoCountTitleString, new Runnable() {
+ public void run() {
+ if (mFeedAboutToChange) {
+ return;
+ }
+ if (sHud.getAlpha() == 1.0f) {
+ disableLocationFiltering();
+ mInputProcessor.clearSelection();
+ setState(STATE_GRID_VIEW);
+ } else {
+ sHud.setAlpha(1.0f);
+ }
+ }
+ });
+ }
+ }
+ if (mState == STATE_FULL_SCREEN) {
+ sHud.getPathBar().popLabel();
+ }
+ break;
+ case STATE_TIMELINE:
+ mTimeElapsedSinceStackViewReady = 0.0f;
+ if (feed != null && feedUnchanged == false) {
+ feed.performClustering();
+ performLayout = false;
+ }
+ disableLocationFiltering();
+ layoutInterface.mNumRows = numMaxRows - 1;
+ layoutInterface.mSpacingX = (int) (100 * Gallery.PIXEL_DENSITY);
+ layoutInterface.mSpacingY = (int) (70 * Gallery.PIXEL_DENSITY * yStretch);
+ break;
+ case STATE_FULL_SCREEN:
+ layoutInterface.mNumRows = 1;
+ layoutInterface.mSpacingX = (int) (40 * Gallery.PIXEL_DENSITY);
+ layoutInterface.mSpacingY = (int) (40 * Gallery.PIXEL_DENSITY);
+ if (mState != STATE_FULL_SCREEN) {
+ sHud.getPathBar().pushLabel(R.drawable.ic_fs_details, "", new Runnable() {
+ public void run() {
+ if (sHud.getAlpha() == 1.0f) {
+ sHud.swapFullscreenLabel();
+ }
+ sHud.setAlpha(1.0f);
+ }
+ });
+ }
+ break;
+ case STATE_MEDIA_SETS:
+ mTimeElapsedSinceStackViewReady = 0.0f;
+ if (feed != null && feedUnchanged == false) {
+ feed.restorePreviousClusteringState();
+ feed.expandMediaSet(Shared.INVALID);
+ performLayout = false;
+ }
+ disableLocationFiltering();
+ mInputProcessor.clearSelection();
+ layoutInterface.mNumRows = numMaxRows - 1;
+ layoutInterface.mSpacingX = (int) (100 * Gallery.PIXEL_DENSITY);
+ layoutInterface.mSpacingY = (int) (70 * Gallery.PIXEL_DENSITY * yStretch);
+ if (mInAlbum) {
+ if (mState == STATE_FULL_SCREEN) {
+ sHud.getPathBar().popLabel();
+ }
+ sHud.getPathBar().popLabel();
+ mInAlbum = false;
+ }
+ break;
+ }
+ mState = state;
+ sHud.onGridStateChanged();
+ if (performLayout && mFeedAboutToChange == false) {
+ onLayout(Shared.INVALID, Shared.INVALID, oldLayout);
+ }
+ if (state != STATE_FULL_SCREEN) {
+ mCamera.moveYTo(0);
+ mCamera.moveZTo(0);
+ }
+ }
- public IndexRange getVisibleRange() {
- return sVisibleRange;
- }
+ protected void enableLocationFiltering(String label) {
+ if (mLocationFilter == false) {
+ mLocationFilter = true;
+ sHud.getPathBar().pushLabel(R.drawable.icon_location_small, label, new Runnable() {
+ public void run() {
+ if (sHud.getAlpha() == 1.0f) {
+ if (mState == STATE_FULL_SCREEN) {
+ mInputProcessor.clearSelection();
+ setState(STATE_GRID_VIEW);
+ } else {
+ disableLocationFiltering();
+ }
+ } else {
+ sHud.setAlpha(1.0f);
+ }
+ }
+ });
+ }
+ }
- public IndexRange getBufferedVisibleRange() {
- return sBufferedVisibleRange;
- }
+ protected void disableLocationFiltering() {
+ if (mLocationFilter) {
+ mLocationFilter = false;
+ mMediaFeed.removeFilter();
+ sHud.getPathBar().popLabel();
+ }
+ }
- public IndexRange getCompleteRange() {
- return sCompleteRange;
- }
+ boolean goBack() {
+ if (mFeedAboutToChange) {
+ return false;
+ }
+ int state = mState;
+ if (mInputProcessor.getCurrentSelectedSlot() == Shared.INVALID) {
+ if (mLocationFilter) {
+ disableLocationFiltering();
+ setState(STATE_TIMELINE);
+ return true;
+ }
+ }
+ switch (state) {
+ case STATE_GRID_VIEW:
+ setState(STATE_MEDIA_SETS);
+ break;
+ case STATE_TIMELINE:
+ setState(STATE_GRID_VIEW);
+ break;
+ case STATE_FULL_SCREEN:
+ setState(STATE_GRID_VIEW);
+ mInputProcessor.clearSelection();
+ break;
+ default:
+ return false;
+ }
+ return true;
+ }
- private int hitTest(Vector3f worldPos, int itemWidth, int itemHeight) {
- int retVal = Shared.INVALID;
- int firstSlotIndex = 0;
- int lastSlotIndex = 0;
- IndexRange rangeToUse = sVisibleRange;
- synchronized (rangeToUse) {
- firstSlotIndex = rangeToUse.begin;
- lastSlotIndex = rangeToUse.end;
- }
- Pool<Vector3f> pool = sTempVec;
- float itemWidthBy2 = itemWidth * 0.5f;
- float itemHeightBy2 = itemHeight * 0.5f;
- Vector3f position = pool.create();
- Vector3f deltaAnchorPosition = pool.create();
- try {
- deltaAnchorPosition.set(sDeltaAnchorPosition);
- for (int i = firstSlotIndex; i <= lastSlotIndex; ++i) {
- GridCameraManager.getSlotPositionForSlotIndex(i, mCamera, mLayoutInterface, deltaAnchorPosition, position);
- if (FloatUtils.boundsContainsPoint(position.x - itemWidthBy2, position.x + itemWidthBy2,
- position.y - itemHeightBy2, position.y + itemHeightBy2, worldPos.x, worldPos.y)) {
- retVal = i;
- break;
- }
- }
- } finally {
- pool.delete(deltaAnchorPosition);
- pool.delete(position);
- }
- return retVal;
- }
+ public void endSlideshow() {
+ mSlideshowMode = false;
+ if (mWakeLock != null) {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ mWakeLock = null;
+ }
+ sHud.setAlpha(1.0f);
+ }
- void centerCameraForSlot(int slotIndex, float baseConvergence) {
- float imageTheta = 0.0f;
- DisplayItem displayItem = getDisplayItemForSlotId(slotIndex);
- if (displayItem != null) {
- imageTheta = displayItem.getImageTheta();
- }
- mCameraManager.centerCameraForSlot(mLayoutInterface, slotIndex, baseConvergence, sDeltaAnchorPositionUncommited,
- mInputProcessor.getCurrentSelectedSlot(), mZoomValue, imageTheta, mState);
- }
+ @Override
+ public void onSensorChanged(RenderView view, SensorEvent event) {
+ mInputProcessor.onSensorChanged(view, event, mState);
+ }
- boolean constrainCameraForSlot(int slotIndex) {
- return mCameraManager.constrainCameraForSlot(mLayoutInterface, slotIndex, sDeltaAnchorPosition, mCurrentFocusItemWidth,
- mCurrentFocusItemHeight);
- }
+ public DataSource getDataSource() {
+ if (mMediaFeed != null)
+ return mMediaFeed.getDataSource();
+ return null;
+ }
- // Called on render thread before rendering.
- @Override
- public boolean update(RenderView view, float timeElapsed) {
- if (mFeedAboutToChange == false) {
- mTimeElapsedSinceTransition += timeElapsed;
- mTimeElapsedSinceGridViewReady += timeElapsed;
- if (mTimeElapsedSinceGridViewReady >= 1.0f) {
- mTimeElapsedSinceGridViewReady = 1.0f;
- }
- mTimeElapsedSinceStackViewReady += timeElapsed;
- if (mTimeElapsedSinceStackViewReady >= 1.0f) {
- mTimeElapsedSinceStackViewReady = 1.0f;
- }
- } else {
- mTimeElapsedSinceTransition = 0;
- }
- if (mMediaFeed != null && mMediaFeed.isSingleImageMode()) {
- HudLayer hud = getHud();
- hud.getPathBar().setHidden(true);
- hud.getMenuBar().setHidden(true);
- if (hud.getMode() != HudLayer.MODE_NORMAL)
- hud.setMode(HudLayer.MODE_NORMAL);
- }
- if (view.elapsedLoadingExpensiveTextures() > 150 || (mMediaFeed != null && mMediaFeed.getWaitingForMediaScanner())) {
- sHud.getPathBar().setAnimatedIcons(GridDrawables.TEXTURE_SPINNER);
- } else {
- sHud.getPathBar().setAnimatedIcons(null);
- }
+ public void setDataSource(DataSource dataSource) {
+ MediaFeed feed = mMediaFeed;
+ if (feed != null) {
+ feed.shutdown();
+ sDisplayList.clear();
+ mBackground.clear();
+ }
+ mMediaFeed = new MediaFeed(mContext, dataSource, this);
+ mMediaFeed.start();
+ }
- // In that case, we need to commit the respective Display Items when the
- // feed was updated.
- GridCamera camera = mCamera;
- camera.update(timeElapsed);
- DisplayItem anchorDisplayItem = getAnchorDisplayItem(ANCHOR_CENTER);
- if (anchorDisplayItem != null && !sHud.getTimeBar().isDragged()) {
- sHud.getTimeBar().setItem(anchorDisplayItem.mItemRef);
- }
- sDisplayList.update(timeElapsed);
- mInputProcessor.update(timeElapsed);
- mSelectedAlpha = FloatUtils.animate(mSelectedAlpha, mTargetAlpha, timeElapsed * 0.5f);
- if (mState == STATE_FULL_SCREEN) {
- sHud.autoHide(true);
- } else {
- sHud.autoHide(false);
- sHud.setAlpha(1.0f);
- }
- GridQuad[] fullscreenQuads = GridDrawables.sFullscreenGrid;
- int numFullScreenQuads = fullscreenQuads.length;
- for (int i = 0; i < numFullScreenQuads; ++i) {
- fullscreenQuads[i].update(timeElapsed);
- }
- if (mSlideshowMode && mState == STATE_FULL_SCREEN) {
- mTimeElapsedSinceView += timeElapsed;
- if (mTimeElapsedSinceView > SLIDESHOW_TRANSITION_TIME) {
- // time to go to the next slide
- mTimeElapsedSinceView = 0.0f;
- changeFocusToNextSlot(0.5f);
- mCamera.commitMoveInX();
- mCamera.commitMoveInY();
- }
- }
- if (mState == STATE_MEDIA_SETS || mState == STATE_TIMELINE) {
- mCamera.moveYTo(-0.1f);
- mCamera.commitMoveInY();
- }
- boolean dirty = mDrawManager.update(timeElapsed);
- dirty |= mSlideshowMode;
- dirty |= mFramesDirty > 0;
- ++mFrameCount;
- if (mFramesDirty > 0) {
- --mFramesDirty;
- }
- try {
- if (mMediaFeed != null && (mMediaFeed.getWaitingForMediaScanner())) {
- // We limit the drawing of the frame so that the MediaScanner thread can do its work
- Thread.sleep(200);
- }
- } catch (InterruptedException e) {
+ public IndexRange getVisibleRange() {
+ return sVisibleRange;
+ }
- }
- if (sDisplayList.getNumAnimatables() != 0 || mCamera.isAnimating()
- || (mTimeElapsedSinceTransition > 0.0f && mTimeElapsedSinceTransition < 1.0f) || mSelectedAlpha != mTargetAlpha
- // || (mAnimatedFov != mTargetFov)
- || dirty)
- return true;
- else
- return false;
- }
+ public IndexRange getBufferedVisibleRange() {
+ return sBufferedVisibleRange;
+ }
- private void computeVisibleRange() {
- if (mPerformingLayoutChange)
- return;
- if (sDeltaAnchorPosition.equals(sDeltaAnchorPositionUncommited) == false) {
- sDeltaAnchorPosition.set(sDeltaAnchorPositionUncommited);
- }
- mCameraManager.computeVisibleRange(mMediaFeed, mLayoutInterface, sDeltaAnchorPosition, sVisibleRange,
- sBufferedVisibleRange, sCompleteRange, mState);
- }
+ public IndexRange getCompleteRange() {
+ return sCompleteRange;
+ }
- private void computeVisibleItems() {
- if (mFeedAboutToChange == true || mPerformingLayoutChange == true) {
- return;
- }
- computeVisibleRange();
- int deltaBegin = sBufferedVisibleRange.begin - sPreviousDataRange.begin;
- int deltaEnd = sBufferedVisibleRange.end - sPreviousDataRange.end;
- if (deltaBegin != 0 || deltaEnd != 0) {
- // The delta has changed, we have to compute the display items again.
- // We find the intersection range, these slots have not changed at all.
- int firstVisibleSlotIndex = sBufferedVisibleRange.begin;
- int lastVisibleSlotIndex = sBufferedVisibleRange.end;
- sPreviousDataRange.begin = firstVisibleSlotIndex;
- sPreviousDataRange.end = lastVisibleSlotIndex;
+ private int hitTest(Vector3f worldPos, int itemWidth, int itemHeight) {
+ int retVal = Shared.INVALID;
+ int firstSlotIndex = 0;
+ int lastSlotIndex = 0;
+ IndexRange rangeToUse = sVisibleRange;
+ synchronized (rangeToUse) {
+ firstSlotIndex = rangeToUse.begin;
+ lastSlotIndex = rangeToUse.end;
+ }
+ Pool<Vector3f> pool = sTempVec;
+ float itemWidthBy2 = itemWidth * 0.5f;
+ float itemHeightBy2 = itemHeight * 0.5f;
+ Vector3f position = pool.create();
+ Vector3f deltaAnchorPosition = pool.create();
+ try {
+ deltaAnchorPosition.set(sDeltaAnchorPosition);
+ for (int i = firstSlotIndex; i <= lastSlotIndex; ++i) {
+ GridCameraManager.getSlotPositionForSlotIndex(i, mCamera, mLayoutInterface, deltaAnchorPosition, position);
+ if (FloatUtils.boundsContainsPoint(position.x - itemWidthBy2, position.x + itemWidthBy2,
+ position.y - itemHeightBy2, position.y + itemHeightBy2, worldPos.x, worldPos.y)) {
+ retVal = i;
+ break;
+ }
+ }
+ } finally {
+ pool.delete(deltaAnchorPosition);
+ pool.delete(position);
+ }
+ return retVal;
+ }
- Pool<Vector3f> pool = sTempVec;
- Vector3f position = pool.create();
- Vector3f deltaAnchorPosition = pool.create();
- try {
- MediaFeed feed = mMediaFeed;
- DisplayList displayList = sDisplayList;
- DisplayItem[] displayItems = sDisplayItems;
- DisplaySlot[] displaySlots = sDisplaySlots;
- int numDisplayItems = displayItems.length;
- int numDisplaySlots = displaySlots.length;
- ArrayList<MediaItem> visibleItems = sVisibleItems;
- deltaAnchorPosition.set(sDeltaAnchorPosition);
- LayoutInterface layout = mLayoutInterface;
- GridCamera camera = mCamera;
- for (int i = firstVisibleSlotIndex; i <= lastVisibleSlotIndex; ++i) {
- GridCameraManager.getSlotPositionForSlotIndex(i, camera, layout, deltaAnchorPosition, position);
- MediaSet set = feed.getSetForSlot(i);
- int indexIntoSlots = i - firstVisibleSlotIndex;
+ void centerCameraForSlot(int slotIndex, float baseConvergence) {
+ float imageTheta = 0.0f;
+ DisplayItem displayItem = getDisplayItemForSlotId(slotIndex);
+ if (displayItem != null) {
+ imageTheta = displayItem.getImageTheta();
+ }
+ mCameraManager.centerCameraForSlot(mLayoutInterface, slotIndex, baseConvergence, sDeltaAnchorPositionUncommited,
+ mInputProcessor.getCurrentSelectedSlot(), mZoomValue, imageTheta, mState);
+ }
- if (set != null && indexIntoSlots >= 0 && indexIntoSlots < numDisplaySlots) {
- ArrayList<MediaItem> items = set.getItems();
- displaySlots[indexIntoSlots].setMediaSet(set);
- ArrayList<MediaItem> bestItems = sTempList;
- if (mTimeElapsedSinceTransition < 1.0f) {
- // We always show the same top thumbnails for a stack of albums
- if (mState == STATE_MEDIA_SETS)
- ArrayUtils.computeSortedIntersection(items, visibleItems, MAX_ITEMS_PER_SLOT, bestItems, sTempHash);
- else
- ArrayUtils.computeSortedIntersection(visibleItems, items, MAX_ITEMS_PER_SLOT, bestItems, sTempHash);
- }
-
- int numItemsInSet = set.getNumItems();
- int numBestItems = bestItems.size();
- int originallyFoundItems = numBestItems;
- if (numBestItems < MAX_ITEMS_PER_SLOT) {
- int itemsRemaining = MAX_ITEMS_PER_SLOT - numBestItems;
- for (int currItemPos = 0; currItemPos < numItemsInSet; currItemPos++) {
- MediaItem item = items.get(currItemPos);
- if (mTimeElapsedSinceTransition >= 1.0f || !bestItems.contains(item)) {
- bestItems.add(item);
- if (--itemsRemaining == 0) {
- break;
- }
- }
- }
- }
- numBestItems = bestItems.size();
- int baseIndex = (i - firstVisibleSlotIndex) * MAX_ITEMS_PER_SLOT;
- for (int j = 0; j < numBestItems; ++j) {
- if (baseIndex + j >= numDisplayItems) {
- break;
- }
- if (j >= numItemsInSet) {
- displayItems[baseIndex + j] = null;
- } else {
- MediaItem item = bestItems.get(j);
- if (item != null) {
- DisplayItem displayItem = displayList.get(item);
- if ((mState == STATE_FULL_SCREEN && i != mInputProcessor.getCurrentSelectedSlot())
- || (mState == STATE_GRID_VIEW && (mTimeElapsedSinceTransition > 1.0f || j >= originallyFoundItems))) {
- displayItem.set(position, j, false);
- displayItem.commit();
- } else {
- displayList.setPositionAndStackIndex(displayItem, position, j, true);
- }
- displayItems[baseIndex + j] = displayItem;
- }
- }
- }
- for (int j = numBestItems; j < MAX_ITEMS_PER_SLOT; ++j) {
- displayItems[baseIndex + j] = null;
- }
- bestItems.clear();
- }
- }
- if (mFeedChanged) {
- mFeedChanged = false;
- if (mInputProcessor != null && mState == STATE_FULL_SCREEN) {
- int currentSelectedSlot = mInputProcessor.getCurrentSelectedSlot();
- if (currentSelectedSlot > sCompleteRange.end)
- currentSelectedSlot = sCompleteRange.end;
- mInputProcessor.setCurrentSelectedSlot(currentSelectedSlot);
- }
- if (mState == STATE_GRID_VIEW) {
- MediaSet expandedSet = mMediaFeed.getExpandedMediaSet();
- if (expandedSet != null) {
- if (!sHud.getPathBar().getCurrentLabel().equals(expandedSet.mNoCountTitleString)) {
- sHud.getPathBar().changeLabel(expandedSet.mNoCountTitleString);
- }
- }
- }
- if (mRequestFocusContentUri != null) {
- // We have to find the item that has this contentUri
- if (mState == STATE_FULL_SCREEN) {
- int numSlots = sCompleteRange.end;
- for (int i = 0; i < numSlots; ++i) {
- MediaSet set = feed.getSetForSlot(i);
- ArrayList<MediaItem> items = set.getItems();
- int numItems = items.size();
- for (int j = 0; j < numItems; ++j) {
- if (items.get(j).mContentUri.equals(mRequestFocusContentUri)) {
- mInputProcessor.setCurrentSelectedSlot(i);
- break;
- }
- }
- }
- }
- mRequestFocusContentUri = null;
- }
- }
- } finally {
- pool.delete(position);
- pool.delete(deltaAnchorPosition);
- }
- // We keep upto 400 thumbnails in memory.
- int numThumbnailsToKeepInMemory = (mState == STATE_MEDIA_SETS || mState == STATE_TIMELINE) ? 100 : 400;
- int startMemoryRange = (sBufferedVisibleRange.begin / numThumbnailsToKeepInMemory) * numThumbnailsToKeepInMemory;
- if (mStartMemoryRange != startMemoryRange) {
- mStartMemoryRange = startMemoryRange;
- clearUnusedThumbnails();
- }
- }
- }
+ boolean constrainCameraForSlot(int slotIndex) {
+ return mCameraManager.constrainCameraForSlot(mLayoutInterface, slotIndex, sDeltaAnchorPosition, mCurrentFocusItemWidth,
+ mCurrentFocusItemHeight);
+ }
+
+ // Called on render thread before rendering.
+ @Override
+ public boolean update(RenderView view, float timeElapsed) {
+ if (mFeedAboutToChange == false) {
+ mTimeElapsedSinceTransition += timeElapsed;
+ mTimeElapsedSinceGridViewReady += timeElapsed;
+ if (mTimeElapsedSinceGridViewReady >= 1.0f) {
+ mTimeElapsedSinceGridViewReady = 1.0f;
+ }
+ mTimeElapsedSinceStackViewReady += timeElapsed;
+ if (mTimeElapsedSinceStackViewReady >= 1.0f) {
+ mTimeElapsedSinceStackViewReady = 1.0f;
+ }
+ } else {
+ mTimeElapsedSinceTransition = 0;
+ }
+ if (mMediaFeed != null && mMediaFeed.isSingleImageMode()) {
+ HudLayer hud = getHud();
+ hud.getPathBar().setHidden(true);
+ hud.getMenuBar().setHidden(true);
+ if (hud.getMode() != HudLayer.MODE_NORMAL)
+ hud.setMode(HudLayer.MODE_NORMAL);
+ }
+ if (view.elapsedLoadingExpensiveTextures() > 150 || (mMediaFeed != null && mMediaFeed.getWaitingForMediaScanner())) {
+ sHud.getPathBar().setAnimatedIcons(GridDrawables.TEXTURE_SPINNER);
+ } else {
+ sHud.getPathBar().setAnimatedIcons(null);
+ }
+
+ // In that case, we need to commit the respective Display Items when the
+ // feed was updated.
+ GridCamera camera = mCamera;
+ camera.update(timeElapsed);
+ DisplayItem anchorDisplayItem = getAnchorDisplayItem(ANCHOR_CENTER);
+ if (anchorDisplayItem != null && !sHud.getTimeBar().isDragged()) {
+ sHud.getTimeBar().setItem(anchorDisplayItem.mItemRef);
+ }
+ sDisplayList.update(timeElapsed);
+ mInputProcessor.update(timeElapsed);
+ mSelectedAlpha = FloatUtils.animate(mSelectedAlpha, mTargetAlpha, timeElapsed * 0.5f);
+ if (mState == STATE_FULL_SCREEN) {
+ sHud.autoHide(true);
+ } else {
+ sHud.autoHide(false);
+ sHud.setAlpha(1.0f);
+ }
+ GridQuad[] fullscreenQuads = GridDrawables.sFullscreenGrid;
+ int numFullScreenQuads = fullscreenQuads.length;
+ for (int i = 0; i < numFullScreenQuads; ++i) {
+ fullscreenQuads[i].update(timeElapsed);
+ }
+ if (mSlideshowMode && mState == STATE_FULL_SCREEN) {
+ mTimeElapsedSinceView += timeElapsed;
+ if (mTimeElapsedSinceView > SLIDESHOW_TRANSITION_TIME) {
+ // time to go to the next slide
+ mTimeElapsedSinceView = 0.0f;
+ changeFocusToNextSlot(0.5f);
+ mCamera.commitMoveInX();
+ mCamera.commitMoveInY();
+ }
+ }
+ if (mState == STATE_MEDIA_SETS || mState == STATE_TIMELINE) {
+ mCamera.moveYTo(-0.1f);
+ mCamera.commitMoveInY();
+ }
+ boolean dirty = mDrawManager.update(timeElapsed);
+ dirty |= mSlideshowMode;
+ dirty |= mFramesDirty > 0;
+ ++mFrameCount;
+ if (mFramesDirty > 0) {
+ --mFramesDirty;
+ }
+ try {
+ if (mMediaFeed != null && (mMediaFeed.getWaitingForMediaScanner())) {
+ // We limit the drawing of the frame so that the MediaScanner
+ // thread can do its work
+ Thread.sleep(200);
+ }
+ } catch (InterruptedException e) {
+
+ }
+ if (sDisplayList.getNumAnimatables() != 0 || mCamera.isAnimating()
+ || (mTimeElapsedSinceTransition > 0.0f && mTimeElapsedSinceTransition < 1.0f) || mSelectedAlpha != mTargetAlpha
+ // || (mAnimatedFov != mTargetFov)
+ || dirty)
+ return true;
+ else
+ return false;
+ }
+
+ private void computeVisibleRange() {
+ if (mPerformingLayoutChange)
+ return;
+ if (sDeltaAnchorPosition.equals(sDeltaAnchorPositionUncommited) == false) {
+ sDeltaAnchorPosition.set(sDeltaAnchorPositionUncommited);
+ }
+ mCameraManager.computeVisibleRange(mMediaFeed, mLayoutInterface, sDeltaAnchorPosition, sVisibleRange,
+ sBufferedVisibleRange, sCompleteRange, mState);
+ }
+
+ private void computeVisibleItems() {
+ if (mFeedAboutToChange == true || mPerformingLayoutChange == true) {
+ return;
+ }
+ computeVisibleRange();
+ int deltaBegin = sBufferedVisibleRange.begin - sPreviousDataRange.begin;
+ int deltaEnd = sBufferedVisibleRange.end - sPreviousDataRange.end;
+ if (deltaBegin != 0 || deltaEnd != 0) {
+ // The delta has changed, we have to compute the display items
+ // again.
+ // We find the intersection range, these slots have not changed at
+ // all.
+ int firstVisibleSlotIndex = sBufferedVisibleRange.begin;
+ int lastVisibleSlotIndex = sBufferedVisibleRange.end;
+ sPreviousDataRange.begin = firstVisibleSlotIndex;
+ sPreviousDataRange.end = lastVisibleSlotIndex;
+
+ Pool<Vector3f> pool = sTempVec;
+ Vector3f position = pool.create();
+ Vector3f deltaAnchorPosition = pool.create();
+ try {
+ MediaFeed feed = mMediaFeed;
+ DisplayList displayList = sDisplayList;
+ DisplayItem[] displayItems = sDisplayItems;
+ DisplaySlot[] displaySlots = sDisplaySlots;
+ int numDisplayItems = displayItems.length;
+ int numDisplaySlots = displaySlots.length;
+ ArrayList<MediaItem> visibleItems = sVisibleItems;
+ deltaAnchorPosition.set(sDeltaAnchorPosition);
+ LayoutInterface layout = mLayoutInterface;
+ GridCamera camera = mCamera;
+ for (int i = firstVisibleSlotIndex; i <= lastVisibleSlotIndex; ++i) {
+ GridCameraManager.getSlotPositionForSlotIndex(i, camera, layout, deltaAnchorPosition, position);
+ MediaSet set = feed.getSetForSlot(i);
+ int indexIntoSlots = i - firstVisibleSlotIndex;
+
+ if (set != null && indexIntoSlots >= 0 && indexIntoSlots < numDisplaySlots) {
+ ArrayList<MediaItem> items = set.getItems();
+ displaySlots[indexIntoSlots].setMediaSet(set);
+ ArrayList<MediaItem> bestItems = sTempList;
+ if (mTimeElapsedSinceTransition < 1.0f) {
+ // We always show the same top thumbnails for a
+ // stack of albums
+ if (mState == STATE_MEDIA_SETS)
+ ArrayUtils.computeSortedIntersection(items, visibleItems, MAX_ITEMS_PER_SLOT, bestItems, sTempHash);
+ else
+ ArrayUtils.computeSortedIntersection(visibleItems, items, MAX_ITEMS_PER_SLOT, bestItems, sTempHash);
+ }
+
+ int numItemsInSet = set.getNumItems();
+ int numBestItems = bestItems.size();
+ int originallyFoundItems = numBestItems;
+ if (numBestItems < MAX_ITEMS_PER_SLOT) {
+ int itemsRemaining = MAX_ITEMS_PER_SLOT - numBestItems;
+ for (int currItemPos = 0; currItemPos < numItemsInSet; currItemPos++) {
+ MediaItem item = items.get(currItemPos);
+ if (mTimeElapsedSinceTransition >= 1.0f || !bestItems.contains(item)) {
+ bestItems.add(item);
+ if (--itemsRemaining == 0) {
+ break;
+ }
+ }
+ }
+ }
+ numBestItems = bestItems.size();
+ int baseIndex = (i - firstVisibleSlotIndex) * MAX_ITEMS_PER_SLOT;
+ for (int j = 0; j < numBestItems; ++j) {
+ if (baseIndex + j >= numDisplayItems) {
+ break;
+ }
+ if (j >= numItemsInSet) {
+ displayItems[baseIndex + j] = null;
+ } else {
+ MediaItem item = bestItems.get(j);
+ if (item != null) {
+ DisplayItem displayItem = displayList.get(item);
+ if ((mState == STATE_FULL_SCREEN && i != mInputProcessor.getCurrentSelectedSlot())
+ || (mState == STATE_GRID_VIEW && (mTimeElapsedSinceTransition > 1.0f || j >= originallyFoundItems))) {
+ displayItem.set(position, j, false);
+ displayItem.commit();
+ } else {
+ displayList.setPositionAndStackIndex(displayItem, position, j, true);
+ }
+ displayItems[baseIndex + j] = displayItem;
+ }
+ }
+ }
+ for (int j = numBestItems; j < MAX_ITEMS_PER_SLOT; ++j) {
+ displayItems[baseIndex + j] = null;
+ }
+ bestItems.clear();
+ }
+ }
+ if (mFeedChanged) {
+ mFeedChanged = false;
+ if (mInputProcessor != null && mState == STATE_FULL_SCREEN && mRequestFocusContentUri == null) {
+ int currentSelectedSlot = mInputProcessor.getCurrentSelectedSlot();
+ if (currentSelectedSlot > sCompleteRange.end)
+ currentSelectedSlot = sCompleteRange.end;
+ mInputProcessor.setCurrentSelectedSlot(currentSelectedSlot);
+ }
+ if (mState == STATE_GRID_VIEW) {
+ MediaSet expandedSet = mMediaFeed.getExpandedMediaSet();
+ if (expandedSet != null) {
+ if (!sHud.getPathBar().getCurrentLabel().equals(expandedSet.mNoCountTitleString)) {
+ sHud.getPathBar().changeLabel(expandedSet.mNoCountTitleString);
+ }
+ }
+ }
+ if (mRequestFocusContentUri != null) {
+ // We have to find the item that has this contentUri
+ if (mState == STATE_FULL_SCREEN) {
+ int numSlots = sCompleteRange.end + 1;
+ for (int i = 0; i < numSlots; ++i) {
+ MediaSet set = feed.getSetForSlot(i);
+ ArrayList<MediaItem> items = set.getItems();
+ int numItems = items.size();
+ for (int j = 0; j < numItems; ++j) {
+ String itemUri = items.get(j).mContentUri;
+ if (itemUri != null && mRequestFocusContentUri != null) {
+ if (itemUri.equals(mRequestFocusContentUri)) {
+ mInputProcessor.setCurrentSelectedSlot(i);
+ mRequestFocusContentUri = null;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ } finally {
+ pool.delete(position);
+ pool.delete(deltaAnchorPosition);
+ }
+ // We keep upto 400 thumbnails in memory.
+ int numThumbnailsToKeepInMemory = (mState == STATE_MEDIA_SETS || mState == STATE_TIMELINE) ? 100 : 400;
+ int startMemoryRange = (sBufferedVisibleRange.begin / numThumbnailsToKeepInMemory) * numThumbnailsToKeepInMemory;
+ if (mStartMemoryRange != startMemoryRange) {
+ mStartMemoryRange = startMemoryRange;
+ clearUnusedThumbnails();
+ }
+ }
+ }
+
+ @Override
+ public void handleLowMemory() {
+ clearUnusedThumbnails();
+ GridDrawables.sStringTextureTable.clear();
+ mBackground.clearCache();
+ }
+
+ // This method can be potentially expensive
+ public void clearUnusedThumbnails() {
+ sDisplayList.clearExcept(sDisplayItems);
+ }
+
+ @Override
+ public void onSurfaceCreated(RenderView view, GL11 gl) {
+ sDisplayList.clear();
+ sHud.clear();
+ sHud.reset();
+ GridDrawables.sStringTextureTable.clear();
+ mDrawables.onSurfaceCreated(view, gl);
+ mBackground.clear();
+ }
+
+ @Override
+ public void onSurfaceChanged(RenderView view, int width, int height) {
+ mCamera.viewportChanged(width, height, mCamera.mItemWidth, mCamera.mItemHeight);
+ view.setFov(mCamera.mFov);
+ setState(mState);
+ }
- @Override
- public void handleLowMemory() {
- clearUnusedThumbnails();
- GridDrawables.sStringTextureTable.clear();
- mBackground.clearCache();
- }
+ // Renders the node in a given pass.
+ public void renderOpaque(RenderView view, GL11 gl) {
+ GridCamera camera = mCamera;
+ int selectedSlotIndex = mInputProcessor.getCurrentSelectedSlot();
+ computeVisibleItems();
- // This method can be potentially expensive
- public void clearUnusedThumbnails() {
- sDisplayList.clearExcept(sDisplayItems);
- }
+ gl.glMatrixMode(GL11.GL_MODELVIEW);
+ gl.glLoadIdentity();
+ GLU.gluLookAt(gl, -camera.mEyeX, -camera.mEyeY, -camera.mEyeZ, -camera.mLookAtX, -camera.mLookAtY, -camera.mLookAtZ,
+ camera.mUpX, camera.mUpY, camera.mUpZ);
+ view.setAlpha(1.0f);
+ if (mSelectedAlpha != 1.0f) {
+ gl.glEnable(GL11.GL_BLEND);
+ gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
+ view.setAlpha(mSelectedAlpha);
+ }
+ if (selectedSlotIndex != Shared.INVALID) {
+ mTargetAlpha = 0.0f;
+ } else {
+ mTargetAlpha = 1.0f;
+ }
+ mDrawManager.prepareDraw(sBufferedVisibleRange, sVisibleRange, selectedSlotIndex, mInputProcessor.getCurrentFocusSlot(),
+ mInputProcessor.isFocusItemPressed());
+ if (mSelectedAlpha != 0.0f) {
+ mDrawManager.drawThumbnails(view, gl, mState);
+ }
+ if (mSelectedAlpha != 1.0f) {
+ gl.glDisable(GL11.GL_BLEND);
+ }
+ // We draw the selected slotIndex.
+ if (selectedSlotIndex != Shared.INVALID) {
+ mDrawManager.drawFocusItems(view, gl, mZoomValue, mSlideshowMode, mTimeElapsedSinceView);
+ mCurrentFocusItemWidth = mDrawManager.getFocusQuadWidth();
+ mCurrentFocusItemHeight = mDrawManager.getFocusQuadHeight();
+ }
+ view.setAlpha(mSelectedAlpha);
+ }
- @Override
- public void onSurfaceCreated(RenderView view, GL11 gl) {
- sDisplayList.clear();
- sHud.clear();
- sHud.reset();
- GridDrawables.sStringTextureTable.clear();
- mDrawables.onSurfaceCreated(view, gl);
- mBackground.clear();
- }
+ public void renderBlended(RenderView view, GL11 gl) {
+ // We draw the placeholder for all visible slots.
+ if (sHud != null && mDrawManager != null) {
+ mDrawManager.drawBlendedComponents(view, gl, mSelectedAlpha, mState, sHud.getMode(), mTimeElapsedSinceStackViewReady,
+ mTimeElapsedSinceGridViewReady, sBucketList, mMediaFeed.getWaitingForMediaScanner() || mFeedAboutToChange
+ || mMediaFeed.isLoading());
+ }
+ }
- @Override
- public void onSurfaceChanged(RenderView view, int width, int height) {
- mCamera.viewportChanged(width, height, mCamera.mItemWidth, mCamera.mItemHeight);
- view.setFov(mCamera.mFov);
- setState(mState);
- }
+ public synchronized void onLayout(int newAnchorSlotIndex, int currentAnchorSlotIndex, LayoutInterface oldLayout) {
+ if (mPerformingLayoutChange || !sDeltaAnchorPosition.equals(sDeltaAnchorPositionUncommited)) {
+ return;
+ }
- // Renders the node in a given pass.
- public void renderOpaque(RenderView view, GL11 gl) {
- GridCamera camera = mCamera;
- int selectedSlotIndex = mInputProcessor.getCurrentSelectedSlot();
- computeVisibleItems();
-
- gl.glMatrixMode(GL11.GL_MODELVIEW);
- gl.glLoadIdentity();
- GLU.gluLookAt(gl, -camera.mEyeX, -camera.mEyeY, -camera.mEyeZ, -camera.mLookAtX, -camera.mLookAtY, -camera.mLookAtZ,
- camera.mUpX, camera.mUpY, camera.mUpZ);
- view.setAlpha(1.0f);
- if (mSelectedAlpha != 1.0f) {
- gl.glEnable(GL11.GL_BLEND);
- gl.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
- view.setAlpha(mSelectedAlpha);
- }
- if (selectedSlotIndex != Shared.INVALID) {
- mTargetAlpha = 0.0f;
- } else {
- mTargetAlpha = 1.0f;
- }
- mDrawManager.prepareDraw(sBufferedVisibleRange, sVisibleRange, selectedSlotIndex, mInputProcessor.getCurrentFocusSlot(),
- mInputProcessor.isFocusItemPressed());
- if (mSelectedAlpha != 0.0f) {
- mDrawManager.drawThumbnails(view, gl, mState);
- }
- if (mSelectedAlpha != 1.0f) {
- gl.glDisable(GL11.GL_BLEND);
- }
- // We draw the selected slotIndex.
- if (selectedSlotIndex != Shared.INVALID) {
- mDrawManager.drawFocusItems(view, gl, mZoomValue, mSlideshowMode, mTimeElapsedSinceView);
- mCurrentFocusItemWidth = mDrawManager.getFocusQuadWidth();
- mCurrentFocusItemHeight = mDrawManager.getFocusQuadHeight();
- }
- view.setAlpha(mSelectedAlpha);
- }
+ mTimeElapsedSinceTransition = 0.0f;
+ mPerformingLayoutChange = true;
+ LayoutInterface layout = mLayoutInterface;
+ if (oldLayout == null) {
+ oldLayout = sfullScreenLayoutInterface;
+ }
+ GridCamera camera = mCamera;
+ if (currentAnchorSlotIndex == Shared.INVALID) {
+ currentAnchorSlotIndex = getAnchorSlotIndex(ANCHOR_CENTER);
+ if (mCurrentExpandedSlot != Shared.INVALID) {
+ currentAnchorSlotIndex = mCurrentExpandedSlot;
+ }
+ int selectedSlotIndex = mInputProcessor.getCurrentSelectedSlot();
+ if (selectedSlotIndex != Shared.INVALID) {
+ currentAnchorSlotIndex = selectedSlotIndex;
+ }
+ }
+ if (newAnchorSlotIndex == Shared.INVALID) {
+ newAnchorSlotIndex = currentAnchorSlotIndex;
+ }
+ int itemHeight = camera.mItemHeight;
+ int itemWidth = camera.mItemWidth;
+ Pool<Vector3f> pool = sTempVec;
+ Vector3f deltaAnchorPosition = pool.create();
+ Vector3f currentSlotPosition = pool.create();
+ try {
+ deltaAnchorPosition.set(0, 0, 0);
+ if (currentAnchorSlotIndex != Shared.INVALID && newAnchorSlotIndex != Shared.INVALID) {
+ layout.getPositionForSlotIndex(newAnchorSlotIndex, itemWidth, itemHeight, deltaAnchorPosition);
+ oldLayout.getPositionForSlotIndex(currentAnchorSlotIndex, itemWidth, itemHeight, currentSlotPosition);
+ currentSlotPosition.subtract(sDeltaAnchorPosition);
+ deltaAnchorPosition.subtract(currentSlotPosition);
+ deltaAnchorPosition.y = 0;
+ deltaAnchorPosition.z = 0;
+ }
+ sDeltaAnchorPositionUncommited.set(deltaAnchorPosition);
+ } finally {
+ pool.delete(deltaAnchorPosition);
+ pool.delete(currentSlotPosition);
+ }
+ centerCameraForSlot(newAnchorSlotIndex, 1.0f);
+ mCurrentExpandedSlot = Shared.INVALID;
- public void renderBlended(RenderView view, GL11 gl) {
- // We draw the placeholder for all visible slots.
- if (sHud != null && mDrawManager != null) {
- mDrawManager.drawBlendedComponents(view, gl, mSelectedAlpha, mState, sHud.getMode(), mTimeElapsedSinceStackViewReady,
- mTimeElapsedSinceGridViewReady, sBucketList, mMediaFeed.getWaitingForMediaScanner() || mFeedAboutToChange
- || mMediaFeed.isLoading());
- }
- }
+ // Force recompute of visible items and their positions.
+ ((GridLayoutInterface) oldLayout).mNumRows = ((GridLayoutInterface) layout).mNumRows;
+ ((GridLayoutInterface) oldLayout).mSpacingX = ((GridLayoutInterface) layout).mSpacingX;
+ ((GridLayoutInterface) oldLayout).mSpacingY = ((GridLayoutInterface) layout).mSpacingY;
+ forceRecomputeVisibleRange();
+ mPerformingLayoutChange = false;
+ }
- public synchronized void onLayout(int newAnchorSlotIndex, int currentAnchorSlotIndex, LayoutInterface oldLayout) {
- if (mPerformingLayoutChange || !sDeltaAnchorPosition.equals(sDeltaAnchorPositionUncommited)) {
- return;
- }
+ private void forceRecomputeVisibleRange() {
+ sPreviousDataRange.begin = Shared.INVALID;
+ sPreviousDataRange.end = Shared.INVALID;
+ if (mView != null) {
+ mView.requestRender();
+ }
+ }
- mTimeElapsedSinceTransition = 0.0f;
- mPerformingLayoutChange = true;
- LayoutInterface layout = mLayoutInterface;
- if (oldLayout == null) {
- oldLayout = sfullScreenLayoutInterface;
- }
- GridCamera camera = mCamera;
- if (currentAnchorSlotIndex == Shared.INVALID) {
- currentAnchorSlotIndex = getAnchorSlotIndex(ANCHOR_CENTER);
- if (mCurrentExpandedSlot != Shared.INVALID) {
- currentAnchorSlotIndex = mCurrentExpandedSlot;
- }
- int selectedSlotIndex = mInputProcessor.getCurrentSelectedSlot();
- if (selectedSlotIndex != Shared.INVALID) {
- currentAnchorSlotIndex = selectedSlotIndex;
- }
- }
- if (newAnchorSlotIndex == Shared.INVALID) {
- newAnchorSlotIndex = currentAnchorSlotIndex;
- }
- int itemHeight = camera.mItemHeight;
- int itemWidth = camera.mItemWidth;
- Pool<Vector3f> pool = sTempVec;
- Vector3f deltaAnchorPosition = pool.create();
- Vector3f currentSlotPosition = pool.create();
- try {
- deltaAnchorPosition.set(0, 0, 0);
- if (currentAnchorSlotIndex != Shared.INVALID && newAnchorSlotIndex != Shared.INVALID) {
- layout.getPositionForSlotIndex(newAnchorSlotIndex, itemWidth, itemHeight, deltaAnchorPosition);
- oldLayout.getPositionForSlotIndex(currentAnchorSlotIndex, itemWidth, itemHeight, currentSlotPosition);
- currentSlotPosition.subtract(sDeltaAnchorPosition);
- deltaAnchorPosition.subtract(currentSlotPosition);
- deltaAnchorPosition.y = 0;
- deltaAnchorPosition.z = 0;
- }
- sDeltaAnchorPositionUncommited.set(deltaAnchorPosition);
- } finally {
- pool.delete(deltaAnchorPosition);
- pool.delete(currentSlotPosition);
- }
- centerCameraForSlot(newAnchorSlotIndex, 1.0f);
- mCurrentExpandedSlot = Shared.INVALID;
-
- // Force recompute of visible items and their positions.
- ((GridLayoutInterface) oldLayout).mNumRows = ((GridLayoutInterface) layout).mNumRows;
- ((GridLayoutInterface) oldLayout).mSpacingX = ((GridLayoutInterface) layout).mSpacingX;
- ((GridLayoutInterface) oldLayout).mSpacingY = ((GridLayoutInterface) layout).mSpacingY;
- forceRecomputeVisibleRange();
- mPerformingLayoutChange = false;
- }
+ // called on background thread
+ public synchronized void onFeedChanged(MediaFeed feed, boolean needsLayout) {
+ if (!needsLayout) {
+ mFeedChanged = true;
+ forceRecomputeVisibleRange();
+ if (mState == STATE_GRID_VIEW || mState == STATE_FULL_SCREEN)
+ sHud.setFeed(feed, mState, needsLayout);
+ return;
+ }
- private void forceRecomputeVisibleRange() {
- sPreviousDataRange.begin = Shared.INVALID;
- sPreviousDataRange.end = Shared.INVALID;
- if (mView != null) {
- mView.requestRender();
- }
- }
+ while (mPerformingLayoutChange == true) {
+ Thread.yield();
+ }
+ if (mState == STATE_GRID_VIEW) {
+ if (sHud != null) {
+ MediaSet set = feed.getCurrentSet();
+ if (set != null && !mLocationFilter)
+ sHud.getPathBar().changeLabel(set.mNoCountTitleString);
+ }
+ }
+ DisplayItem[] displayItems = sDisplayItems;
+ int firstBufferedVisibleSlotIndex = sBufferedVisibleRange.begin;
+ int lastBufferedVisibleSlotIndex = sBufferedVisibleRange.end;
+ int currentlyVisibleSlotIndex = getAnchorSlotIndex(ANCHOR_CENTER);
+ if (mCurrentExpandedSlot != Shared.INVALID) {
+ currentlyVisibleSlotIndex = mCurrentExpandedSlot;
+ }
+ MediaItem anchorItem = null;
+ ArrayList<MediaItem> visibleItems = sVisibleItems;
+ visibleItems.clear();
+ visibleItems.ensureCapacity(lastBufferedVisibleSlotIndex - firstBufferedVisibleSlotIndex);
+ if (currentlyVisibleSlotIndex != Shared.INVALID && currentlyVisibleSlotIndex >= firstBufferedVisibleSlotIndex
+ && currentlyVisibleSlotIndex <= lastBufferedVisibleSlotIndex) {
+ int baseIndex = (currentlyVisibleSlotIndex - firstBufferedVisibleSlotIndex) * MAX_ITEMS_PER_SLOT;
+ for (int i = 0; i < MAX_ITEMS_PER_SLOT; ++i) {
+ DisplayItem displayItem = displayItems[baseIndex + i];
+ if (displayItem != null) {
+ if (anchorItem == null) {
+ anchorItem = displayItem.mItemRef;
+ }
+ visibleItems.add(displayItem.mItemRef);
+ }
+ }
+ }
+ // We want to add items from the middle.
+ int numItems = lastBufferedVisibleSlotIndex - firstBufferedVisibleSlotIndex + 1;
+ int midPoint = (lastBufferedVisibleSlotIndex - firstBufferedVisibleSlotIndex) / 2;
+ int length = displayItems.length;
+ for (int i = 0; i < numItems; ++i) {
+ int index = midPoint + Shared.midPointIterator(i);
+ int indexIntoDisplayItem = (index - firstBufferedVisibleSlotIndex) * MAX_ITEMS_PER_SLOT;
+ if (indexIntoDisplayItem >= 0 && indexIntoDisplayItem < length) {
+ for (int j = 0; j < MAX_ITEMS_PER_SLOT; ++j) {
+ DisplayItem displayItem = displayItems[indexIntoDisplayItem + j];
+ if (displayItem != null) {
+ MediaItem item = displayItem.mItemRef;
+ if (item != anchorItem) {
+ visibleItems.add(item);
+ }
+ }
+ }
+ }
+ }
+ int newSlotIndex = Shared.INVALID;
+ if (anchorItem != null) {
+ // We try to find the anchor item in the new feed.
+ int numSlots = feed.getNumSlots();
+ for (int i = 0; i < numSlots; ++i) {
+ MediaSet set = feed.getSetForSlot(i);
+ if (set != null && set.containsItem(anchorItem)) {
+ newSlotIndex = i;
+ break;
+ }
+ }
+ }
- // called on background thread
- public synchronized void onFeedChanged(MediaFeed feed, boolean needsLayout) {
- if (!needsLayout) {
- mFeedChanged = true;
- forceRecomputeVisibleRange();
- if (mState == STATE_GRID_VIEW || mState == STATE_FULL_SCREEN)
- sHud.setFeed(feed, mState, needsLayout);
- return;
- }
+ if (anchorItem != null && newSlotIndex == Shared.INVALID) {
+ int numSlots = feed.getNumSlots();
+ MediaSet parentSet = anchorItem.mParentMediaSet;
+ for (int i = 0; i < numSlots; ++i) {
+ MediaSet set = feed.getSetForSlot(i);
+ if (set != null && set.mId == parentSet.mId) {
+ newSlotIndex = i;
+ break;
+ }
+ }
+ }
- while (mPerformingLayoutChange == true) {
- Thread.yield();
- }
- if (mState == STATE_GRID_VIEW) {
- if (sHud != null) {
- MediaSet set = feed.getCurrentSet();
- if (set != null && !mLocationFilter)
- sHud.getPathBar().changeLabel(set.mNoCountTitleString);
- }
- }
- DisplayItem[] displayItems = sDisplayItems;
- int firstBufferedVisibleSlotIndex = sBufferedVisibleRange.begin;
- int lastBufferedVisibleSlotIndex = sBufferedVisibleRange.end;
- int currentlyVisibleSlotIndex = getAnchorSlotIndex(ANCHOR_CENTER);
- if (mCurrentExpandedSlot != Shared.INVALID) {
- currentlyVisibleSlotIndex = mCurrentExpandedSlot;
- }
- MediaItem anchorItem = null;
- ArrayList<MediaItem> visibleItems = sVisibleItems;
- visibleItems.clear();
- visibleItems.ensureCapacity(lastBufferedVisibleSlotIndex - firstBufferedVisibleSlotIndex);
- if (currentlyVisibleSlotIndex != Shared.INVALID && currentlyVisibleSlotIndex >= firstBufferedVisibleSlotIndex
- && currentlyVisibleSlotIndex <= lastBufferedVisibleSlotIndex) {
- int baseIndex = (currentlyVisibleSlotIndex - firstBufferedVisibleSlotIndex) * MAX_ITEMS_PER_SLOT;
- for (int i = 0; i < MAX_ITEMS_PER_SLOT; ++i) {
- DisplayItem displayItem = displayItems[baseIndex + i];
- if (displayItem != null) {
- if (anchorItem == null) {
- anchorItem = displayItem.mItemRef;
- }
- visibleItems.add(displayItem.mItemRef);
- }
- }
- }
- // We want to add items from the middle.
- int numItems = lastBufferedVisibleSlotIndex - firstBufferedVisibleSlotIndex + 1;
- int midPoint = (lastBufferedVisibleSlotIndex - firstBufferedVisibleSlotIndex) / 2;
- int length = displayItems.length;
- for (int i = 0; i < numItems; ++i) {
- int index = midPoint + Shared.midPointIterator(i);
- int indexIntoDisplayItem = (index - firstBufferedVisibleSlotIndex) * MAX_ITEMS_PER_SLOT;
- if (indexIntoDisplayItem >= 0 && indexIntoDisplayItem < length) {
- for (int j = 0; j < MAX_ITEMS_PER_SLOT; ++j) {
- DisplayItem displayItem = displayItems[indexIntoDisplayItem + j];
- if (displayItem != null) {
- MediaItem item = displayItem.mItemRef;
- if (item != anchorItem) {
- visibleItems.add(item);
- }
- }
- }
- }
- }
- int newSlotIndex = Shared.INVALID;
- if (anchorItem != null) {
- // We try to find the anchor item in the new feed.
- int numSlots = feed.getNumSlots();
- for (int i = 0; i < numSlots; ++i) {
- MediaSet set = feed.getSetForSlot(i);
- if (set != null && set.containsItem(anchorItem)) {
- newSlotIndex = i;
- break;
- }
- }
- }
+ // We must create a new display store now since the data has changed.
+ if (newSlotIndex != Shared.INVALID) {
+ if (mState == STATE_MEDIA_SETS) {
+ sDisplayList.clearExcept(displayItems);
+ }
+ onLayout(newSlotIndex, currentlyVisibleSlotIndex, null);
+ } else {
+ forceRecomputeVisibleRange();
+ }
+ mCurrentExpandedSlot = Shared.INVALID;
+ mFeedAboutToChange = false;
+ mFeedChanged = true;
+ if (feed != null) {
+ if (mState == STATE_GRID_VIEW || mState == STATE_FULL_SCREEN)
+ sHud.setFeed(feed, mState, needsLayout);
+ }
+ if (mView != null) {
+ mView.requestRender();
+ }
+ }
- if (anchorItem != null && newSlotIndex == Shared.INVALID) {
- int numSlots = feed.getNumSlots();
- MediaSet parentSet = anchorItem.mParentMediaSet;
- for (int i = 0; i < numSlots; ++i) {
- MediaSet set = feed.getSetForSlot(i);
- if (set != null && set.mId == parentSet.mId) {
- newSlotIndex = i;
- break;
- }
- }
- }
-
- // We must create a new display store now since the data has changed.
- if (newSlotIndex != Shared.INVALID) {
- if (mState == STATE_MEDIA_SETS) {
- sDisplayList.clearExcept(displayItems);
- }
- onLayout(newSlotIndex, currentlyVisibleSlotIndex, null);
- } else {
- forceRecomputeVisibleRange();
- }
- mCurrentExpandedSlot = Shared.INVALID;
- mFeedAboutToChange = false;
- mFeedChanged = true;
- if (feed != null) {
- if (mState == STATE_GRID_VIEW || mState == STATE_FULL_SCREEN)
- sHud.setFeed(feed, mState, needsLayout);
- }
- if (mView != null) {
- mView.requestRender();
- }
- }
-
- public DisplayItem getRepresentativeDisplayItem() {
- int slotIndex = Shared.INVALID;
- if (mInputProcessor != null) {
- slotIndex = mInputProcessor.getCurrentFocusSlot();
- }
- if (slotIndex == Shared.INVALID) {
- slotIndex = getAnchorSlotIndex(ANCHOR_CENTER);
- }
- int index = (slotIndex - sBufferedVisibleRange.begin) * MAX_ITEMS_PER_SLOT;
- if (index >= 0 && index < MAX_ITEMS_DRAWABLE) {
- return sDisplayItems[index];
- } else {
- return null;
- }
- }
+ public DisplayItem getRepresentativeDisplayItem() {
+ int slotIndex = Shared.INVALID;
+ if (mInputProcessor != null) {
+ slotIndex = mInputProcessor.getCurrentFocusSlot();
+ }
+ if (slotIndex == Shared.INVALID) {
+ slotIndex = getAnchorSlotIndex(ANCHOR_CENTER);
+ }
+ int index = (slotIndex - sBufferedVisibleRange.begin) * MAX_ITEMS_PER_SLOT;
+ if (index >= 0 && index < MAX_ITEMS_DRAWABLE) {
+ return sDisplayItems[index];
+ } else {
+ return null;
+ }
+ }
- public DisplayItem getAnchorDisplayItem(int type) {
- int slotIndex = getAnchorSlotIndex(type);
- return sDisplayItems[(slotIndex - sBufferedVisibleRange.begin) * MAX_ITEMS_PER_SLOT];
- }
+ public DisplayItem getAnchorDisplayItem(int type) {
+ int slotIndex = getAnchorSlotIndex(type);
+ return sDisplayItems[(slotIndex - sBufferedVisibleRange.begin) * MAX_ITEMS_PER_SLOT];
+ }
- public float getScrollPosition() {
- return (mCamera.mLookAtX * mCamera.mScale + sDeltaAnchorPosition.x); // in
- // pixels
- }
+ public float getScrollPosition() {
+ return (mCamera.mLookAtX * mCamera.mScale + sDeltaAnchorPosition.x); // in
+ // pixels
+ }
- public DisplayItem getDisplayItemForScrollPosition(float posX) {
- Pool<Vector3f> pool = sTempVecAlt;
- MediaFeed feed = mMediaFeed;
- int itemWidth = mCamera.mItemWidth;
- int itemHeight = mCamera.mItemHeight;
- GridLayoutInterface gridInterface = (GridLayoutInterface) mLayoutInterface;
- float absolutePosX = posX;
- int left = (int) ((absolutePosX / itemWidth) * gridInterface.mNumRows);
- int right = feed == null ? 0 : (int) (feed.getNumSlots());
- int retSlot = left;
- Vector3f position = pool.create();
- try {
- for (int i = left; i < right; ++i) {
- gridInterface.getPositionForSlotIndex(i, itemWidth, itemHeight, position);
- retSlot = i;
- if (position.x >= absolutePosX) {
- break;
- }
- }
- } finally {
- pool.delete(position);
- }
- if (mFeedAboutToChange) {
- return null;
- }
- right = feed == null ? 0 : feed.getNumSlots();
- if (right == 0) {
- return null;
- }
+ public DisplayItem getDisplayItemForScrollPosition(float posX) {
+ Pool<Vector3f> pool = sTempVecAlt;
+ MediaFeed feed = mMediaFeed;
+ int itemWidth = mCamera.mItemWidth;
+ int itemHeight = mCamera.mItemHeight;
+ GridLayoutInterface gridInterface = (GridLayoutInterface) mLayoutInterface;
+ float absolutePosX = posX;
+ int left = (int) ((absolutePosX / itemWidth) * gridInterface.mNumRows);
+ int right = feed == null ? 0 : (int) (feed.getNumSlots());
+ int retSlot = left;
+ Vector3f position = pool.create();
+ try {
+ for (int i = left; i < right; ++i) {
+ gridInterface.getPositionForSlotIndex(i, itemWidth, itemHeight, position);
+ retSlot = i;
+ if (position.x >= absolutePosX) {
+ break;
+ }
+ }
+ } finally {
+ pool.delete(position);
+ }
+ if (mFeedAboutToChange) {
+ return null;
+ }
+ right = feed == null ? 0 : feed.getNumSlots();
+ if (right == 0) {
+ return null;
+ }
- if (retSlot >= right)
- retSlot = right - 1;
- MediaSet set = feed.getSetForSlot(retSlot);
- if (set != null) {
- ArrayList<MediaItem> items = set.getItems();
- if (items != null && set.getNumItems() > 0) {
- return (sDisplayList.get(items.get(0)));
- }
- }
- return null;
- }
+ if (retSlot >= right)
+ retSlot = right - 1;
+ MediaSet set = feed.getSetForSlot(retSlot);
+ if (set != null) {
+ ArrayList<MediaItem> items = set.getItems();
+ if (items != null && set.getNumItems() > 0) {
+ return (sDisplayList.get(items.get(0)));
+ }
+ }
+ return null;
+ }
- // Returns the top left-most item.
- public int getAnchorSlotIndex(int anchorType) {
- int retVal = 0;
- switch (anchorType) {
- case ANCHOR_LEFT:
- retVal = sVisibleRange.begin;
- break;
- case ANCHOR_RIGHT:
- retVal = sVisibleRange.end;
- break;
- case ANCHOR_CENTER:
- retVal = (sVisibleRange.begin + sVisibleRange.end) / 2;
- break;
- }
- return retVal;
- }
+ // Returns the top left-most item.
+ public int getAnchorSlotIndex(int anchorType) {
+ int retVal = 0;
+ switch (anchorType) {
+ case ANCHOR_LEFT:
+ retVal = sVisibleRange.begin;
+ break;
+ case ANCHOR_RIGHT:
+ retVal = sVisibleRange.end;
+ break;
+ case ANCHOR_CENTER:
+ retVal = (sVisibleRange.begin + sVisibleRange.end) / 2;
+ break;
+ }
+ return retVal;
+ }
- DisplayItem getDisplayItemForSlotId(int slotId) {
- int index = slotId - sBufferedVisibleRange.begin;
- if (index >= 0 && slotId <= sBufferedVisibleRange.end) {
- return sDisplayItems[index * MAX_ITEMS_PER_SLOT];
- }
- return null;
- }
+ DisplayItem getDisplayItemForSlotId(int slotId) {
+ int index = slotId - sBufferedVisibleRange.begin;
+ if (index >= 0 && slotId <= sBufferedVisibleRange.end) {
+ return sDisplayItems[index * MAX_ITEMS_PER_SLOT];
+ }
+ return null;
+ }
- boolean changeFocusToNextSlot(float convergence) {
- int currentSelectedSlot = mInputProcessor.getCurrentSelectedSlot();
- boolean retVal = changeFocusToSlot(currentSelectedSlot + 1, convergence);
- if (mInputProcessor.getCurrentSelectedSlot() == currentSelectedSlot) {
- endSlideshow();
- sHud.setAlpha(1.0f);
- }
- return retVal;
- }
+ boolean changeFocusToNextSlot(float convergence) {
+ int currentSelectedSlot = mInputProcessor.getCurrentSelectedSlot();
+ boolean retVal = changeFocusToSlot(currentSelectedSlot + 1, convergence);
+ if (mInputProcessor.getCurrentSelectedSlot() == currentSelectedSlot) {
+ endSlideshow();
+ sHud.setAlpha(1.0f);
+ }
+ return retVal;
+ }
- boolean changeFocusToSlot(int slotId, float convergence) {
- mZoomValue = 1.0f;
- int index = slotId - sBufferedVisibleRange.begin;
- if (index >= 0 && slotId <= sBufferedVisibleRange.end) {
- DisplayItem displayItem = sDisplayItems[index * MAX_ITEMS_PER_SLOT];
- if (displayItem != null) {
- MediaItem item = displayItem.mItemRef;
- sHud.fullscreenSelectionChanged(item, slotId + 1, sCompleteRange.end + 1);
- if (slotId != Shared.INVALID && slotId <= sCompleteRange.end) {
- mInputProcessor.setCurrentFocusSlot(slotId);
- centerCameraForSlot(slotId, convergence);
- return true;
- } else {
- centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), convergence);
- return false;
- }
- }
- }
- return false;
- }
+ boolean changeFocusToSlot(int slotId, float convergence) {
+ mZoomValue = 1.0f;
+ int index = slotId - sBufferedVisibleRange.begin;
+ if (index >= 0 && slotId <= sBufferedVisibleRange.end) {
+ DisplayItem displayItem = sDisplayItems[index * MAX_ITEMS_PER_SLOT];
+ if (displayItem != null) {
+ MediaItem item = displayItem.mItemRef;
+ sHud.fullscreenSelectionChanged(item, slotId + 1, sCompleteRange.end + 1);
+ if (slotId != Shared.INVALID && slotId <= sCompleteRange.end) {
+ mInputProcessor.setCurrentFocusSlot(slotId);
+ centerCameraForSlot(slotId, convergence);
+ return true;
+ } else {
+ centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), convergence);
+ return false;
+ }
+ }
+ }
+ return false;
+ }
- boolean changeFocusToPreviousSlot(float convergence) {
- return changeFocusToSlot(mInputProcessor.getCurrentSelectedSlot() - 1, convergence);
- }
+ boolean changeFocusToPreviousSlot(float convergence) {
+ return changeFocusToSlot(mInputProcessor.getCurrentSelectedSlot() - 1, convergence);
+ }
- public ArrayList<MediaBucket> getSelectedBuckets() {
- return sBucketList.get();
- }
+ public ArrayList<MediaBucket> getSelectedBuckets() {
+ return sBucketList.get();
+ }
- public void selectAll() {
- if (mState != STATE_FULL_SCREEN) {
- int numSlots = sCompleteRange.end + 1;
- for (int i = 0; i < numSlots; ++i) {
- addSlotToSelectedItems(i, false, false);
- }
- updateCountOfSelectedItems();
- } else {
- addSlotToSelectedItems(mInputProcessor.getCurrentFocusSlot(), false, true);
- }
- }
+ public void selectAll() {
+ if (mState != STATE_FULL_SCREEN) {
+ int numSlots = sCompleteRange.end + 1;
+ for (int i = 0; i < numSlots; ++i) {
+ addSlotToSelectedItems(i, false, false);
+ }
+ updateCountOfSelectedItems();
+ } else {
+ addSlotToSelectedItems(mInputProcessor.getCurrentFocusSlot(), false, true);
+ }
+ }
- public void deselectOrCancelSelectMode() {
- if (sBucketList.size() == 0) {
- sHud.cancelSelection();
- } else {
- sBucketList.clear();
- updateCountOfSelectedItems();
- }
- }
+ public void deselectOrCancelSelectMode() {
+ if (sBucketList.size() == 0) {
+ sHud.cancelSelection();
+ } else {
+ sBucketList.clear();
+ updateCountOfSelectedItems();
+ }
+ }
- public void deselectAll() {
- sHud.cancelSelection();
- sBucketList.clear();
- updateCountOfSelectedItems();
- }
+ public void deselectAll() {
+ sHud.cancelSelection();
+ sBucketList.clear();
+ updateCountOfSelectedItems();
+ }
- public void deleteSelection() {
- // Delete the selection and exit selection mode.
- mMediaFeed.performOperation(MediaFeed.OPERATION_DELETE, getSelectedBuckets(), null);
- deselectAll();
+ public void deleteSelection() {
+ // Delete the selection and exit selection mode.
+ mMediaFeed.performOperation(MediaFeed.OPERATION_DELETE, getSelectedBuckets(), null);
+ deselectAll();
- // If the current set is now empty, return to the parent set.
- if (sCompleteRange.isEmpty()) {
- goBack(); // TODO(venkat): This does not work most of the time, can you take a look?
- }
- }
+ // If the current set is now empty, return to the parent set.
+ if (sCompleteRange.isEmpty()) {
+ goBack(); // TODO(venkat): This does not work most of the time, can
+ // you take a look?
+ }
+ }
- void addSlotToSelectedItems(int slotId, boolean removeIfAlreadyAdded, boolean updateCount) {
- if (mFeedAboutToChange == false) {
- MediaFeed feed = mMediaFeed;
- sBucketList.add(slotId, feed, removeIfAlreadyAdded);
- if (updateCount) {
- updateCountOfSelectedItems();
- if (sBucketList.size() == 0)
- deselectAll();
- }
- }
- }
+ void addSlotToSelectedItems(int slotId, boolean removeIfAlreadyAdded, boolean updateCount) {
+ if (mFeedAboutToChange == false) {
+ MediaFeed feed = mMediaFeed;
+ sBucketList.add(slotId, feed, removeIfAlreadyAdded);
+ if (updateCount) {
+ updateCountOfSelectedItems();
+ if (sBucketList.size() == 0)
+ deselectAll();
+ }
+ }
+ sHud.computeBottomMenu();
+ }
- private void updateCountOfSelectedItems() {
- sHud.updateNumItemsSelected(sBucketList.size());
- }
+ private void updateCountOfSelectedItems() {
+ sHud.updateNumItemsSelected(sBucketList.size());
+ }
- public int getMetadataSlotIndexForScreenPosition(int posX, int posY) {
- return getSlotForScreenPosition(posX, posY, mCamera.mItemWidth + (int) (100 * Gallery.PIXEL_DENSITY), mCamera.mItemHeight
- + (int) (100 * Gallery.PIXEL_DENSITY));
- }
+ public int getMetadataSlotIndexForScreenPosition(int posX, int posY) {
+ return getSlotForScreenPosition(posX, posY, mCamera.mItemWidth + (int) (100 * Gallery.PIXEL_DENSITY), mCamera.mItemHeight
+ + (int) (100 * Gallery.PIXEL_DENSITY));
+ }
- public int getSlotIndexForScreenPosition(int posX, int posY) {
- return getSlotForScreenPosition(posX, posY, mCamera.mItemWidth, mCamera.mItemHeight);
- }
+ public int getSlotIndexForScreenPosition(int posX, int posY) {
+ return getSlotForScreenPosition(posX, posY, mCamera.mItemWidth, mCamera.mItemHeight);
+ }
- private int getSlotForScreenPosition(int posX, int posY, int itemWidth, int itemHeight) {
- Pool<Vector3f> pool = sTempVec;
- int retVal = 0;
- Vector3f worldPos = pool.create();
- try {
- GridCamera camera = mCamera;
- camera.convertToCameraSpace(posX, posY, 0, worldPos);
- // slots are expressed in pixels as well
- worldPos.x *= camera.mScale;
- worldPos.y *= camera.mScale;
- // we ignore z
- retVal = hitTest(worldPos, itemWidth, itemHeight);
- } finally {
- pool.delete(worldPos);
- }
- return retVal;
- }
+ private int getSlotForScreenPosition(int posX, int posY, int itemWidth, int itemHeight) {
+ Pool<Vector3f> pool = sTempVec;
+ int retVal = 0;
+ Vector3f worldPos = pool.create();
+ try {
+ GridCamera camera = mCamera;
+ camera.convertToCameraSpace(posX, posY, 0, worldPos);
+ // slots are expressed in pixels as well
+ worldPos.x *= camera.mScale;
+ worldPos.y *= camera.mScale;
+ // we ignore z
+ retVal = hitTest(worldPos, itemWidth, itemHeight);
+ } finally {
+ pool.delete(worldPos);
+ }
+ return retVal;
+ }
- public boolean tapGesture(int slotIndex, boolean metadata) {
- MediaFeed feed = mMediaFeed;
- if (!feed.isClustered()) {
- // It is not clustering.
- if (!feed.hasExpandedMediaSet()) {
- if (feed.canExpandSet(slotIndex)) {
- mCurrentExpandedSlot = slotIndex;
- feed.expandMediaSet(slotIndex);
- setState(STATE_GRID_VIEW);
- }
- return false;
- } else {
- return true;
- }
- } else {
- // Select a cluster, and recompute a new cluster within this cluster.
- mCurrentExpandedSlot = slotIndex;
- goBack();
- if (metadata) {
- DisplaySlot slot = sDisplaySlots[slotIndex - sBufferedVisibleRange.begin];
- if (slot.hasValidLocation()) {
- MediaSet set = slot.getMediaSet();
- if (set.mReverseGeocodedLocation != null) {
- enableLocationFiltering(set.mReverseGeocodedLocation);
- }
- feed.setFilter(new LocationMediaFilter(set.mMinLatLatitude, set.mMinLonLongitude, set.mMaxLatLatitude, set.mMaxLonLongitude));
- }
- }
- return false;
- }
- }
+ public boolean tapGesture(int slotIndex, boolean metadata) {
+ MediaFeed feed = mMediaFeed;
+ if (!feed.isClustered()) {
+ // It is not clustering.
+ if (!feed.hasExpandedMediaSet()) {
+ if (feed.canExpandSet(slotIndex)) {
+ mCurrentExpandedSlot = slotIndex;
+ feed.expandMediaSet(slotIndex);
+ setState(STATE_GRID_VIEW);
+ }
+ return false;
+ } else {
+ return true;
+ }
+ } else {
+ // Select a cluster, and recompute a new cluster within this
+ // cluster.
+ mCurrentExpandedSlot = slotIndex;
+ goBack();
+ if (metadata) {
+ DisplaySlot slot = sDisplaySlots[slotIndex - sBufferedVisibleRange.begin];
+ if (slot.hasValidLocation()) {
+ MediaSet set = slot.getMediaSet();
+ if (set.mReverseGeocodedLocation != null) {
+ enableLocationFiltering(set.mReverseGeocodedLocation);
+ }
+ feed.setFilter(new LocationMediaFilter(set.mMinLatLatitude, set.mMinLonLongitude, set.mMaxLatLatitude,
+ set.mMaxLonLongitude));
+ }
+ }
+ return false;
+ }
+ }
- public void onTimeChanged(TimeBar timebar) {
- if (mFeedAboutToChange) {
- return;
- }
- // TODO lot of optimization possible here
- MediaItem item = timebar.getItem();
- MediaFeed feed = mMediaFeed;
- int numSlots = feed.getNumSlots();
- for (int i = 0; i < numSlots; ++i) {
- MediaSet set = feed.getSetForSlot(i);
- if (set == null) {
- return;
- }
- ArrayList<MediaItem> items = set.getItems();
- if (items == null || set.getNumItems() == 0) {
- return;
- }
- if (items.contains(item)) {
- centerCameraForSlot(i, 1.0f);
- break;
- }
- }
- }
+ public void onTimeChanged(TimeBar timebar) {
+ if (mFeedAboutToChange) {
+ return;
+ }
+ // TODO lot of optimization possible here
+ MediaItem item = timebar.getItem();
+ MediaFeed feed = mMediaFeed;
+ int numSlots = feed.getNumSlots();
+ for (int i = 0; i < numSlots; ++i) {
+ MediaSet set = feed.getSetForSlot(i);
+ if (set == null) {
+ return;
+ }
+ ArrayList<MediaItem> items = set.getItems();
+ if (items == null || set.getNumItems() == 0) {
+ return;
+ }
+ if (items.contains(item)) {
+ centerCameraForSlot(i, 1.0f);
+ break;
+ }
+ }
+ }
- public void onFeedAboutToChange(MediaFeed feed) {
- mFeedAboutToChange = true;
- mTimeElapsedSinceTransition = 0;
- }
+ public void onFeedAboutToChange(MediaFeed feed) {
+ mFeedAboutToChange = true;
+ mTimeElapsedSinceTransition = 0;
+ }
- public void startSlideshow() {
- endSlideshow();
- mSlideshowMode = true;
- mZoomValue = 1.0f;
- centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
- mTimeElapsedSinceView = SLIDESHOW_TRANSITION_TIME - 1.0f;
- sHud.setAlpha(0);
- PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow");
- mWakeLock.acquire();
- }
+ public void startSlideshow() {
+ endSlideshow();
+ mSlideshowMode = true;
+ mZoomValue = 1.0f;
+ centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
+ mTimeElapsedSinceView = SLIDESHOW_TRANSITION_TIME - 1.0f;
+ sHud.setAlpha(0);
+ PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow");
+ mWakeLock.acquire();
+ }
- public void enterSelectionMode() {
- mSlideshowMode = false;
- sHud.enterSelectionMode();
- int currentSlot = mInputProcessor.getCurrentSelectedSlot();
- if (currentSlot == Shared.INVALID) {
- currentSlot = mInputProcessor.getCurrentFocusSlot();
- }
- addSlotToSelectedItems(currentSlot, false, true);
- }
+ public void enterSelectionMode() {
+ mSlideshowMode = false;
+ sHud.enterSelectionMode();
+ int currentSlot = mInputProcessor.getCurrentSelectedSlot();
+ if (currentSlot == Shared.INVALID) {
+ currentSlot = mInputProcessor.getCurrentFocusSlot();
+ }
+ addSlotToSelectedItems(currentSlot, false, true);
+ }
- private float getFillScreenZoomValue() {
- return GridCameraManager.getFillScreenZoomValue(mCamera, sTempVec, mCurrentFocusItemWidth, mCurrentFocusItemHeight);
- }
+ private float getFillScreenZoomValue() {
+ return GridCameraManager.getFillScreenZoomValue(mCamera, sTempVec, mCurrentFocusItemWidth, mCurrentFocusItemHeight);
+ }
- public void zoomInToSelectedItem() {
- mSlideshowMode = false;
- float potentialZoomValue = getFillScreenZoomValue();
- if (mZoomValue < potentialZoomValue) {
- mZoomValue = potentialZoomValue;
- } else {
- mZoomValue *= 3.0f;
- }
- if (mZoomValue > 6.0f) {
- mZoomValue = 6.0f;
- }
- sHud.setAlpha(1.0f);
- centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
- }
+ public void zoomInToSelectedItem() {
+ mSlideshowMode = false;
+ float potentialZoomValue = getFillScreenZoomValue();
+ if (mZoomValue < potentialZoomValue) {
+ mZoomValue = potentialZoomValue;
+ } else {
+ mZoomValue *= 3.0f;
+ }
+ if (mZoomValue > 6.0f) {
+ mZoomValue = 6.0f;
+ }
+ sHud.setAlpha(1.0f);
+ centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
+ }
- public void zoomOutFromSelectedItem() {
- mSlideshowMode = false;
- if (mZoomValue == getFillScreenZoomValue()) {
- mZoomValue = 1.0f;
- } else {
- mZoomValue /= 3.0f;
- }
- if (mZoomValue < 1.0f) {
- mZoomValue = 1.0f;
- }
- sHud.setAlpha(1.0f);
- centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
- }
+ public void zoomOutFromSelectedItem() {
+ mSlideshowMode = false;
+ if (mZoomValue == getFillScreenZoomValue()) {
+ mZoomValue = 1.0f;
+ } else {
+ mZoomValue /= 3.0f;
+ }
+ if (mZoomValue < 1.0f) {
+ mZoomValue = 1.0f;
+ }
+ sHud.setAlpha(1.0f);
+ centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
+ }
- public void rotateSelectedItems(float f) {
- MediaBucketList bucketList = sBucketList;
- ArrayList<MediaBucket> mediaBuckets = bucketList.get();
- DisplayList displayList = sDisplayList;
- int numBuckets = mediaBuckets.size();
- for (int i = 0; i < numBuckets; ++i) {
- MediaBucket bucket = mediaBuckets.get(i);
- ArrayList<MediaItem> mediaItems = bucket.mediaItems;
- if (mediaItems != null) {
- int numMediaItems = mediaItems.size();
- for (int j = 0; j < numMediaItems; ++j) {
- MediaItem item = mediaItems.get(j);
- DisplayItem displayItem = displayList.get(item);
- displayItem.rotateImageBy(f);
- displayList.addToAnimatables(displayItem);
- }
- }
- }
- if (mState == STATE_FULL_SCREEN) {
- centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
- }
- mMediaFeed.performOperation(MediaFeed.OPERATION_ROTATE, mediaBuckets, new Float(f));
- // we recreate these displayitems from the cache
- }
+ public void rotateSelectedItems(float f) {
+ MediaBucketList bucketList = sBucketList;
+ ArrayList<MediaBucket> mediaBuckets = bucketList.get();
+ DisplayList displayList = sDisplayList;
+ int numBuckets = mediaBuckets.size();
+ for (int i = 0; i < numBuckets; ++i) {
+ MediaBucket bucket = mediaBuckets.get(i);
+ ArrayList<MediaItem> mediaItems = bucket.mediaItems;
+ if (mediaItems != null) {
+ int numMediaItems = mediaItems.size();
+ for (int j = 0; j < numMediaItems; ++j) {
+ MediaItem item = mediaItems.get(j);
+ DisplayItem displayItem = displayList.get(item);
+ displayItem.rotateImageBy(f);
+ displayList.addToAnimatables(displayItem);
+ }
+ }
+ }
+ if (mState == STATE_FULL_SCREEN) {
+ centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
+ }
+ mMediaFeed.performOperation(MediaFeed.OPERATION_ROTATE, mediaBuckets, new Float(f));
+ // we recreate these displayitems from the cache
+ }
- public void cropSelectedItem() {
+ public void cropSelectedItem() {
- }
+ }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- return mInputProcessor.onTouchEvent(event);
- }
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ return mInputProcessor.onTouchEvent(event);
+ }
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if (mInputProcessor != null)
- return mInputProcessor.onKeyDown(keyCode, event, mState);
- return false;
- }
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (mInputProcessor != null)
+ return mInputProcessor.onKeyDown(keyCode, event, mState);
+ return false;
+ }
- public boolean inSlideShowMode() {
- return mSlideshowMode;
- }
+ public boolean inSlideShowMode() {
+ return mSlideshowMode;
+ }
- public boolean noDeleteMode() {
- return mNoDeleteMode || (mMediaFeed != null && mMediaFeed.isSingleImageMode());
- }
+ public boolean noDeleteMode() {
+ return mNoDeleteMode || (mMediaFeed != null && mMediaFeed.isSingleImageMode());
+ }
- public float getZoomValue() {
- return mZoomValue;
- }
+ public float getZoomValue() {
+ return mZoomValue;
+ }
- public boolean feedAboutToChange() {
- return mFeedAboutToChange;
- }
+ public boolean feedAboutToChange() {
+ return mFeedAboutToChange;
+ }
- public boolean isInAlbumMode() {
- return mInAlbum;
- }
+ public boolean isInAlbumMode() {
+ return mInAlbum;
+ }
- public Vector3f getDeltaAnchorPosition() {
- return sDeltaAnchorPosition;
- }
+ public Vector3f getDeltaAnchorPosition() {
+ return sDeltaAnchorPosition;
+ }
- public int getExpandedSlot() {
- return mCurrentExpandedSlot;
- }
+ public int getExpandedSlot() {
+ return mCurrentExpandedSlot;
+ }
- public GridLayoutInterface getLayoutInterface() {
- return (GridLayoutInterface) mLayoutInterface;
- }
+ public GridLayoutInterface getLayoutInterface() {
+ return (GridLayoutInterface) mLayoutInterface;
+ }
- public void setZoomValue(float f) {
- mZoomValue = f;
- centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
- }
+ public void setZoomValue(float f) {
+ mZoomValue = f;
+ centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
+ }
- public void setPickIntent(boolean b) {
- mPickIntent = b;
- sHud.getPathBar().popLabel();
- sHud.getPathBar().pushLabel(R.drawable.icon_location_small, mContext.getResources().getString(R.string.pick),
- new Runnable() {
- public void run() {
- if (sHud.getAlpha() == 1.0f) {
- if (!mFeedAboutToChange) {
- setState(STATE_MEDIA_SETS);
- }
- } else {
- sHud.setAlpha(1.0f);
- }
- }
- });
- }
+ public void setPickIntent(boolean b) {
+ mPickIntent = b;
+ sHud.getPathBar().popLabel();
+ sHud.getPathBar().pushLabel(R.drawable.icon_location_small, mContext.getResources().getString(R.string.pick),
+ new Runnable() {
+ public void run() {
+ if (sHud.getAlpha() == 1.0f) {
+ if (!mFeedAboutToChange) {
+ setState(STATE_MEDIA_SETS);
+ }
+ } else {
+ sHud.setAlpha(1.0f);
+ }
+ }
+ });
+ }
- public boolean getPickIntent() {
- return mPickIntent;
- }
+ public boolean getPickIntent() {
+ return mPickIntent;
+ }
- public void setViewIntent(boolean b, final String setName) {
- mViewIntent = b;
- if (b) {
- mMediaFeed.expandMediaSet(0);
- setState(STATE_GRID_VIEW);
- // We need to make sure we haven't pushed the same label twice
- if (sHud.getPathBar().getNumLevels() == 1) {
- sHud.getPathBar().pushLabel(R.drawable.icon_folder_small, setName, new Runnable() {
- public void run() {
- if (mFeedAboutToChange) {
- return;
- }
- if (sHud.getAlpha() == 1.0f) {
- disableLocationFiltering();
- if (mInputProcessor != null)
- mInputProcessor.clearSelection();
- setState(STATE_GRID_VIEW);
- } else {
- sHud.setAlpha(1.0f);
- }
- }
- });
- }
- }
- }
+ public void setViewIntent(boolean b, final String setName) {
+ mViewIntent = b;
+ if (b) {
+ mMediaFeed.expandMediaSet(0);
+ setState(STATE_GRID_VIEW);
+ // We need to make sure we haven't pushed the same label twice
+ if (sHud.getPathBar().getNumLevels() == 1) {
+ sHud.getPathBar().pushLabel(R.drawable.icon_folder_small, setName, new Runnable() {
+ public void run() {
+ if (mFeedAboutToChange) {
+ return;
+ }
+ if (sHud.getAlpha() == 1.0f) {
+ disableLocationFiltering();
+ if (mInputProcessor != null)
+ mInputProcessor.clearSelection();
+ setState(STATE_GRID_VIEW);
+ } else {
+ sHud.setAlpha(1.0f);
+ }
+ }
+ });
+ }
+ }
+ }
- public boolean getViewIntent() {
- return mViewIntent;
- }
+ public boolean getViewIntent() {
+ return mViewIntent;
+ }
- public void setSingleImage(boolean noDeleteMode) {
- mNoDeleteMode = noDeleteMode;
- mInputProcessor.setCurrentSelectedSlot(0);
- }
+ public void setSingleImage(boolean noDeleteMode) {
+ mNoDeleteMode = noDeleteMode;
+ mInputProcessor.setCurrentSelectedSlot(0);
+ }
- public MediaFeed getFeed() {
- return mMediaFeed;
- }
+ public MediaFeed getFeed() {
+ return mMediaFeed;
+ }
- public void markDirty(int numFrames) {
- mFramesDirty = numFrames;
- }
+ public void markDirty(int numFrames) {
+ mFramesDirty = numFrames;
+ }
- public void focusItem(String contentUri) {
- mRequestFocusContentUri = contentUri;
- mMediaFeed.updateListener(false);
- }
+ public void focusItem(String contentUri) {
+ mRequestFocusContentUri = contentUri;
+ mMediaFeed.updateListener(false);
+ }
}
diff --git a/src/com/cooliris/media/HudLayer.java b/src/com/cooliris/media/HudLayer.java
index e2d1bef..d7db544 100644
--- a/src/com/cooliris/media/HudLayer.java
+++ b/src/com/cooliris/media/HudLayer.java
@@ -396,6 +396,7 @@
void setGridLayer(GridLayer layer) {
mGridLayer = layer;
+ updateViews();
}
int getMode() {
@@ -754,7 +755,6 @@
public void enterSelectionMode() {
setAlpha(1.0f);
setMode(HudLayer.MODE_SELECT);
-
// if we are in single view mode, show the bottom menu without the delete button.
if (mGridLayer.noDeleteMode()) {
mSelectionMenuBottom.setMenus(mSingleViewIntentBottomMenu);
@@ -762,6 +762,22 @@
mSelectionMenuBottom.setMenus(mNormalBottomMenu);
}
}
+
+ public void computeBottomMenu() {
+ // we need to the same for picasa albums
+ ArrayList<MediaBucket> selection = mGridLayer.getSelectedBuckets();
+ Menu[] menus = mSelectionMenuBottom.getMenus();
+ if (menus == mSingleViewIntentBottomMenu)
+ return;
+ int numBuckets = selection.size();
+ for (int i = 0; i < numBuckets; ++i) {
+ MediaBucket bucket = selection.get(i);
+ if (bucket.mediaSet.mPicasaAlbumId != Shared.INVALID) {
+ mSelectionMenuBottom.setMenus(mSingleViewIntentBottomMenu);
+ break;
+ }
+ }
+ }
public Layer getMenuBar() {
return mFullscreenMenu;
diff --git a/src/com/cooliris/media/LocalDataSource.java b/src/com/cooliris/media/LocalDataSource.java
index acd8d70..e6b89ac 100644
--- a/src/com/cooliris/media/LocalDataSource.java
+++ b/src/com/cooliris/media/LocalDataSource.java
@@ -32,6 +32,8 @@
public static final String DOWNLOAD_BUCKET_NAME = Environment.getExternalStorageDirectory().toString() + "/" + DOWNLOAD_STRING;
public static final int CAMERA_BUCKET_ID = getBucketId(CAMERA_BUCKET_NAME);
public static final int DOWNLOAD_BUCKET_ID = getBucketId(DOWNLOAD_BUCKET_NAME);
+
+ public static boolean sObserverActive = false;
private boolean mDisableImages;
private boolean mDisableVideos;
@@ -43,8 +45,7 @@
}
private Context mContext;
- private ContentObserver mImagesObserver;
- private ContentObserver mVideosObserver;
+ private ContentObserver mObserver;
public LocalDataSource(Context context) {
mContext = context;
@@ -62,35 +63,29 @@
stopListeners();
CacheService.loadMediaSets(feed, this, !mDisableImages, !mDisableVideos);
Handler handler = ((Gallery) mContext).getHandler();
- ContentObserver imagesObserver = new ContentObserver(handler) {
+ ContentObserver observer = new ContentObserver(handler) {
public void onChange(boolean selfChange) {
- if (((Gallery) mContext).isPaused()) {
- refresh(feed, CAMERA_BUCKET_ID);
- refresh(feed, DOWNLOAD_BUCKET_ID);
-
- MediaSet set = feed.getCurrentSet();
- if (set != null && set.mPicasaAlbumId == Shared.INVALID) {
- refresh(feed, set.mId);
- }
- }
+ CacheService.senseDirty(mContext, new CacheService.Observer() {
+ public void onChange(long[] ids) {
+ if (ids != null) {
+ int numLongs = ids.length;
+ for (int i = 0; i < numLongs; ++i) {
+ refreshUI(feed, ids[i]);
+ }
+ }
+ }
+ });
}
};
- ContentObserver videosObserver = new ContentObserver(handler) {
- public void onChange(boolean selfChange) {
- if (((Gallery) mContext).isPaused()) {
- refresh(feed, CAMERA_BUCKET_ID);
- }
- }
- };
-
- // Start listening. TODO: coalesce update notifications while mediascanner is active.
+
+ // Start listening.
Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
ContentResolver cr = mContext.getContentResolver();
- mImagesObserver = imagesObserver;
- mVideosObserver = videosObserver;
- cr.registerContentObserver(uriImages, false, mImagesObserver);
- cr.registerContentObserver(uriVideos, false, mVideosObserver);
+ mObserver = observer;
+ cr.registerContentObserver(uriImages, false, observer);
+ cr.registerContentObserver(uriVideos, false, observer);
+ sObserverActive = true;
}
public void shutdown() {
@@ -101,23 +96,18 @@
private void stopListeners() {
ContentResolver cr = mContext.getContentResolver();
- if (mImagesObserver != null) {
- cr.unregisterContentObserver(mImagesObserver);
+ if (mObserver != null) {
+ cr.unregisterContentObserver(mObserver);
}
- if (mVideosObserver != null) {
- cr.unregisterContentObserver(mVideosObserver);
- }
+ sObserverActive = false;
}
-
- protected void refresh(MediaFeed feed, long setIdToUse) {
+
+ protected void refreshUI(MediaFeed feed, long setIdToUse) {
if (setIdToUse == Shared.INVALID) {
return;
}
Log.i(TAG, "Refreshing local data source");
- Gallery.NEEDS_REFRESH = true;
if (feed.getMediaSet(setIdToUse) == null) {
- if (!CacheService.setHasItems(mContext.getContentResolver(), setIdToUse))
- return;
MediaSet mediaSet = feed.addMediaSet(setIdToUse, this);
if (setIdToUse == CAMERA_BUCKET_ID) {
mediaSet.mName = CAMERA_STRING;
@@ -125,8 +115,6 @@
mediaSet.mName = DOWNLOAD_STRING;
}
mediaSet.generateTitle(true);
- if (!CacheService.isPresentInCache(setIdToUse))
- CacheService.markDirty(mContext);
} else {
MediaSet mediaSet = feed.replaceMediaSet(setIdToUse, this);
if (setIdToUse == CAMERA_BUCKET_ID) {
@@ -135,7 +123,6 @@
mediaSet.mName = DOWNLOAD_STRING;
}
mediaSet.generateTitle(true);
- CacheService.markDirty(mContext, setIdToUse);
}
}
@@ -152,7 +139,7 @@
return;
}
CacheService.loadMediaItemsIntoMediaFeed(mediaFeed, set, rangeStart, rangeEnd, !mDisableImages, !mDisableVideos);
- if (set.mId == CAMERA_BUCKET_ID && set.mNumItemsLoaded > 0) {
+ if (set.mId == CAMERA_BUCKET_ID) {
mediaFeed.moveSetToFront(set);
}
}
diff --git a/src/com/cooliris/media/MediaBucketList.java b/src/com/cooliris/media/MediaBucketList.java
index 3e0f568..773fefc 100644
--- a/src/com/cooliris/media/MediaBucketList.java
+++ b/src/com/cooliris/media/MediaBucketList.java
@@ -3,6 +3,7 @@
import java.util.ArrayList;
import java.util.HashMap;
+
public final class MediaBucketList {
private static final Boolean TRUE = new Boolean(true);
private static final Boolean FALSE = new Boolean(false);
diff --git a/src/com/cooliris/media/PicasaDataSource.java b/src/com/cooliris/media/PicasaDataSource.java
index 0bd34ae..e3b9f87 100644
--- a/src/com/cooliris/media/PicasaDataSource.java
+++ b/src/com/cooliris/media/PicasaDataSource.java
@@ -30,14 +30,31 @@
private ContentProviderClient mProviderClient;
private final Context mContext;
private ContentObserver mAlbumObserver;
- private HashMap<String, Boolean> mAccountEnabled = new HashMap<String, Boolean>();
- public PicasaDataSource(Context context) {
+ public PicasaDataSource(final Context context) {
mContext = context;
}
+
+ public static final HashMap<String, Boolean> getAccountStatus(final Context context) {
+ final Account[] accounts = PicasaApi.getAccounts(context);
+ int numAccounts = accounts.length;
+ HashMap<String, Boolean> accountsEnabled = new HashMap<String, Boolean>(numAccounts);
+ for (int i = 0; i < numAccounts; ++i) {
+ Account account = accounts[i];
+ boolean isEnabled = ContentResolver.getSyncAutomatically(account, PicasaContentProvider.AUTHORITY);
+ String username = account.name;
+ if (username.contains("@gmail.") || username.contains("@googlemail.")) {
+ // Strip the domain from GMail accounts for canonicalization. TODO: is there an official way?
+ username = username.substring(0, username.indexOf('@'));
+ }
+ accountsEnabled.put(username, new Boolean(isEnabled));
+ }
+ return accountsEnabled;
+ }
public void loadMediaSets(final MediaFeed feed) {
- if (mProviderClient == null) {
+ // We do this here and not in the constructor to speed application loading time since this method is called in a background thread
+ if (mProviderClient == null) {
mProviderClient = mContext.getContentResolver().acquireContentProviderClient(PicasaContentProvider.AUTHORITY);
}
// Force permission dialog to be displayed if necessary. TODO: remove this after signed by Google.
@@ -45,8 +62,8 @@
// Ensure that users are up to date. TODO: also listen for accounts changed broadcast.
PicasaService.requestSync(mContext, PicasaService.TYPE_USERS_ALBUMS, 0);
- Handler handler = ((Gallery) mContext).getHandler();
- ContentObserver albumObserver = new ContentObserver(handler) {
+ final Handler handler = ((Gallery) mContext).getHandler();
+ final ContentObserver albumObserver = new ContentObserver(handler) {
public void onChange(boolean selfChange) {
loadMediaSetsIntoFeed(feed, true);
}
@@ -77,34 +94,23 @@
}
protected void loadMediaSetsIntoFeed(final MediaFeed feed, boolean sync) {
- Account[] accounts = PicasaApi.getAccounts(mContext);
- int numAccounts = accounts.length;
- for (int i = 0; i < numAccounts; ++i) {
- Account account = accounts[i];
- boolean isEnabled = ContentResolver.getSyncAutomatically(account, PicasaContentProvider.AUTHORITY);
- String username = account.name;
- if (username.contains("@gmail.") || username.contains("@googlemail.")) {
- // Strip the domain from GMail accounts for canonicalization. TODO: is there an official way?
- username = username.substring(0, username.indexOf('@'));
- }
- mAccountEnabled.put(username, new Boolean(isEnabled));
- }
- ContentProviderClient client = mProviderClient;
+ final HashMap<String, Boolean> accountsEnabled = getAccountStatus(mContext);
+ final ContentProviderClient client = mProviderClient;
if (client == null)
return;
try {
- EntrySchema albumSchema = AlbumEntry.SCHEMA;
- Cursor cursor = client.query(PicasaContentProvider.ALBUMS_URI, albumSchema.getProjection(), null, null,
+ final EntrySchema albumSchema = AlbumEntry.SCHEMA;
+ final Cursor cursor = client.query(PicasaContentProvider.ALBUMS_URI, albumSchema.getProjection(), null, null,
DEFAULT_BUCKET_SORT_ORDER);
- AlbumEntry album = new AlbumEntry();
+ final AlbumEntry album = new AlbumEntry();
MediaSet mediaSet;
if (cursor.moveToFirst()) {
- int numAlbums = cursor.getCount();
- ArrayList<MediaSet> picasaSets = new ArrayList<MediaSet>(numAlbums);
+ final int numAlbums = cursor.getCount();
+ final ArrayList<MediaSet> picasaSets = new ArrayList<MediaSet>(numAlbums);
do {
albumSchema.cursorToObject(cursor, album);
- Boolean accountEnabledObj = mAccountEnabled.get(album.user);
- boolean accountEnabled = (accountEnabledObj == null) ? false : accountEnabledObj.booleanValue();
+ final Boolean accountEnabledObj = accountsEnabled.get(album.user);
+ final boolean accountEnabled = (accountEnabledObj == null) ? false : accountEnabledObj.booleanValue();
if (accountEnabled) {
mediaSet = feed.getMediaSet(album.id);
if (mediaSet == null) {
@@ -128,14 +134,14 @@
}
private void addItemsToFeed(MediaFeed feed, MediaSet set, int start, int end) {
- ContentProviderClient client = mProviderClient;
+ final ContentProviderClient client = mProviderClient;
Cursor cursor = null;
try {
// Query photos in the album.
- EntrySchema photosSchema = PhotoProjection.SCHEMA;
- String whereInAlbum = "album_id = " + Long.toString(set.mId);
+ final EntrySchema photosSchema = PhotoProjection.SCHEMA;
+ final String whereInAlbum = "album_id = " + Long.toString(set.mId);
cursor = client.query(PicasaContentProvider.PHOTOS_URI, photosSchema.getProjection(), whereInAlbum, null, null);
- PhotoProjection photo = new PhotoProjection();
+ final PhotoProjection photo = new PhotoProjection();
int count = cursor.getCount();
if (count < end) {
end = count;
@@ -143,7 +149,7 @@
set.setNumExpectedItems(count);
set.generateTitle(true);
// Move to the next unread item.
- int newIndex = start + 1;
+ final int newIndex = start + 1;
if (newIndex > count || !cursor.move(newIndex)) {
end = 0;
cursor.close();
@@ -161,7 +167,7 @@
}
for (int i = 0; i < end; ++i) {
photosSchema.cursorToObject(cursor, photo);
- MediaItem item = new MediaItem();
+ final MediaItem item = new MediaItem();
item.mId = photo.id;
item.mEditUri = photo.editUri;
item.mMimeType = photo.contentType;
@@ -189,9 +195,6 @@
}
}
- public void prime(final MediaItem item) {
- }
-
public boolean performOperation(final int operation, final ArrayList<MediaBucket> mediaBuckets, final Object data) {
try {
if (operation == MediaFeed.OPERATION_DELETE) {
diff --git a/src/com/cooliris/media/TimeBar.java b/src/com/cooliris/media/TimeBar.java
index 1fc4238..1b0184c 100644
--- a/src/com/cooliris/media/TimeBar.java
+++ b/src/com/cooliris/media/TimeBar.java
@@ -18,6 +18,7 @@
import android.graphics.Rect;
import android.util.SparseArray;
import android.view.MotionEvent;
+
import com.cooliris.media.RenderView.Lists;
public final class TimeBar extends Layer implements MediaFeed.Listener {