We got out of sync, this is a fresh code drop to resync the trees.
final ContentObserver localObserver = new ContentObserver(handler) {
public void onChange(boolean selfChange) {
if (!LocalDataSource.sObserverActive) {
- CacheService.senseDirty(context, null);
+ CacheService.senseDirty(context, null);
}
}
};
cr.registerContentObserver(uriImages, false, localObserver);
cr.registerContentObserver(uriVideos, false, localObserver);
} else if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
- LocalDataSource.sThumbnailCache.close();
- LocalDataSource.sThumbnailCacheVideo.close();
- PicasaDataSource.sThumbnailCache.close();
- CacheService.sAlbumCache.close();
- CacheService.sMetaAlbumCache.close();
+ LocalDataSource.sThumbnailCache.close();
+ LocalDataSource.sThumbnailCacheVideo.close();
+ PicasaDataSource.sThumbnailCache.close();
+ CacheService.sAlbumCache.close();
+ CacheService.sMetaAlbumCache.close();
}
}
}
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.atomic.AtomicReference;
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 DiskCache sMetaAlbumCache = new DiskCache("local-meta-cache");
-
- 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;
-
- public static final String DEFAULT_IMAGE_SORT_ORDER = Images.ImageColumns.DATE_TAKEN + " ASC";
- public static final String DEFAULT_VIDEO_SORT_ORDER = Video.VideoColumns.DATE_TAKEN + " 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 };
-
- 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 };
-
- public static final String[] SENSE_PROJECTION = new String[] { Images.ImageColumns.BUCKET_ID,
- "MAX(" + Images.ImageColumns.DATE_ADDED + "), COUNT(*)" };
-
- // 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 };
-
- 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 };
-
- 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>();
-
- // 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;
-
- 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 interface Observer {
- void onChange(long[] bucketIds);
- }
-
- public static final String getCachePath(final String subFolderName) {
- return Environment.getExternalStorageDirectory() + "/Android/data/com.cooliris.media/cache/" + subFolderName;
- }
-
- 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 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 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 boolean isPresentInCache(final long setId) {
- return sAlbumCache.get(setId, 0) != null;
- }
-
- 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() {
- try {
- // We sleep for a bit here waiting for the provider database to insert the row(s).
- // This should be unnecessary, and to be fixed in future versions.
- Thread.sleep(100);
+ 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-cache");
+
+ 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;
+
+ public static final String DEFAULT_IMAGE_SORT_ORDER = Images.ImageColumns.DATE_TAKEN + " ASC";
+ public static final String DEFAULT_VIDEO_SORT_ORDER = Video.VideoColumns.DATE_TAKEN + " 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 };
+
+ 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 };
+
+ public static final String[] SENSE_PROJECTION = new String[] { Images.ImageColumns.BUCKET_ID,
+ "MAX(" + Images.ImageColumns.DATE_ADDED + "), COUNT(*)" };
+
+ // 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 };
+
+ 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 };
+
+ 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>();
+
+ // 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;
+
+ 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 interface Observer {
+ void onChange(long[] bucketIds);
+ }
+
+ public static final String getCachePath(final String subFolderName) {
+ return Environment.getExternalStorageDirectory() + "/Android/data/com.cooliris.media/cache/" + subFolderName;
+ }
+
+ 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 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 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 boolean isPresentInCache(final long setId) {
+ return sAlbumCache.get(setId, 0) != null;
+ }
+
+ 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() {
+ try {
+ // We sleep for a bit here waiting for the provider
+ // database to insert the row(s).
+ // This should be unnecessary, and to be fixed in future
+ // versions.
+ Thread.sleep(100);
} catch (InterruptedException e) {
}
- Log.i(TAG, "Computing dirty sets.");
- long ids[] = computeDirtySets(context);
- if (ids != null && observer != null) {
- observer.onChange(ids);
- }
- if (ids != null && ids.length > 0) {
- sList = null;
- Log.i(TAG, "Done computing dirty sets for num " + ids.length);
- }
- }
- });
- } else {
- QUEUE_DIRTY_SENSE = true;
- }
- }
-
- 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 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 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 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 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 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 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);
- }
-
- 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 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);
- }
-
- final int orientationDurationValue = cursor.getInt(CacheService.MEDIA_ORIENTATION_OR_DURATION_INDEX);
- if (itemMediaType == MediaItem.MEDIA_TYPE_IMAGE) {
- item.mRotation = orientationDurationValue;
- } else {
- item.mDurationInSec = orientationDurationValue;
- }
- }
-
- // 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.");
- }
-
- // Ensures that we only try retrieving EXIF date taken once.
- item.mTriedRetrievingExifDateTaken = true;
- }
- return -1L;
- }
-
- 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);
- }
-
- 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;
- }
-
- 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) {
- 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));
- }
- return bitmap;
- }
-
- 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.");
- }
-
- 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 {
- 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 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.
-
- // 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;
- // }
-
- // 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();
-
- // 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 CacheService() {
- super("CacheService");
- }
-
- @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();
- }
- }
- }
-
- 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.");
- ;
- }
- }
-
- 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 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();
-
- // Interrupt any existing thread.
- final Thread existingThread = threadRef.getAndSet(newThread);
- if (existingThread != null) {
- existingThread.interrupt();
- }
- }
-
- 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 void startNewCacheThread() {
- restartThread(CACHE_THREAD, "CacheRefresh", new Runnable() {
- public void run() {
- refresh(CacheService.this);
- }
- });
- }
-
- private void startNewCacheThreadForDirtySets() {
- restartThread(CACHE_THREAD, "CacheRefreshDirtySets", new Runnable() {
- public void run() {
- refreshDirtySets(CacheService.this);
- }
- });
- }
-
- 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;
- }
-
- 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 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 static final byte[] longArrayToByteArray(final long[] l) {
- final byte[] bArray = new byte[8 * l.length];
- final ByteBuffer bBuffer = ByteBuffer.wrap(bArray);
- final LongBuffer lBuffer = bBuffer.asLongBuffer();
- int numLongs = l.length;
- for (int i = 0; i < numLongs; ++i) {
- lBuffer.put(i, l[i]);
- }
- return bArray;
- }
-
- 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.");
- sAlbumCache.deleteAll();
- putLocaleForAlbumCache(Locale.getDefault());
-
- 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();
-
- 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();
- }
-
- 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);
-
- // Complete any queued dirty requests
- processQueuedDirty(context);
- }
-
- 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 long[] computeDirtySets(final Context context) {
- final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
- final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
- final ContentResolver cr = context.getContentResolver();
- final String where = Images.ImageColumns.BUCKET_ID + "!=0) GROUP BY (" + Images.ImageColumns.BUCKET_ID + " ";
- final Cursor cursorImages = cr.query(uriImages, SENSE_PROJECTION, where, null, null);
- final Cursor cursorVideos = cr.query(uriVideos, SENSE_PROJECTION, where, null, null);
- Cursor[] cursors = new Cursor[2];
- cursors[0] = cursorImages;
- cursors[1] = cursorVideos;
- final MergeCursor cursor = new MergeCursor(cursors);
- ArrayList<Long> retVal = new ArrayList<Long>();
- try {
- if (cursor.moveToFirst()) {
- boolean allDirty = false;
- do {
- long setId = cursor.getLong(0);
- if (allDirty) {
- addNoDupe(retVal, setId);
- } else {
- boolean contains = sAlbumCache.isDataAvailable(setId, 0);
- if (!contains) {
- // We need to refresh everything.
- markDirty(context);
- addNoDupe(retVal, setId);
- allDirty = true;
- }
- if (!allDirty) {
- long maxAdded = cursor.getLong(1);
- int count = cursor.getInt(2);
- byte[] data = sMetaAlbumCache.get(setId, 0);
- long[] dataLong = new long[2];
- if (data != null) {
- dataLong = toLongArray(data);
- }
- long oldMaxAdded = dataLong[0];
- long oldCount = dataLong[1];
- if (maxAdded > oldMaxAdded || oldCount != count) {
- markDirty(context, setId);
- addNoDupe(retVal, setId);
- dataLong[0] = maxAdded;
- dataLong[1] = count;
- sMetaAlbumCache.put(setId, longArrayToByteArray(dataLong));
- }
- }
- }
- } while (cursor.moveToNext());
- }
- } finally {
- cursor.close();
- }
- sMetaAlbumCache.flush();
- processQueuedDirty(context);
- int numIds = retVal.size();
- long retValIds[] = new long[retVal.size()];
- for (int i = 0; i < numIds; ++i) {
- retValIds[i] = retVal.get(i);
- }
- return retValIds;
- }
-
- private static final void addNoDupe(ArrayList<Long> array, long value) {
- int size = array.size();
- for (int i = 0; i < size; ++i) {
- if (array.get(i).longValue() == value)
- return;
- }
- array.add(value);
- }
-
- 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.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.addItem(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));
- }
- sAlbumCache.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);
- }
+ Log.i(TAG, "Computing dirty sets.");
+ long ids[] = computeDirtySets(context);
+ processQueuedDirty(context);
+ if (ids != null && observer != null) {
+ observer.onChange(ids);
+ }
+ if (ids != null && ids.length > 0) {
+ sList = null;
+ Log.i(TAG, "Done computing dirty sets for num " + ids.length);
+ }
+ }
+ });
+ } else {
+ QUEUE_DIRTY_SENSE = true;
+ }
+ }
+
+ 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);
+ processQueuedDirty(context);
+ }
+ });
+ } else {
+ QUEUE_DIRTY_ALL = true;
+ }
+ }
+
+ 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 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);
+ processQueuedDirty(context);
+ }
+ });
+ } else {
+ QUEUE_DIRTY_SET = 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);
+ try {
+ 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;
+ }
+ } catch (Exception e) {
+ // If the database query failed for any reason
+ ;
+ }
+ return false;
+ }
+
+ 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 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 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);
+ }
+
+ 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 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);
+ }
+ try {
+ cr.update(Uri.parse(item.mContentUri), values, null, null);
+ } catch (Exception e) {
+ // If the database operation fails for any reason.
+ ;
+ }
+ }
+
+ final int orientationDurationValue = cursor.getInt(CacheService.MEDIA_ORIENTATION_OR_DURATION_INDEX);
+ if (itemMediaType == MediaItem.MEDIA_TYPE_IMAGE) {
+ item.mRotation = orientationDurationValue;
+ } else {
+ item.mDurationInSec = orientationDurationValue;
+ }
+ }
+
+ // 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.");
+ }
+
+ // Ensures that we only try retrieving EXIF date taken once.
+ item.mTriedRetrievingExifDateTaken = true;
+ }
+ return -1L;
+ }
+
+ 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);
+ }
+
+ 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();
+ try {
+ 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;
+ }
+ } catch (Exception e) {
+ // If the database operation failed for any reason
+ ;
+ }
+ if (sList == null) {
+ sList = list;
+ }
+ return list;
+ }
+
+ 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) {
+ 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));
+ }
+ return bitmap;
+ }
+
+ 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.");
+ }
+
+ 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 {
+ 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 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.
+
+ // 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;
+ // }
+
+ // 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();
+
+ // 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 CacheService() {
+ super("CacheService");
+ }
+
+ @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();
+ }
+ }
+ }
+
+ 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.");
+ ;
+ }
+ }
+
+ 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 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();
+
+ // Interrupt any existing thread.
+ final Thread existingThread = threadRef.getAndSet(newThread);
+ if (existingThread != null) {
+ existingThread.interrupt();
+ }
+ }
+
+ 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 void startNewCacheThread() {
+ restartThread(CACHE_THREAD, "CacheRefresh", new Runnable() {
+ public void run() {
+ refresh(CacheService.this);
+ }
+ });
+ }
+
+ private void startNewCacheThreadForDirtySets() {
+ restartThread(CACHE_THREAD, "CacheRefreshDirtySets", new Runnable() {
+ public void run() {
+ refreshDirtySets(CacheService.this);
+ }
+ });
+ }
+
+ 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;
+ }
+
+ 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 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 static final byte[] longArrayToByteArray(final long[] l) {
+ final byte[] bArray = new byte[8 * l.length];
+ final ByteBuffer bBuffer = ByteBuffer.wrap(bArray);
+ final LongBuffer lBuffer = bBuffer.asLongBuffer();
+ int numLongs = l.length;
+ for (int i = 0; i < numLongs; ++i) {
+ lBuffer.put(i, l[i]);
+ }
+ return bArray;
+ }
+
+ 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.");
+ sAlbumCache.deleteAll();
+ putLocaleForAlbumCache(Locale.getDefault());
+
+ 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();
+ try {
+ 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();
+ }
+
+ 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);
+ } catch (Exception e) {
+ // If the database operation failed for any reason.
+ ;
+ }
+ sAlbumCache.delete(ALBUM_CACHE_INCOMPLETE_INDEX);
+ }
+
+ 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);
+ }
+ }
+ sAlbumCache.delete(ALBUM_CACHE_DIRTY_BUCKET_INDEX);
+ }
+
+ private static final long[] computeDirtySets(final Context context) {
+ final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
+ final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
+ final ContentResolver cr = context.getContentResolver();
+ final String where = Images.ImageColumns.BUCKET_ID + "!=0) GROUP BY (" + Images.ImageColumns.BUCKET_ID + " ";
+ ArrayList<Long> retVal = new ArrayList<Long>();
+ try {
+ final Cursor cursorImages = cr.query(uriImages, SENSE_PROJECTION, where, null, null);
+ final Cursor cursorVideos = cr.query(uriVideos, SENSE_PROJECTION, where, null, null);
+ Cursor[] cursors = new Cursor[2];
+ cursors[0] = cursorImages;
+ cursors[1] = cursorVideos;
+ final MergeCursor cursor = new MergeCursor(cursors);
+ try {
+ if (cursor.moveToFirst()) {
+ boolean allDirty = false;
+ do {
+ long setId = cursor.getLong(0);
+ if (allDirty) {
+ addNoDupe(retVal, setId);
+ } else {
+ boolean contains = sAlbumCache.isDataAvailable(setId, 0);
+ if (!contains) {
+ // We need to refresh everything.
+ markDirty(context);
+ addNoDupe(retVal, setId);
+ allDirty = true;
+ }
+ if (!allDirty) {
+ long maxAdded = cursor.getLong(1);
+ int count = cursor.getInt(2);
+ byte[] data = sMetaAlbumCache.get(setId, 0);
+ long[] dataLong = new long[2];
+ if (data != null) {
+ dataLong = toLongArray(data);
+ }
+ long oldMaxAdded = dataLong[0];
+ long oldCount = dataLong[1];
+ if (maxAdded > oldMaxAdded || oldCount != count) {
+ markDirty(context, setId);
+ addNoDupe(retVal, setId);
+ dataLong[0] = maxAdded;
+ dataLong[1] = count;
+ sMetaAlbumCache.put(setId, longArrayToByteArray(dataLong));
+ }
+ }
+ }
+ } while (cursor.moveToNext());
+ }
+ } finally {
+ cursor.close();
+ }
+ sMetaAlbumCache.flush();
+ } catch (Exception e) {
+ // If the database operation failed for any reason.
+ ;
+ }
+ int numIds = retVal.size();
+ long retValIds[] = new long[numIds];
+ for (int i = 0; i < numIds; ++i) {
+ retValIds[i] = retVal.get(i);
+ }
+ return retValIds;
+ }
+
+ private static final void addNoDupe(ArrayList<Long> array, long value) {
+ int size = array.size();
+ for (int i = 0; i < size; ++i) {
+ if (array.get(i).longValue() == value)
+ return;
+ }
+ array.add(value);
+ }
+
+ private static final void processQueuedDirty(final Context context) {
+ do {
+ 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);
+ }
+ } while (QUEUE_DIRTY_SENSE || QUEUE_DIRTY_SET || QUEUE_DIRTY_ALL);
+ }
+
+ 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);
+ }
+ try {
+ 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.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.addItem(item);
+ }
+ } while (sortCursor.moveToNext());
+ }
+ } finally {
+ if (sortCursor != null)
+ sortCursor.close();
+ }
+ } catch (Exception e) {
+ // If the database operation failed for any reason
+ ;
+ }
+ 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));
+ }
+ sAlbumCache.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);
+ }
}
protected boolean shouldQueue() {
return true;
}
-
+
@Override
public boolean isCached() {
return true;
@Override
protected Bitmap load(RenderView view) {
- // Determine a crop rectangle for the source image that is the aspect ratio of the destination.
+ // Determine a crop rectangle for the source image that is the aspect
+ // ratio of the destination.
Bitmap source = mSource;
if (source == null) {
if (mBaseTexture != null) {
source = mBaseTexture.load(view);
if (source == null) {
- return null;
+ return null;
}
} else {
return null;
int sourceHeight = source.getHeight();
int destWidth = mWidth;
int destHeight = mHeight;
- float fitX = (float)sourceWidth / (float)destWidth;
- float fitY = (float)sourceHeight / (float)destHeight;
+ float fitX = (float) sourceWidth / (float) destWidth;
+ float fitY = (float) sourceHeight / (float) destHeight;
float scale;
int cropX;
int cropY;
if (fitX < fitY) {
// Full width, partial height.
cropWidth = sourceWidth;
- cropHeight = (int)(destHeight * fitX);
+ cropHeight = (int) (destHeight * fitX);
cropX = 0;
cropY = (sourceHeight - cropHeight) / 2;
scale = 1.0f / fitX;
// Get the source pixels as 32-bit ARGB.
source.getPixels(in, 0, cropWidth, cropX, cropY, cropWidth, cropHeight);
- // Box blur is a separable kernel, so it is decomposed into a horizontal and vertical pass.
- // The filter function applies the kernel across each row and transposes the output.
- // Hence we apply it twice to provide efficient horizontal and vertical convolution.
+ // Box blur is a separable kernel, so it is decomposed into a horizontal
+ // and vertical pass.
+ // The filter function applies the kernel across each row and transposes
+ // the output.
+ // Hence we apply it twice to provide efficient horizontal and vertical
+ // convolution.
// The filter discards the alpha channel.
boxBlurFilter(in, tmp, cropWidth, cropHeight, cropWidth);
boxBlurFilter(tmp, in, cropHeight, cropWidth, START_FADE_X);
canvas.scale(scale, scale);
canvas.drawBitmap(filtered, 0f, 0f, paint);
filtered.recycle();
-
+
// Clear the texture
mBaseTexture = null;
return output;
int alpha = (y < startFadeX) ? 0xff : ((height - y - 1) * MAX_COLOR_VALUE / (height - startFadeX));
// Compute output values for the row.
int outPos = y;
- for (int x = 0; x != width; ++x) { // CR: x < width
+ for (int x = 0; x != width; ++x) { // CR: x < width
// Output the current pixel.
- out[outPos] = (alpha << 24) | (KERNEL_NORM[red] << RED_MASK_SHIFT) | (KERNEL_NORM[green] << GREEN_MASK_SHIFT) | KERNEL_NORM[blue];
+ out[outPos] = (alpha << 24) | (KERNEL_NORM[red] << RED_MASK_SHIFT) | (KERNEL_NORM[green] << GREEN_MASK_SHIFT)
+ | KERNEL_NORM[blue];
// Slide to the next pixel, adding the new rightmost pixel and
// subtracting the former leftmost.
int prevX = FloatUtils.clamp(x - RADIUS, 0, maxX);
import java.util.Arrays;
public final class ArrayUtils {
- public static final void computeSortedIntersection(ArrayList<MediaItem> firstList, final ArrayList<MediaItem> secondList, int maxSize,
- ArrayList<MediaItem> intersectionList, MediaItem[] hash) {
+ public static final void computeSortedIntersection(ArrayList<MediaItem> firstList, final ArrayList<MediaItem> secondList,
+ int maxSize, ArrayList<MediaItem> intersectionList, MediaItem[] hash) {
// Assumes that firstList is generally larger than the second list.
// Build a simple filter to speed up containment testing.
int mask = hash.length - 1;
for (int i = 0; i < firstListSize; ++i) {
MediaItem firstListItem = firstList.get(i);
if (firstListItem == null)
- continue;
+ continue;
MediaItem hashItem = (hash != null) ? hash[firstListItem.hashCode() & mask] : null;
- if (hashItem != null && ((hashItem.mId != Shared.INVALID && hashItem.mId == firstListItem.mId) || contains(secondList, firstListItem))) {
+ if (hashItem != null
+ && ((hashItem.mId != Shared.INVALID && hashItem.mId == firstListItem.mId) || contains(secondList, firstListItem))) {
intersectionList.add(firstListItem);
if (--maxSize == 0) {
break;
return false;
}
- public static void clear(Object[] array) {
- int length = array.length;
- for (int i = 0; i < length; i++) {
- array[i] = null;
- }
- }
+ public static void clear(Object[] array) {
+ int length = array.length;
+ for (int i = 0; i < length; i++) {
+ array[i] = null;
+ }
+ }
public static final boolean contains(ArrayList<MediaItem> items, MediaItem item) {
final int numItems = items.size();
mFallbackBackground = texture;
}
}
-
- // We stitch this crossfading texture, and to cover all cases of overlap we need to perform 3 draws.
+
+ // We stitch this crossfading texture, and to cover all cases of overlap
+ // we need to perform 3 draws.
int cameraPosition = (int) (mGridLayer.getScrollPosition() * PARALLAX);
int backgroundSpacing = mBackgroundBlitWidth - mBackgroundOverlap;
int anchorEdge = -cameraPosition % (backgroundSpacing);
int rightEdge = anchorEdge + backgroundSpacing;
-
+
view.draw2D(rightEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight);
view.draw2D(anchorEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight);
int leftEdge = anchorEdge - backgroundSpacing;
view.draw2D(leftEdge, 0, Z_FAR_PLANE, mBackgroundBlitWidth, mHeight);
-
+
if (bind) {
anchorTexture.unbind(view, gl);
}
-
+
gl.glBlendFunc(GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA);
gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
/**
* The state of the task, possible transitions are:
+ *
* <pre>
- * INITIAL -> CANCELED
- * EXECUTING -> COMPLETE, CANCELING, ERROR, CANCELED
- * CANCELING -> CANCELED
+ * INITIAL -> CANCELED
+ * EXECUTING -> COMPLETE, CANCELING, ERROR, CANCELED
+ * CANCELING -> CANCELED
* </pre>
+ *
* When the task stop, it must be end with one of the following states:
* COMPLETE, CANCELED, or ERROR;
*/
if (mState == STATE_ERROR) {
throw new ExecutionException(mError);
}
- if (mState == STATE_COMPLETE) return mResult;
+ if (mState == STATE_COMPLETE)
+ return mResult;
throw new IllegalStateException();
}
}
}
synchronized (this) {
- if (mState == STATE_CANCELING) mState = STATE_CANCELED;
- if (mState == STATE_EXECUTING) mState = STATE_COMPLETE;
+ if (mState == STATE_CANCELING)
+ mState = STATE_CANCELED;
+ if (mState == STATE_EXECUTING)
+ mState = STATE_COMPLETE;
notifyAll();
if (mState == STATE_CANCELED && mResult != null) {
freeCanceledResult(mResult);
/**
* Requests the task to be canceled.
- *
+ *
* @return true if the task is running and has not been canceled; false
- * otherwise
+ * otherwise
*/
public synchronized boolean requestCancel() {
return false;
}
if (mState == STATE_EXECUTING) {
- if (mCurrentTask != null) mCurrentTask.requestCancel();
+ if (mCurrentTask != null)
+ mCurrentTask.requestCancel();
mState = STATE_CANCELING;
return true;
}
return false;
}
}
-
/**
* This class provides several utilities to cancel bitmap decoding.
- *
+ *
* The function decodeFileDescriptor() is used to decode a bitmap. During
* decoding if another thread wants to cancel it, it calls the function
* cancelThreadDecoding() specifying the Thread which is in decoding.
- *
+ *
* cancelThreadDecoding() is sticky until allowThreadDecoding() is called.
- *
- * You can also cancel decoding for a set of threads using ThreadSet as
- * the parameter for cancelThreadDecoding. To put a thread into a ThreadSet,
- * use the add() method. A ThreadSet holds (weak) references to the threads,
- * so you don't need to remove Thread from it if some thread dies.
+ *
+ * You can also cancel decoding for a set of threads using ThreadSet as the
+ * parameter for cancelThreadDecoding. To put a thread into a ThreadSet, use the
+ * add() method. A ThreadSet holds (weak) references to the threads, so you
+ * don't need to remove Thread from it if some thread dies.
*/
public class BitmapManager {
private static final String TAG = "BitmapManager";
- private static enum State {CANCEL, ALLOW}
+
+ private static enum State {
+ CANCEL, ALLOW
+ }
+
private static class ThreadStatus {
public State mState = State.ALLOW;
public BitmapFactory.Options mOptions;
}
public static class ThreadSet implements Iterable<Thread> {
- private final WeakHashMap<Thread, Object> mWeakCollection =
- new WeakHashMap<Thread, Object>();
+ private final WeakHashMap<Thread, Object> mWeakCollection = new WeakHashMap<Thread, Object>();
public void add(Thread t) {
mWeakCollection.put(t, null);
}
+
public void remove(Thread t) {
mWeakCollection.remove(t);
}
+
public Iterator<Thread> iterator() {
return mWeakCollection.keySet().iterator();
}
}
- private final WeakHashMap<Thread, ThreadStatus> mThreadStatus =
- new WeakHashMap<Thread, ThreadStatus>();
+ private final WeakHashMap<Thread, ThreadStatus> mThreadStatus = new WeakHashMap<Thread, ThreadStatus>();
private static BitmapManager sManager = null;
* The following three methods are used to keep track of
* BitmapFaction.Options used for decoding and cancelling.
*/
- private synchronized void setDecodingOptions(Thread t,
- BitmapFactory.Options options) {
+ private synchronized void setDecodingOptions(Thread t, BitmapFactory.Options options) {
getOrCreateThreadStatus(t).mOptions = options;
}
}
/**
- * The following two methods are used to allow/cancel a set of threads
- * for bitmap decoding.
+ * The following two methods are used to allow/cancel a set of threads for
+ * bitmap decoding.
*/
public synchronized void allowThreadDecoding(ThreadSet threads) {
for (Thread t : threads) {
}
/**
- * The following three methods are used to keep track of which thread
- * is being disabled for bitmap decoding.
+ * The following three methods are used to keep track of which thread is
+ * being disabled for bitmap decoding.
*/
public synchronized boolean canThreadDecoding(Thread t) {
ThreadStatus status = mThreadStatus.get(t);
/**
* The real place to delegate bitmap decoding to BitmapFactory.
*/
- public Bitmap decodeFileDescriptor(FileDescriptor fd,
- BitmapFactory.Options options) {
+ public Bitmap decodeFileDescriptor(FileDescriptor fd, BitmapFactory.Options options) {
if (options.mCancel) {
return null;
}
public class BitmapTexture extends Texture {
// A simple flexible texture class that enables a Texture from a bitmap.
final Bitmap mBitmap;
+
BitmapTexture(Bitmap bitmap) {
mBitmap = bitmap;
}
-
+
@Override
protected Bitmap load(RenderView view) {
return mBitmap;
* limitations under the License.
*/
-
import java.util.concurrent.ExecutionException;
/**
* Requests this <code>Cancelable</code> to be canceled. This function will
* return <code>true</code> if and only if the task is originally running
* and now begin requested for cancel.
- *
+ *
* If subclass need to do more things to cancel the task. It can override
- * the code like this:
- * <pre>
- * @Override
- * public boolean requestCancel() {
- * if (super.requestCancel()) {
- * // do necessary work to cancel the task
- * return true;
- * }
- * return false;
- * }
+ * the code like this: <pre>
+ *
+ * @Override public boolean requestCancel() { if (super.requestCancel()) {
+ * // do necessary work to cancel the task return true; } return false; }
* </pre>
*/
public boolean requestCancel();
/**
* Gets the results of this <code>Cancelable</code> task.
- *
- * @throws ExecutionException if exception is thrown during the execution of
- * the task
+ *
+ * @throws ExecutionException
+ * if exception is thrown during the execution of the task
*/
public T get() throws InterruptedException, ExecutionException;
}
\ No newline at end of file
}
public void resetTexture() {
- // Happens when restoring the scene. Need to manage this more automatically.
+ // Happens when restoring the scene. Need to manage this more
+ // automatically.
mTextureId = 0;
mNeedsResize = true;
}
import java.util.ArrayList;
-
import android.util.Log;
public final class ConcatenatedDataSource implements DataSource {
singleBucket.add(null);
int numBuckets = mediaBuckets.size();
boolean retVal = true;
- for (int i = 0; i < numBuckets; ++i) { // CR: iterator for
+ for (int i = 0; i < numBuckets; ++i) { // CR: iterator for
MediaBucket bucket = mediaBuckets.get(i);
MediaSet set = bucket.mediaSet;
if (set != null) {
- DataSource dataSource = set.mDataSource;
- if (dataSource != null) {
- singleBucket.set(0, bucket);
- retVal &= dataSource.performOperation(operation, singleBucket, data);
- } else {
- Log.e(TAG, "MediaSet was not added to the feed");
- }
+ DataSource dataSource = set.mDataSource;
+ if (dataSource != null) {
+ singleBucket.set(0, bucket);
+ retVal &= dataSource.performOperation(operation, singleBucket, data);
+ } else {
+ Log.e(TAG, "MediaSet was not added to the feed");
+ }
}
}
return retVal;
public DiskCache getThumbnailCache() {
throw new UnsupportedOperationException("ConcatenatedDataSource should not create MediaItems");
}
-
+
public void shutdown() {
mFirst.shutdown();
mSecond.shutdown();
// lists.blendedList.add(this);
// lists.hitTestList.add(this);
// }
-//}
+// }
private static final String TAG = "CropImage";
// These are various options can be specified in the intent.
- private Bitmap.CompressFormat mOutputFormat = Bitmap.CompressFormat.JPEG; // only used with mSaveUri
+ private Bitmap.CompressFormat mOutputFormat = Bitmap.CompressFormat.JPEG; // only
+ // used
+ // with
+ // mSaveUri
private Uri mSaveUri = null;
- private int mAspectX, mAspectY; // CR: two definitions per line == sad panda.
+ private int mAspectX, mAspectY; // CR: two definitions per line == sad
+ // panda.
private boolean mDoFaceDetection = true;
private boolean mCircleCrop = false;
private final Handler mHandler = new Handler();
mImageView = (CropImageView) findViewById(R.id.image);
// CR: remove TODO's.
- // TODO: we may need to show this indicator for the main gallery application
+ // TODO: we may need to show this indicator for the main gallery
+ // application
// MenuHelper.showStorageToast(this);
Intent intent = getIntent();
if (mBitmap == null) {
// Create a MediaItem representing the URI.
- Uri target = intent.getData();
+ Uri target = intent.getData();
String targetScheme = target.getScheme();
int rotation = 0;
-
+
if (targetScheme.equals("content")) {
- mItem = LocalDataSource.createMediaItemFromUri(this, target);
+ mItem = LocalDataSource.createMediaItemFromUri(this, target);
}
try {
- if (mItem != null) {
- mBitmap = UriTexture.createFromUri(this, mItem.mContentUri, 1024, 1024, 0, null);
- rotation = (int)mItem.mRotation;
- } else {
- mBitmap = UriTexture.createFromUri(this, target.toString(), 1024, 1024, 0, null);
- if (targetScheme.equals("file")) {
- ExifInterface exif = new ExifInterface(target.getPath());
- rotation = (int)Shared.exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
- ExifInterface.ORIENTATION_NORMAL));
- }
- }
+ if (mItem != null) {
+ mBitmap = UriTexture.createFromUri(this, mItem.mContentUri, 1024, 1024, 0, null);
+ rotation = (int) mItem.mRotation;
+ } else {
+ mBitmap = UriTexture.createFromUri(this, target.toString(), 1024, 1024, 0, null);
+ if (targetScheme.equals("file")) {
+ ExifInterface exif = new ExifInterface(target.getPath());
+ rotation = (int) Shared.exifOrientationToDegrees(exif.getAttributeInt(ExifInterface.TAG_ORIENTATION,
+ ExifInterface.ORIENTATION_NORMAL));
+ }
+ }
} catch (IOException e) {
} catch (URISyntaxException e) {
}
- if (mBitmap != null && rotation != 0f) {
- mBitmap = Util.rotate(mBitmap, rotation);
- }
+ if (mBitmap != null && rotation != 0f) {
+ mBitmap = Util.rotate(mBitmap, rotation);
+ }
}
if (mBitmap == null) {
Rect r = mCrop.getCropRect();
- int width = r.width(); // CR: final == happy panda!
+ int width = r.width(); // CR: final == happy panda!
int height = r.height();
// If we are circle cropping, we want alpha channel, which is the
} else {
/*
- * Don't scale the image crop it to the size requested. Create an new image with the cropped image in the center and
- * the extra space filled.
+ * Don't scale the image crop it to the size requested. Create
+ * an new image with the cropped image in the center and the
+ * extra space filled.
*/
// Don't scale the image but instead fill it so it's the
String fileName = oldPath.getName();
fileName = fileName.substring(0, fileName.lastIndexOf("."));
- // Try file-1.jpg, file-2.jpg, ... until we find a filename which
+ // Try file-1.jpg, file-2.jpg, ... until we find a filename
+ // which
// does not exist yet.
while (true) {
x += 1;
String candidate = directory.toString() + "/" + fileName + "-" + x + ".jpg";
boolean exists = (new File(candidate)).exists();
- if (!exists) { // CR: inline the expression for exists here--it's clear enough.
+ if (!exists) { // CR: inline the expression for exists
+ // here--it's clear enough.
break;
}
}
String finalFileName = fileName + "-" + x + ".jpg";
// TODO this is going to cause the orientation to reset.
Uri newUri = ImageManager.addImage(mContentResolver, item.mCaption, item.mDateTakenInMs, item.mLatitude,
- item.mLongitude, 0, directory.toString(), finalFileName);
+ item.mLongitude, 0, directory.toString(), finalFileName);
boolean complete = false;
try {
String[] projection = new String[] { ImageColumns._ID, ImageColumns.MINI_THUMB_MAGIC };
}
}
setResult(RESULT_OK, new Intent().setAction(newUri.toString()).putExtras(extras));
- } catch (Exception e) { // CR: e.
+ } catch (Exception e) { // CR: e.
// CR: sentences!
Log.e(TAG, "Store image fail, continue anyway", e);
}
// 256 pixels wide is enough.
if (mBitmap.getWidth() > 256) {
- mScale = 256.0F / mBitmap.getWidth(); // CR: F => f (or change all f to F).
+ mScale = 256.0F / mBitmap.getWidth(); // CR: F => f (or change
+ // all f to F).
}
Matrix matrix = new Matrix();
matrix.setScale(mScale, mScale);
}
if (mNumFaces > 1) {
- // CR: no need for the variable t. just do Toast.makeText(...).show().
+ // CR: no need for the variable t. just do
+ // Toast.makeText(...).show().
Toast t = Toast.makeText(CropImage.this, R.string.multiface_crop_help, Toast.LENGTH_SHORT);
t.show();
}
}
switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN: // CR: inline case blocks.
+ case MotionEvent.ACTION_DOWN: // CR: inline case blocks.
if (cropImage.mWaitingToPick) {
recomputeFocus(event);
} else {
- for (int i = 0; i < mHighlightViews.size(); i++) { // CR: iterator for; if not, then i++ => ++i.
+ for (int i = 0; i < mHighlightViews.size(); i++) { // CR:
+ // iterator
+ // for; if
+ // not, then
+ // i++ =>
+ // ++i.
HighlightView hv = mHighlightViews.get(i);
int edge = hv.getHit(event.getX(), event.getY());
if (edge != HighlightView.GROW_NONE) {
if (hv.hasFocus()) {
cropImage.mCrop = hv;
for (int j = 0; j < mHighlightViews.size(); j++) {
- if (j == i) { // CR: if j != i do your shit; no need for continue.
+ if (j == i) { // CR: if j != i do your shit; no need
+ // for continue.
continue;
}
mHighlightViews.get(j).setHidden(true);
if ((Math.abs(zoom - getScale()) / zoom) > .1) {
float[] coordinates = new float[] { hv.mCropRect.centerX(), hv.mCropRect.centerY() };
getImageMatrix().mapPoints(coordinates);
- zoomTo(zoom, coordinates[0], coordinates[1], 300F); // CR: 300.0f.
+ zoomTo(zoom, coordinates[0], coordinates[1], 300F); // CR: 300.0f.
}
ensureVisible(hv);
private boolean mBind = false;
private boolean mFadeNecessary = false;
- public CrossFadingTexture() { }
-
+ public CrossFadingTexture() {
+ }
+
public CrossFadingTexture(Texture initialTexture) {
mMixRatio = 1.0f;
mAnimatedMixRatio = 1.0f;
}
public void setTexture(Texture texture) {
- if (mTexture == texture || texture == null || (mAnimatedMixRatio > 0.0f && mAnimatedMixRatio < 1.0f)) {
+ if (mTexture == texture || texture == null || mAnimatedMixRatio < 1.0f) {
return;
}
mFadeNecessary = false;
return false;
}
}
-
+
public boolean bind(RenderView view, GL11 gl) {
if (mBind) {
- return true; // Already bound.
+ return true; // Already bound.
}
if (mFadingTexture != null && mFadingTexture.mState == Texture.STATE_ERROR) {
mFadingTexture = null;
mBind = true;
if (mAnimatedMixRatio <= 0.0f && fadingTextureLoaded) {
view.bind(mFadingTexture);
- } else if (mAnimatedMixRatio >= 1.0f || !fadingTextureLoaded ||
- view.getAlpha() < mAnimatedMixRatio || mFadingTexture == mTexture) {
+ } else if (mAnimatedMixRatio >= 1.0f || !fadingTextureLoaded || view.getAlpha() < mAnimatedMixRatio
+ || mFadingTexture == mTexture) {
view.bind(mTexture);
} else {
mBindUsingMixed = true;
import java.util.ArrayList;
-
public interface DataSource {
// Load the sets to be displayed.
void loadMediaSets(final MediaFeed feed);
// Pass in Shared.INFINITY for the rangeEnd to load all items.
void loadItemsForSet(final MediaFeed feed, final MediaSet parentSet, int rangeStart, int rangeEnd);
-
+
// Called when the data source will no longer be used.
void shutdown();
-
+
boolean performOperation(int operation, ArrayList<MediaBucket> mediaBuckets, Object data);
DiskCache getThumbnailCache();
}
public int size() {
- return (mTail - mHead) & (mArray.length - 1); // CR: wtf?!? this definitely needs a comment.
+ return (mTail - mHead) & (mArray.length - 1); // CR: wtf?!? this
+ // definitely needs a
+ // comment.
}
public void clear() {
import java.util.Date;
import android.content.Context;
-import android.content.res.Resources;;
+import android.content.res.Resources;
+
+;
public final class DetailMode {
public static CharSequence[] populateDetailModeStrings(Context context, ArrayList<MediaBucket> buckets) {
int numBuckets = buckets.size();
if (MediaBucketList.isSetSelection(buckets) && numBuckets == 1) {
- // If just 1 set was selected, save the trouble of processing the items in the set again.
+ // If just 1 set was selected, save the trouble of processing the
+ // items in the set again.
// We have already processed details for that set.
return populateSetViewDetailModeStrings(context, MediaBucketList.getFirstSetSelection(buckets), 1);
} else if (MediaBucketList.isSetSelection(buckets) || MediaBucketList.isMultipleItemSelection(buckets)) {
}
return populateSetViewDetailModeStrings(context, selectedItemsSet, numBuckets);
} else {
- return populateItemViewDetailModeStrings(context, MediaBucketList.getFirstItemSelection(buckets));
+ return populateItemViewDetailModeStrings(context, MediaBucketList.getFirstItemSelection(buckets));
}
}
}
Resources resources = context.getResources();
ArrayList<CharSequence> strings = new ArrayList<CharSequence>();
-
+
// Number of albums selected.
if (numOriginalSets == 1) {
strings.add("1 " + resources.getString(R.string.album_selected));
} else {
strings.add(Integer.toString(numItems) + " " + resources.getString(R.string.items_selected));
}
-
- DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.SHORT);
-
+
+ DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
+
// Start and end times of the selected items.
if (selectedItemsSet.areTimestampsAvailable()) {
long minTimestamp = selectedItemsSet.mMinTimestamp;
maxTimestamp -= Gallery.CURRENT_TIME_ZONE.getOffset(maxTimestamp);
}
strings.add(resources.getString(R.string.start) + ": " + dateTimeFormat.format(new Date(minTimestamp)));
- strings.add(resources.getString(R.string.end) + ": " + dateTimeFormat.format(new Date(maxTimestamp)));
+ strings.add(resources.getString(R.string.end) + ": " + dateTimeFormat.format(new Date(maxTimestamp)));
} else {
strings.add(resources.getString(R.string.start) + ": " + resources.getString(R.string.date_unknown));
strings.add(resources.getString(R.string.end) + ": " + resources.getString(R.string.date_unknown));
}
}
if (locationString != null && locationString.length() > 0) {
- strings.add(resources.getString(R.string.location) + ": " + locationString);
+ strings.add(resources.getString(R.string.location) + ": " + locationString);
}
int numStrings = strings.size();
CharSequence[] stringsArr = new CharSequence[numStrings];
for (int i = 0; i < numStrings; ++i) {
- stringsArr[i] = strings.get(i);
+ stringsArr[i] = strings.get(i);
}
return stringsArr;
}
if (item == null) {
return null;
}
- Resources resources = context.getResources();
+ Resources resources = context.getResources();
CharSequence[] strings = new CharSequence[5];
strings[0] = resources.getString(R.string.title) + ": " + item.mCaption;
strings[1] = resources.getString(R.string.type) + ": " + item.getDisplayMimeType();
-
- DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM,DateFormat.SHORT);
-
+
+ DateFormat dateTimeFormat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);
+
if (item.isDateTakenValid()) {
long dateTaken = item.mDateTakenInMs;
if (item.isPicassaItem()) {
dateAdded -= Gallery.CURRENT_TIME_ZONE.getOffset(dateAdded);
}
// TODO: Make this added_on as soon as translations are ready.
- //strings[2] = resources.getString(R.string.added_on) + ": " + DateFormat.format("h:mmaa MMM dd yyyy", dateAdded);
+ // strings[2] = resources.getString(R.string.added_on) + ": " +
+ // DateFormat.format("h:mmaa MMM dd yyyy", dateAdded);
strings[2] = resources.getString(R.string.taken_on) + ": " + dateTimeFormat.format(new Date(dateAdded));
} else {
strings[2] = resources.getString(R.string.taken_on) + ": " + resources.getString(R.string.date_unknown);
chunkFile.seek(record.offset);
chunkFile.write(data);
synchronized (mIndexMap) {
- mIndexMap.put(key, new Record(currentChunk, record.offset, data.length, record.sizeOnDisk, System.currentTimeMillis()));
+ mIndexMap.put(key, new Record(currentChunk, record.offset, data.length, record.sizeOnDisk, System
+ .currentTimeMillis()));
}
return;
}
}
mTargetPosition.add(mJitteredPosition);
mStacktopPosition.set(position);
- }
+ }
public int getStackIndex() {
return mStackId;
}
} else {
texture = new UriTexture(mItemRef.mScreennailUri);
- ((UriTexture)texture).setCacheId(Utils.Crc64Long(mItemRef.mFilePath));
+ ((UriTexture) texture).setCacheId(Utils.Crc64Long(mItemRef.mFilePath));
}
mScreennailImage = texture;
}
* @return true if the display item is animating
*/
public boolean isAnimating() {
- return mAlive && (!mAnimatedPosition.equals(mTargetPosition) ||
- mAnimatedTheta != mTargetTheta || mAnimatedImageTheta != mImageTheta ||
- mAnimatedPlaceholderFade != 1f);
+ return mAlive
+ && (!mAnimatedPosition.equals(mTargetPosition) || mAnimatedTheta != mTargetTheta
+ || mAnimatedImageTheta != mImageTheta || mAnimatedPlaceholderFade != 1f);
}
/**
mTitle = null;
mTitleImage = null;
mLocationImage = null;
+ if (set.mReverseGeocodedLocation == null) {
+ set.mReverseGeocodedLocationRequestMade = false;
+ set.mReverseGeocodedLocationComputed = false;
+ }
}
public MediaSet getMediaSet() {
}
}
- private StringTexture getTextureForString(String string, HashMap<String, StringTexture> textureTable, StringTexture.Config config) {
+ private StringTexture getTextureForString(String string, HashMap<String, StringTexture> textureTable,
+ StringTexture.Config config) {
StringTexture texture = null;
if (textureTable != null && textureTable.containsKey(string)) {
texture = textureTable.get(string);
StringTexture texture = mTitleImage;
String title = mSetRef.mTruncTitleString;
if (texture == null && title != null && !(title.equals(mTitle))) {
- texture = getTextureForString(title, textureTable, ((mSetRef.mId != Shared.INVALID && mSetRef.mId != 0) ? CAPTION_STYLE : CLUSTER_STYLE));
+ texture = getTextureForString(title, textureTable, ((mSetRef.mId != Shared.INVALID && mSetRef.mId != 0) ? CAPTION_STYLE
+ : CLUSTER_STYLE));
mTitleImage = texture;
mTitle = title;
}
String geocodedLocation = mSetRef.mReverseGeocodedLocation;
if (geocodedLocation != null) {
mLocation = geocodedLocation;
- mLocationImage = getTextureForString(mLocation, textureTable, LOCATION_STYLE);
+ mLocationImage = getTextureForString(mLocation, textureTable, LOCATION_STYLE);
}
}
}
mValue = value;
mStartTime = 0;
}
-
+
public boolean isAnimating() {
return mStartTime != 0;
}
-
+
public float getTimeRemaining(long currentTime) {
float duration = (currentTime - mStartTime) * 0.001f;
- if (mDuration > duration) // CR: braces
+ if (mDuration > duration) // CR: braces
return mDuration - duration;
else
return 0.0f;
private float getInterpolatedValue(long currentTime) {
float ratio = (float) (currentTime - mStartTime) * 0.001f / mDuration;
- if (ratio >= 1f) { // CR: 1.0f
+ if (ratio >= 1f) { // CR: 1.0f
mStartTime = 0;
return mValue;
} else {
- ratio = 0.5f - 0.5f * FloatMath.cos(ratio * 3.14159265f); // CR: (float)Math.PI
+ ratio = 0.5f - 0.5f * FloatMath.cos(ratio * 3.14159265f); // CR:
+ // (float)Math.PI
return mValue + (1f - ratio) * mDelta;
}
}
public class FloatUtils {
private static final float ANIMATION_SPEED = 4.0f;
-
+
/**
* This function animates a float value to another float value
- * @param prevVal: The previous value (or the animated value)
- * @param targetVal: The target value
- * @param timeElapsed Time elapsed since the last time this function was called
- * @return The new animated value that is closer to the target value and clamped to the target value
+ *
+ * @param prevVal
+ * : The previous value (or the animated value)
+ * @param targetVal
+ * : The target value
+ * @param timeElapsed
+ * Time elapsed since the last time this function was called
+ * @return The new animated value that is closer to the target value and
+ * clamped to the target value
*/
public static final float animate(float prevVal, float targetVal, float timeElapsed) {
timeElapsed = timeElapsed * ANIMATION_SPEED;
return animateAfterFactoringSpeed(prevVal, targetVal, timeElapsed);
}
-
+
/**
* This function animates a Tuple3f value to another Tuple3f value
- * @param animVal: The animating Tuple
- * @param targetVal: The target value for the Tuple
- * @param timeElapsed: Time elapsed since the last time this function was called
+ *
+ * @param animVal
+ * : The animating Tuple
+ * @param targetVal
+ * : The target value for the Tuple
+ * @param timeElapsed
+ * : Time elapsed since the last time this function was called
*/
public static final void animate(Vector3f animVal, Vector3f targetVal, float timeElapsed) {
timeElapsed = timeElapsed * ANIMATION_SPEED;
animVal.y = animateAfterFactoringSpeed(animVal.y, targetVal.y, timeElapsed);
animVal.z = animateAfterFactoringSpeed(animVal.z, targetVal.z, timeElapsed);
}
-
+
/**
* Clamp a float to a lower bound
- * @param val: the input float value
- * @param minVal: the minimum value to use to clamp
+ *
+ * @param val
+ * : the input float value
+ * @param minVal
+ * : the minimum value to use to clamp
* @return the clamped value
*/
public static final float clampMin(float val, float minVal) {
if (val < minVal)
- return minVal; // CR: braces
+ return minVal; // CR: braces
else
return val;
}
-
+
/**
* Clamp a float to an upper bound
- * @param val: the input float value
- * @param maxVal: the maximum value to use to clamp
+ *
+ * @param val
+ * : the input float value
+ * @param maxVal
+ * : the maximum value to use to clamp
* @return the clamped value
*/
public static final float clampMax(float val, float maxVal) {
else
return val;
}
-
- // CR: these comments are barely useful. they mostly just fill space. If anything, a one-liner would be sufficient.
+
+ // CR: these comments are barely useful. they mostly just fill space. If
+ // anything, a one-liner would be sufficient.
/**
* Clamp a float to a lower and upper bound
- * @param val: the input float value
- * @param minVal: the minimum value to use to clamp
- * @param maxVal: the maximum value to use to clamp
+ *
+ * @param val
+ * : the input float value
+ * @param minVal
+ * : the minimum value to use to clamp
+ * @param maxVal
+ * : the maximum value to use to clamp
* @return the clamped value
*/
public static final float clamp(float val, float minVal, float maxVal) {
else
return val;
}
-
+
/**
* Clamp an integer to a lower and upper bound
- * @param val: the input float value
- * @param minVal: the minimum value to use to clamp
- * @param maxVal: the maximum value to use to clamp
+ *
+ * @param val
+ * : the input float value
+ * @param minVal
+ * : the minimum value to use to clamp
+ * @param maxVal
+ * : the maximum value to use to clamp
* @return the clamped value
*/
public static final int clamp(int val, int minVal, int maxVal) {
else
return val;
}
-
+
/**
* Function to check whether a point lies inside a rectangle
- * @param left: the x coordinate of the left most point
- * @param right: the x coordinate of the right most point
- * @param top: the y coordinate of the top most point
- * @param bottom: the y coordinate of the bottom most point
- * @param posX: the input point's x coordinate
- * @param posY: the input point's y coordinate
+ *
+ * @param left
+ * : the x coordinate of the left most point
+ * @param right
+ * : the x coordinate of the right most point
+ * @param top
+ * : the y coordinate of the top most point
+ * @param bottom
+ * : the y coordinate of the bottom most point
+ * @param posX
+ * : the input point's x coordinate
+ * @param posY
+ * : the input point's y coordinate
* @return true if point is inside the rectangle else return false
*/
public static final boolean boundsContainsPoint(float left, float right, float top, float bottom, float posX, float posY) {
- // CR: return ... (one statement).
+ // CR: return ... (one statement).
if (posX < left || posX > right || posY < top || posY > bottom)
return false;
else
return targetVal;
if (newVal == prevVal) {
return targetVal;
- } else { // } else if (...) { ... }; no need for a new level of indentation.
+ } else { // } else if (...) { ... }; no need for a new level of
+ // indentation.
if (prevVal > targetVal && newVal < targetVal) {
return targetVal;
} else if (prevVal < targetVal && newVal > targetVal) {
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 final int CROP_MSG_INTERNAL = 100;
+ 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";
- 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;
+ 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 = new HashMap<String, Boolean>();
- @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.isSingleImage()) {
- 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");
- }
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ final boolean imageManagerHasStorage = ImageManager.quickHasStorage();
+ if (isViewIntent() && getIntent().getData().equals(Images.Media.EXTERNAL_CONTENT_URI)
+ && getIntent().getExtras().getBoolean("slideshow", false)) {
+ 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);
- public ReverseGeocoder getReverseGeocoder() {
- return mReverseGeocoder;
- }
+ // Creating the DataSource objects.
+ final PicasaDataSource picasaDataSource = new PicasaDataSource(this);
+ final LocalDataSource localDataSource = new LocalDataSource(this);
+ final ConcatenatedDataSource combinedDataSource = new ConcatenatedDataSource(localDataSource, picasaDataSource);
- public Handler getHandler() {
- return mHandler;
- }
+ // 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.isSingleImage()) {
+ 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");
+ }
- @Override
- public void onRestart() {
- super.onRestart();
- }
+ public ReverseGeocoder getReverseGeocoder() {
+ return mReverseGeocoder;
+ }
- @Override
- public void onStart() {
- super.onStart();
- }
+ public Handler getHandler() {
+ return mHandler;
+ }
- @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 onRestart() {
+ super.onRestart();
+ }
- @Override
- public void onPause() {
- super.onPause();
- if (mRenderView != null)
- mRenderView.onPause();
- mPause = true;
- }
+ @Override
+ public void onStart() {
+ super.onStart();
+ }
- public boolean isPaused() {
- return mPause;
- }
+ @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.
+ if (mGridLayer != null)
+ mGridLayer.setDataSource(mGridLayer.getDataSource());
+ break;
+ }
+ }
+ mAccountsEnabled = accountsEnabled;
+ mPause = false;
+ }
+ }
- @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 onPause() {
+ super.onPause();
+ if (mRenderView != null)
+ mRenderView.onPause();
+ mPause = 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");
- }
+ public boolean isPaused() {
+ return mPause;
+ }
- @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 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 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 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");
+ }
- private boolean isPickIntent() {
- String action = getIntent().getAction();
- return (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action));
- }
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ if (mGridLayer != null) {
+ mGridLayer.markDirty(30);
+ }
+ if (mRenderView != null)
+ mRenderView.requestRender();
+ Log.i(TAG, "onConfigurationChanged");
+ }
- private boolean isViewIntent() {
- String action = getIntent().getAction();
- return Intent.ACTION_VIEW.equals(action);
- }
+ @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 isImageType(String type) {
- return type.equals("vnd.android.cursor.dir/image") || type.equals("image/*");
- }
+ private boolean isPickIntent() {
+ String action = getIntent().getAction();
+ return (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action));
+ }
- private boolean isVideoType(String type) {
- return type.equals("vnd.android.cursor.dir/video") || type.equals("video/*");
- }
+ private boolean isViewIntent() {
+ String action = getIntent().getAction();
+ return Intent.ACTION_VIEW.equals(action);
+ }
- @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;
- }
- }
- }
+ private boolean isImageType(String type) {
+ return type.equals("vnd.android.cursor.dir/image") || type.equals("image/*");
+ }
- @Override
- public void onLowMemory() {
- if (mRenderView != null) {
- mRenderView.handleLowMemory();
- }
- }
+ private boolean isVideoType(String type) {
+ return type.equals("vnd.android.cursor.dir/video") || type.equals("video/*");
+ }
- 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("");
- }
- }
- }
+ @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;
+ }
+ }
+ }
- public void onScanCompleted(String path, Uri uri) {
- shutdown(uri.toString());
- }
+ @Override
+ public void onLowMemory() {
+ if (mRenderView != null) {
+ mRenderView.handleLowMemory();
+ }
+ }
- 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 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("");
+ }
+ }
+ }
- 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();
- }
+ 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);
+ }
+ }
+ }
+
+ 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();
+ }
}
public static final float EYE_Z = 8.0f; // Initial z distance.
private static final float DEFAULT_PORTRAIT_ASPECT = 320.0f / 480.0f;
private static final float DEFAULT_LANDSCAPE_ASPECT = 1.0f / DEFAULT_PORTRAIT_ASPECT;
-
+
public float mEyeX;
public float mEyeY;
public float mEyeZ;
public float mUpX;
public float mUpY;
public float mUpZ;
-
+
// To tilt the wall.
public float mEyeOffsetX;
public float mEyeOffsetY;
private float mEyeEdgeOffsetXAnim;
private float mAmountExceeding;
-
// Animation speed, 1.0f is normal speed.
public float mConvergenceSpeed;
-
+
// Camera field of view and its relation to the grid item width.
public float mFov;
public float mScale;
private float mEyeOffsetAnimX;
private float mEyeOffsetAnimY;
private float mTargetEyeX;
-
+
// Screen width and height.
private int mWidthBy2;
private int mHeightBy2;
private float mTanFovBy2;
-
+
public GridCamera(int width, int height, int itemWidth, int itemHeight) {
reset();
viewportChanged(width, height, itemWidth, itemHeight);
mHeight = h;
mWidthBy2 = w >> 1;
mHeightBy2 = h >> 1;
- mAspectRatio = (h == 0) ? 1.0f : (float)w / (float)h;
+ mAspectRatio = (h == 0) ? 1.0f : (float) w / (float) h;
mDefaultAspectRatio = (w > h) ? DEFAULT_LANDSCAPE_ASPECT : DEFAULT_PORTRAIT_ASPECT;
mTanFovBy2 = (float) Math.tan(Math.toRadians(fov * 0.5f));
mItemHeight = (int) itemHeight;
// The width will hit the screen.
h = (f * mHeight) / mWidth;
}
- // To fit ITEM_HEIGHT pixels perfectly, the targetZ value must be the 1.0f for the given fov
+ // To fit ITEM_HEIGHT pixels perfectly, the targetZ value must be the
+ // 1.0f for the given fov
// Thus to fit h pixels,
h = h / mItemHeight;
float targetZ = h / mTanFovBy2;
mPosY = mTargetPosY;
mPosZ = mTargetPosZ;
}
-
+
public void commitMoveInX() {
mPosX = mTargetPosX;
}
public void commitMoveInZ() {
mPosZ = mTargetPosZ;
}
-
+
public boolean computeConstraints(boolean applyConstraints, boolean applyOverflowFeedback, Vector3f firstSlotPosition,
Vector3f lastSlotPosition) {
boolean retVal = false;
}
if (applyConstraints) {
mEyeEdgeOffsetX = 0.0f;
- // We look at amount exceeding and calculate target position in the reverse direction.
+ // We look at amount exceeding and calculate target position in the
+ // reverse direction.
final float maxBounceBack = 0.8f;
if (mAmountExceeding < -maxBounceBack)
mAmountExceeding = -maxBounceBack;
public boolean isAnimating() {
return (mPosX != mTargetPosX || mPosY != mTargetPosY || mPosZ != mTargetPosZ || mEyeOffsetAnimX != mEyeOffsetX || mEyeEdgeOffsetXAnim != mEyeEdgeOffsetX);
}
-
+
public boolean isZAnimating() {
return mPosZ != mTargetPosZ;
}
mTargetEyeX = EYE_X + mPosX;
if (mEyeZ == EYE_Z) {
mEyeX = mTargetEyeX;
- // Enable the line below for achieving tilt while you scroll the wall.
- // FloatUtils.animate(eyeX_, targetEyeX_, timeElapsedx - (timeElapsedx * 0.35f));
+ // Enable the line below for achieving tilt while you scroll the
+ // wall.
+ // FloatUtils.animate(eyeX_, targetEyeX_, timeElapsedx -
+ // (timeElapsedx * 0.35f));
} else {
mEyeX = mTargetEyeX;
}
mLookAtZ = mPosZ;
}
}
-
package com.cooliris.media;
-
public final class GridCameraManager {
private final GridCamera mCamera;
private static final Pool<Vector3f> sPool;
width = height;
height = temp;
}
- camera.moveTo(position.x, position.y, zoomin ? camera.getDistanceToFitRect(width * oneByZoom, height * oneByZoom) : 0);
+ camera.moveTo(position.x, position.y, zoomin ? camera.getDistanceToFitRect(width * oneByZoom, height
+ * oneByZoom) : 0);
} finally {
pool.delete(position);
- pool.delete(deltaAnchorPosition);
+ pool.delete(deltaAnchorPosition);
}
} else {
camera.moveYTo(0);
}
}
- // CR: line too long. Documentation--what are the semantics of the return value?
+ // CR: line too long. Documentation--what are the semantics of the return
+ // value?
/**
*/
public boolean constrainCameraForSlot(LayoutInterface layout, int slotIndex, Vector3f deltaAnchorPositionIn,
if (bottomExtent > 0) {
camera.moveBy(0, -bottomExtent, 0);
}
- }
+ }
} finally {
pool.delete(position);
pool.delete(deltaAnchorPosition);
Texture texture = displayItem.getThumbnailImage(context, sThumbnailConfig);
if (texture != null && !texture.isLoaded() && numTexturesQueued <= 6) {
boolean isCached = texture.isCached();
- if (isCached)
- view.prime(texture, priority);
+ view.prime(texture, priority);
view.bind(texture);
if (priority && isCached && texture.mState != Texture.STATE_ERROR)
++numTexturesQueued;
}
public void drawBlendedComponents(RenderView view, GL11 gl, float alpha, int state, int hudMode, float stackMixRatio,
- float gridMixRatio, MediaBucketList bucketList, boolean isFeedLoading) {
+ float gridMixRatio, MediaBucketList selectedBucketList, MediaBucketList markedBucketList, boolean isFeedLoading) {
int firstBufferedVisibleSlot = mBufferedVisibleRange.begin;
int lastBufferedVisibleSlot = mBufferedVisibleRange.end;
int firstVisibleSlot = mVisibleRange.begin;
if (itemDrawn == null) {
continue;
}
- boolean displayItemPresentInSelectedItems = bucketList.find(itemDrawn.mItemRef);
+ boolean displayItemPresentInSelectedItems = selectedBucketList.find(itemDrawn.mItemRef);
+ boolean displayItemPresentInMarkedItems = markedBucketList.find(itemDrawn.mItemRef);
Texture previousTexture = (displayItemPresentInSelectedItems) ? texturePressed : texture;
Texture textureToUse = (itemDrawn.getHasFocus()) ? (currentFocusIsPressed ? texturePressed : textureFocus)
- : ((displayItemPresentInSelectedItems) ? texturePressed : textureGrid);
+ : ((displayItemPresentInSelectedItems) ? texturePressed : (displayItemPresentInMarkedItems) ? texture : textureGrid);
float ratio = timeElapsedSinceGridView;
if (itemDrawn.mAlive) {
if (state != GridLayer.STATE_GRID_VIEW) {
DisplaySlot displaySlot = displaySlots[i - firstBufferedVisibleSlot];
StringTexture textureString = displaySlot.getLocationImage(reverseGeocoder, stringTextureTable);
if (textureString != null) {
+ view.loadTexture(textureString);
drawDisplayItem(view, gl, displayItem, textureString, PASS_TEXT_LABEL, null, 0);
}
}
Texture locationTexture = view.getResource(drawables
.getIconForSet(displaySlot.getMediaSet(), false), false);
- // Draw the icon at 0.85 alpha over the top item in the stack.
+ // Draw the icon at 0.85 alpha over the top item
+ // in the stack.
gl.glTranslatef(0.24f, 0.5f, 0);
drawDisplayItem(view, gl, displayItem, locationTexture, PASS_MEDIASET_SOURCE_LABEL,
transparentTexture, 0.85f);
for (int i = firstBufferedVisibleSlot; i <= lastBufferedVisibleSlot; ++i) {
DisplayItem displayItem = displayItems[(i - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT];
if (displayItem != null) {
- Texture textureToUse = bucketList.find(displayItem.mItemRef) ? textureSelectedOn : textureSelectedOff;
+ Texture textureToUse = selectedBucketList.find(displayItem.mItemRef) ? textureSelectedOn : textureSelectedOff;
drawDisplayItem(view, gl, displayItem, textureToUse, PASS_SELECTION_LABEL, null, 0);
}
}
sFullscreenGrid[2] = GridQuad.createGridQuad(width, height, 0, 0, 1.0f, oneByAspect, false);
sFullscreenGrid[2].setDynamic(true);
- // We create supplementary quads for the checkmarks, video overlay and location button
+ // We create supplementary quads for the checkmarks, video overlay
+ // and location button
float sizeOfSelectedIcon = 32 * Gallery.PIXEL_DENSITY; // In pixels.
sizeOfSelectedIcon /= itemHeight;
float sizeOfLocationIcon = 52 * Gallery.PIXEL_DENSITY; // In pixels.
}
public int getIconForSet(MediaSet set, boolean scaled) {
- // We return the scaled version for HUD rendering and the unscaled version for 3D rendering.
+ // We return the scaled version for HUD rendering and the unscaled
+ // version for 3D rendering.
if (scaled) {
if (set == null) {
return R.drawable.icon_folder_small;
import android.view.MotionEvent;
public final class GridInputProcessor implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
- private int mCurrentFocusSlot;
- private boolean mCurrentFocusIsPressed;
- private int mCurrentSelectedSlot;
-
- private float mPrevTiltValueLowPass;
- private float mPrevShakeValueHighPass;
- private float mShakeValue;
- private int mTouchPosX;
- private int mTouchPosY;
- private int mActionCode;
- private long mPrevTouchTime;
- private float mFirstTouchPosX;
- private float mFirstTouchPosY;
- private float mPrevTouchPosX;
- private float mPrevTouchPosY;
- private float mTouchVelX;
- private float mTouchVelY;
- private boolean mProcessTouch;
- private boolean mTouchMoved;
- private float mDpadIgnoreTime = 0.0f;
- private GridCamera mCamera;
- private GridLayer mLayer;
- private Context mContext;
- private Pool<Vector3f> mPool;
- private DisplayItem[] mDisplayItems;
- private boolean mPrevHitEdge;
- private boolean mTouchFeedbackDelivered;
- private GestureDetector mGestureDetector;
-
- public GridInputProcessor(Context context, GridCamera camera, GridLayer layer, RenderView view, Pool<Vector3f> pool,
- DisplayItem[] displayItems) {
- mPool = pool;
- mCamera = camera;
- mLayer = layer;
- mCurrentFocusSlot = Shared.INVALID;
- mCurrentSelectedSlot = Shared.INVALID;
- mContext = context;
- mDisplayItems = displayItems;
- mGestureDetector = new GestureDetector(context, this);
- mGestureDetector.setIsLongpressEnabled(true);
- }
-
- public int getCurrentFocusSlot() {
- return mCurrentFocusSlot;
- }
-
- public int getCurrentSelectedSlot() {
- return mCurrentSelectedSlot;
- }
-
- public void setCurrentSelectedSlot(int slot) {
- mCurrentSelectedSlot = slot;
- GridLayer layer = mLayer;
- layer.setState(GridLayer.STATE_FULL_SCREEN);
- mCamera.mConvergenceSpeed = 2.0f;
- DisplayItem displayItem = layer.getDisplayItemForSlotId(slot);
- MediaItem item = null;
- if (displayItem != null)
- item = displayItem.mItemRef;
- layer.getHud().fullscreenSelectionChanged(item, mCurrentSelectedSlot + 1, layer.getCompleteRange().end + 1);
- }
-
- public void onSensorChanged(RenderView view, SensorEvent event, int state) {
- switch (event.sensor.getType()) {
- case Sensor.TYPE_ACCELEROMETER:
- case Sensor.TYPE_ORIENTATION:
- float[] values = event.values;
- float valueToUse = (mCamera.mWidth < mCamera.mHeight) ? values[0] : -values[1];
- float tiltValue = 0.8f * mPrevTiltValueLowPass + 0.2f * valueToUse;
- if (Math.abs(tiltValue) < 0.5f)
- tiltValue = 0.0f;
- if (state == GridLayer.STATE_FULL_SCREEN)
- tiltValue = 0.0f;
- if (tiltValue != 0.0f)
- view.requestRender();
- mCamera.mEyeOffsetX = -3.0f * tiltValue;
- float shakeValue = values[1] * values[1] + values[2] * values[2];
- mShakeValue = shakeValue - mPrevShakeValueHighPass;
- mPrevShakeValueHighPass = shakeValue;
- if (mShakeValue < 16.0f) {
- mShakeValue = 0;
- } else {
- mShakeValue = mShakeValue * 4.0f;
- if (mShakeValue > 200) {
- mShakeValue = 200;
- }
- }
- break;
- }
- }
-
- public boolean onTouchEvent(MotionEvent event) {
- mTouchPosX = (int) (event.getX());
- mTouchPosY = (int) (event.getY());
- mActionCode = event.getAction();
- long timestamp = SystemClock.elapsedRealtime();
- long delta = timestamp - mPrevTouchTime;
- mPrevTouchTime = timestamp;
- float timeElapsed = (float) delta;
- timeElapsed = timeElapsed * 0.001f; // division by 1000 for seconds
- switch (mActionCode) {
- case MotionEvent.ACTION_UP:
- if (mProcessTouch == false) {
- touchBegan(mTouchPosX, mTouchPosY);
- }
- touchEnded(mTouchPosX, mTouchPosY, timeElapsed);
- break;
- case MotionEvent.ACTION_DOWN:
- mPrevTouchTime = timestamp;
- touchBegan(mTouchPosX, mTouchPosY);
- break;
- case MotionEvent.ACTION_MOVE:
- touchMoved(mTouchPosX, mTouchPosY, timeElapsed);
- break;
- }
- mGestureDetector.onTouchEvent(event);
- return true;
- }
-
- public boolean onKeyDown(int keyCode, KeyEvent event, int state) {
- GridLayer layer = mLayer;
- if (keyCode == KeyEvent.KEYCODE_BACK) {
- if (layer.getViewIntent())
- return false;
- if (layer.getHud().getMode() == HudLayer.MODE_SELECT) {
- layer.deselectAll();
- return true;
- }
- if (layer.inSlideShowMode()) {
- layer.endSlideshow();
- layer.getHud().setAlpha(1.0f);
- return true;
- }
- float zoomValue = layer.getZoomValue();
- if (zoomValue != 1.0f) {
- layer.setZoomValue(1.0f);
- layer.centerCameraForSlot(mCurrentSelectedSlot, 1.0f);
- return true;
- }
- layer.goBack();
- if (state == GridLayer.STATE_MEDIA_SETS)
- return false;
- return true;
- }
- if (mDpadIgnoreTime < 0.1f)
- return true;
- mDpadIgnoreTime = 0.0f;
- IndexRange bufferedVisibleRange = layer.getBufferedVisibleRange();
- int firstBufferedVisibleSlot = bufferedVisibleRange.begin;
- int lastBufferedVisibleSlot = bufferedVisibleRange.end;
- int anchorSlot = layer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER);
- if (state == GridLayer.STATE_FULL_SCREEN) {
- if (keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN
- && keyCode != KeyEvent.KEYCODE_MUTE && keyCode != KeyEvent.KEYCODE_HEADSETHOOK
- && keyCode != KeyEvent.KEYCODE_NOTIFICATION) {
- layer.endSlideshow();
- }
- boolean needsVibrate = false;
- if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- needsVibrate = !layer.changeFocusToNextSlot(1.0f);
- }
- if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
- needsVibrate = !layer.changeFocusToPreviousSlot(1.0f);
- }
- if (needsVibrate) {
- vibrateShort();
- }
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && !mCamera.isAnimating()) {
- if (layer.getZoomValue() == 1.0f)
- layer.zoomInToSelectedItem();
- else
- 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
- layer.deselectAll();
- }
- } else {
- mCurrentFocusIsPressed = false;
- int numRows = ((GridLayoutInterface) layer.getLayoutInterface()).mNumRows;
- if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && mCurrentFocusSlot != Shared.INVALID) {
- if (layer.getHud().getMode() != HudLayer.MODE_SELECT) {
- boolean centerCamera = layer.tapGesture(mCurrentFocusSlot, false);
- if (centerCamera) {
- int slotId = mCurrentFocusSlot;
- selectSlot(slotId);
- }
- mCurrentFocusSlot = Shared.INVALID;
- return true;
- } else {
- layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true);
- }
- mCurrentFocusIsPressed = true;
- } else if (keyCode == KeyEvent.KEYCODE_MENU && mCurrentFocusSlot != Shared.INVALID) {
- if (layer.getHud().getMode() == HudLayer.MODE_NORMAL)
- layer.enterSelectionMode();
- else
- layer.deselectAll();
- } else if (mCurrentFocusSlot == Shared.INVALID) {
- mCurrentFocusSlot = anchorSlot;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
- mCurrentFocusSlot += numRows;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
- mCurrentFocusSlot -= numRows;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
- --mCurrentFocusSlot;
- } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
- ++mCurrentFocusSlot;
- }
- if (mCurrentFocusSlot > lastBufferedVisibleSlot) {
- mCurrentFocusSlot = lastBufferedVisibleSlot;
- }
- if (mCurrentFocusSlot < firstBufferedVisibleSlot)
- mCurrentFocusSlot = firstBufferedVisibleSlot;
- if (mCurrentFocusSlot != Shared.INVALID) {
- layer.centerCameraForSlot(mCurrentFocusSlot, 1.0f);
- }
- }
- return false;
- }
-
- private void touchBegan(int posX, int posY) {
- mPrevTouchPosX = posX;
- mPrevTouchPosY = posY;
- mFirstTouchPosX = posX;
- mFirstTouchPosY = posY;
- mTouchVelX = 0;
- mTouchVelY = 0;
- mProcessTouch = true;
- mTouchMoved = false;
- mCamera.stopMovementInX();
- GridLayer layer = mLayer;
- mCurrentFocusSlot = layer.getSlotIndexForScreenPosition(posX, posY);
- mCurrentFocusIsPressed = true;
- mTouchFeedbackDelivered = false;
- HudLayer hud = layer.getHud();
- if (hud.getMode() == HudLayer.MODE_SELECT)
- hud.closeSelectionMenu();
- if (layer.getState() == GridLayer.STATE_FULL_SCREEN && hud.getMode() == HudLayer.MODE_SELECT) {
- layer.deselectAll();
- hud.setAlpha(1.0f);
- }
- int slotId = layer.getSlotIndexForScreenPosition(posX, posY);
- if (slotId != Shared.INVALID && layer.getState() != GridLayer.STATE_FULL_SCREEN) {
- vibrateShort();
- }
- }
-
- private void touchMoved(int posX, int posY, float timeElapsedx) {
- if (mProcessTouch) {
- GridLayer layer = mLayer;
- GridCamera camera = mCamera;
- float deltaX = -(posX - mPrevTouchPosX); // negation since the wall
- // moves in a direction
- // opposite to that of
- // the touch
- float deltaY = -(posY - mPrevTouchPosY);
- if (Math.abs(deltaX) >= 10.0f || Math.abs(deltaY) >= 10.0f) {
- mTouchMoved = true;
- }
- Pool<Vector3f> pool = mPool;
- Vector3f firstPosition = pool.create();
- Vector3f lastPosition = pool.create();
- Vector3f deltaAnchorPosition = pool.create();
- Vector3f worldPosDelta = pool.create();
- try {
- deltaAnchorPosition.set(layer.getDeltaAnchorPosition());
- LayoutInterface layout = layer.getLayoutInterface();
- GridCameraManager.getSlotPositionForSlotIndex(0, camera, layout, deltaAnchorPosition, firstPosition);
- int lastSlotIndex = 0;
- IndexRange completeRange = layer.getCompleteRange();
- synchronized (completeRange) {
- lastSlotIndex = completeRange.end;
- }
- GridCameraManager.getSlotPositionForSlotIndex(lastSlotIndex, camera, layout, deltaAnchorPosition, lastPosition);
-
- camera.convertToRelativeCameraSpace(deltaX, deltaY, 0, worldPosDelta);
- deltaX = worldPosDelta.x;
- deltaY = worldPosDelta.y;
- camera.moveBy(deltaX, (layer.getZoomValue() == 1.0f) ? 0 : deltaY, 0);
- deltaX *= camera.mScale;
- deltaY *= camera.mScale;
- } finally {
- pool.delete(firstPosition);
- pool.delete(lastPosition);
- pool.delete(deltaAnchorPosition);
- pool.delete(worldPosDelta);
- }
- if (layer.getZoomValue() == 1.0f) {
- if (camera
- .computeConstraints(false, (layer.getState() != GridLayer.STATE_FULL_SCREEN), firstPosition, lastPosition)) {
- deltaX = 0.0f;
- // vibrate
- if (!mTouchFeedbackDelivered) {
- mTouchFeedbackDelivered = true;
- vibrateLong();
- }
- }
- }
- mTouchVelX = deltaX * timeElapsedx;
- mTouchVelY = deltaY * timeElapsedx;
- float maxVelXx = (mCamera.mWidth * 0.5f);
- float maxVelYx = (mCamera.mHeight);
- mTouchVelX = FloatUtils.clamp(mTouchVelX, -maxVelXx, maxVelXx);
- mTouchVelY = FloatUtils.clamp(mTouchVelY, -maxVelYx, maxVelYx);
- mPrevTouchPosX = posX;
- mPrevTouchPosY = posY;
- // you want the movement to track the finger immediately
- if (mTouchMoved == false)
- mCurrentFocusSlot = layer.getSlotIndexForScreenPosition(posX, posY);
- else
- mCurrentFocusSlot = Shared.INVALID;
- if (!mCamera.isZAnimating()) {
- mCamera.commitMoveInX();
- mCamera.commitMoveInY();
- }
- int anchorSlotIndex = layer.getAnchorSlotIndex(GridLayer.ANCHOR_LEFT);
- DisplayItem[] displayItems = mDisplayItems;
- IndexRange bufferedVisibleRange = layer.getBufferedVisibleRange();
- int firstBufferedVisibleSlot = bufferedVisibleRange.begin;
- int lastBufferedVisibleSlot = bufferedVisibleRange.end;
- synchronized (displayItems) {
- if (anchorSlotIndex >= firstBufferedVisibleSlot && anchorSlotIndex <= lastBufferedVisibleSlot) {
- DisplayItem item = displayItems[(anchorSlotIndex - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT];
- if (item != null) {
- layer.getHud().setTimeBarTime(item.mItemRef.mDateTakenInMs);
- }
- }
- }
- }
- }
-
- private void touchEnded(int posX, int posY, float timeElapsedx) {
- if (mProcessTouch == false)
- return;
- int maxPixelsBeforeSwitch = mCamera.mWidth / 8;
- mCamera.mConvergenceSpeed = 2.0f;
- GridLayer layer = mLayer;
- if (layer.getExpandedSlot() == Shared.INVALID && !layer.feedAboutToChange()) {
- if (mCurrentSelectedSlot != Shared.INVALID) {
- if (layer.getState() == GridLayer.STATE_FULL_SCREEN) {
- if (!mTouchMoved) {
- // tap gesture for fullscreen
- if (layer.getZoomValue() == 1.0f)
- layer.changeFocusToSlot(mCurrentSelectedSlot, 1.0f);
- } else if (layer.getZoomValue() == 1.0f) {
- // we want to snap to a new slotIndex based on where the
- // current position is
- if (layer.inSlideShowMode()) {
- layer.endSlideshow();
- }
- float deltaX = posX - mFirstTouchPosX;
- float deltaY = posY - mFirstTouchPosY;
- if (deltaY != 0) {
- // it has moved vertically
- }
- layer.changeFocusToSlot(mCurrentSelectedSlot, 1.0f);
- HudLayer hud = layer.getHud();
- if (deltaX > maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
- layer.changeFocusToPreviousSlot(1.0f);
- } else if (deltaX < -maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
- layer.changeFocusToNextSlot(1.0f);
- }
- } else {
- // in zoomed state
- // we do nothing for now, but we should clamp to the
- // image bounds
- boolean hitEdge = layer.constrainCameraForSlot(mCurrentSelectedSlot);
- // mPrevHitEdge = false;
- if (hitEdge && mPrevHitEdge) {
- float deltaX = posX - mFirstTouchPosX;
- float deltaY = posY - mFirstTouchPosY;
- maxPixelsBeforeSwitch *= 4;
- if (deltaY != 0) {
- // it has moved vertically
- }
- mPrevHitEdge = false;
- HudLayer hud = layer.getHud();
- if (deltaX > maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
- layer.changeFocusToPreviousSlot(1.0f);
- } else if (deltaX < -maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
- layer.changeFocusToNextSlot(1.0f);
- } else {
- mPrevHitEdge = hitEdge;
- }
- } else {
- mPrevHitEdge = hitEdge;
- }
- }
- }
- } else {
- if (!layer.feedAboutToChange() && layer.getZoomValue() == 1.0f) {
- constrainCamera(true);
- }
- }
- }
- mCurrentFocusSlot = Shared.INVALID;
- mCurrentFocusIsPressed = false;
- mPrevTouchPosX = posX;
- mPrevTouchPosY = posY;
- mProcessTouch = false;
- }
-
- private void constrainCamera(boolean b) {
- Pool<Vector3f> pool = mPool;
- GridLayer layer = mLayer;
- Vector3f firstPosition = pool.create();
- Vector3f lastPosition = pool.create();
- Vector3f deltaAnchorPosition = pool.create();
- try {
- deltaAnchorPosition.set(layer.getDeltaAnchorPosition());
- GridCamera camera = mCamera;
- LayoutInterface layout = layer.getLayoutInterface();
- GridCameraManager.getSlotPositionForSlotIndex(0, camera, layout, deltaAnchorPosition, firstPosition);
- int lastSlotIndex = 0;
- IndexRange completeRange = layer.getCompleteRange();
- synchronized (completeRange) {
- lastSlotIndex = completeRange.end;
- }
- GridCameraManager.getSlotPositionForSlotIndex(lastSlotIndex, camera, layout, deltaAnchorPosition, lastPosition);
- camera.computeConstraints(true, (layer.getState() != GridLayer.STATE_FULL_SCREEN), firstPosition, lastPosition);
- } finally {
- pool.delete(firstPosition);
- pool.delete(lastPosition);
- pool.delete(deltaAnchorPosition);
- }
- }
-
- public void clearSelection() {
- mCurrentSelectedSlot = Shared.INVALID;
- }
-
- public void clearFocus() {
- mCurrentFocusSlot = Shared.INVALID;
- }
-
- public boolean isFocusItemPressed() {
- return mCurrentFocusIsPressed;
- }
-
- public void update(float timeElapsed) {
- mDpadIgnoreTime += timeElapsed;
- }
-
- public void setCurrentFocusSlot(int slotId) {
- mCurrentSelectedSlot = slotId;
- }
-
- public boolean onDown(MotionEvent e) {
- // TODO Auto-generated method stub
- return true;
- }
-
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- if (mCurrentSelectedSlot == Shared.INVALID) {
- mCamera.moveYTo(0);
- mCamera.moveZTo(0);
- mCamera.mConvergenceSpeed = 1.0f;
- float normalizedVelocity = velocityX * mCamera.mOneByScale;
- // mCamera.moveBy(-velocityX * mCamera.mOneByScale * 0.25f, 0, 0);
- // constrainCamera(true);
- IndexRange visibleRange = mLayer.getVisibleRange();
- int numVisibleSlots = visibleRange.end - visibleRange.begin;
- if (numVisibleSlots > 0) {
- float fastFlingVelocity = 20.0f;
- int slotsToSkip = (int) (numVisibleSlots * (-normalizedVelocity / fastFlingVelocity));
- int maxSlots = numVisibleSlots;
- if (slotsToSkip > maxSlots)
- slotsToSkip = maxSlots;
- if (slotsToSkip < -maxSlots)
- slotsToSkip = -maxSlots;
- if (Math.abs(slotsToSkip) <= 1) {
- if (velocityX > 0)
- slotsToSkip = -2;
- else if (velocityX < 0)
- slotsToSkip = 2;
- }
- int slotToGetTo = mLayer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER) + slotsToSkip;
- if (slotToGetTo < 0)
- slotToGetTo = 0;
- int lastSlot = mLayer.getCompleteRange().end;
- if (slotToGetTo > lastSlot)
- slotToGetTo = lastSlot;
- mLayer.centerCameraForSlot(slotToGetTo, 1.0f);
- }
- constrainCamera(true);
- return true;
- } else {
- return false;
- }
- }
-
- public void onLongPress(MotionEvent e) {
- if (mLayer.getFeed() != null && mLayer.getFeed().isSingleImageMode()) {
- HudLayer hud = mLayer.getHud();
- hud.getPathBar().setHidden(true);
- hud.getMenuBar().setHidden(true);
- if (hud.getMode() != HudLayer.MODE_NORMAL)
- hud.setMode(HudLayer.MODE_NORMAL);
- }
- if (mCurrentFocusSlot != Shared.INVALID) {
- vibrateLong();
- GridLayer layer = mLayer;
- if (layer.getState() == GridLayer.STATE_FULL_SCREEN) {
- layer.deselectAll();
- }
- HudLayer hud = layer.getHud();
- hud.enterSelectionMode();
- layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true);
- }
- }
-
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- // TODO Auto-generated method stub
- return false;
- }
-
- public void onShowPress(MotionEvent e) {
- // TODO Auto-generated method stub
-
- }
-
- public boolean onSingleTapUp(MotionEvent e) {
- GridLayer layer = mLayer;
- int posX = (int) e.getX();
- int posY = (int) e.getY();
- if (mCurrentSelectedSlot != Shared.INVALID) {
- // Fullscreen mode.
- mCamera.mConvergenceSpeed = 2.0f;
- int slotId = mCurrentSelectedSlot;
- if (layer.getZoomValue() == 1.0f) {
- layer.centerCameraForSlot(slotId, 1.0f);
- } else {
- layer.constrainCameraForSlot(slotId);
- }
- DisplayItem displayItem = layer.getDisplayItemForSlotId(slotId);
- if (displayItem != null) {
- final MediaItem item = displayItem.mItemRef;
- int heightBy2 = mCamera.mHeight / 2;
- boolean posYInBounds = (Math.abs(posY - heightBy2) < 64);
- if (posX < 32 && posYInBounds) {
- layer.changeFocusToPreviousSlot(1.0f);
- } else if (posX > mCamera.mWidth - 32 && posYInBounds) {
- layer.changeFocusToNextSlot(1.0f);
- } else if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) {
- Utils.playVideo(mContext, item);
- } else {
- // We stop any slideshow.
- HudLayer hud = layer.getHud();
- if (layer.inSlideShowMode()) {
- layer.endSlideshow();
- } else {
- hud.setAlpha(1.0f - hud.getAlpha());
- }
- if (hud.getMode() == HudLayer.MODE_SELECT) {
- hud.setAlpha(1.0f);
- }
- }
- }
- } else {
- int slotId = layer.getSlotIndexForScreenPosition(posX, posY);
- if (slotId != Shared.INVALID) {
- HudLayer hud = layer.getHud();
- if (hud.getMode() == HudLayer.MODE_SELECT) {
- layer.addSlotToSelectedItems(slotId, true, true);
- } else {
- boolean centerCamera = (mCurrentSelectedSlot == Shared.INVALID) ? layer.tapGesture(slotId, false) : true;
- if (centerCamera) {
- // We check if this item is a video or not.
- selectSlot(slotId);
- }
- }
- } else {
- int state = layer.getState();
- if (state != GridLayer.STATE_FULL_SCREEN && state != GridLayer.STATE_GRID_VIEW
- && layer.getHud().getMode() != HudLayer.MODE_SELECT) {
- slotId = layer.getMetadataSlotIndexForScreenPosition(posX, posY);
- if (slotId != Shared.INVALID) {
- layer.tapGesture(slotId, true);
- }
- }
- }
- }
- return true;
- }
-
- private void selectSlot(int slotId) {
- GridLayer layer = mLayer;
- if (layer.getState() == GridLayer.STATE_GRID_VIEW) {
- DisplayItem displayItem = layer.getDisplayItemForSlotId(slotId);
- if (displayItem != null) {
- final MediaItem item = displayItem.mItemRef;
- if (layer.getPickIntent()) {
- // we need to return this item
- ((Gallery) mContext).getHandler().post(new Runnable() {
- public void run() {
- ((Gallery) mContext).launchCropperOrFinish(item);
- }
- });
- return;
- }
- if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) {
- Utils.playVideo(mContext, item);
- } else {
- mCurrentSelectedSlot = slotId;
- layer.endSlideshow();
- layer.setState(GridLayer.STATE_FULL_SCREEN);
- mCamera.mConvergenceSpeed = 2.0f;
- layer.getHud().fullscreenSelectionChanged(item, mCurrentSelectedSlot + 1, layer.getCompleteRange().end + 1);
- }
- }
- }
- }
-
- public boolean onDoubleTap(MotionEvent e) {
- final GridLayer layer = mLayer;
- if (layer.getState() == GridLayer.STATE_FULL_SCREEN && !mCamera.isZAnimating()) {
- float posX = e.getX();
- float posY = e.getY();
- final Vector3f retVal = new Vector3f();
- posX -= (mCamera.mWidth / 2);
- posY -= (mCamera.mHeight / 2);
- mCamera.convertToRelativeCameraSpace(posX, posY, 0, retVal);
- if (layer.getZoomValue() == 1.0f) {
- layer.setZoomValue(3f);
- mCamera.update(0.001f);
- mCamera.moveBy(retVal.x, retVal.y, 0);
- layer.constrainCameraForSlot(mCurrentSelectedSlot);
- } else {
- layer.setZoomValue(1.0f);
- }
- mCamera.mConvergenceSpeed = 2.0f;
- } else {
- return onSingleTapConfirmed(e);
- }
- return true;
- }
-
- public boolean onDoubleTapEvent(MotionEvent e) {
- return false;
- }
-
- public boolean onSingleTapConfirmed(MotionEvent e) {
- return false;
- }
-
- public boolean touchPressed() {
- return mProcessTouch;
- }
-
- private void vibrateShort() {
- // As per request by Google, this line disables vibration.
- // mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
- }
-
- private void vibrateLong() {
- // mView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
- }
+ private int mCurrentFocusSlot;
+ private boolean mCurrentFocusIsPressed;
+ private int mCurrentSelectedSlot;
+
+ private float mPrevTiltValueLowPass;
+ private float mPrevShakeValueHighPass;
+ private float mShakeValue;
+ private int mTouchPosX;
+ private int mTouchPosY;
+ private int mActionCode;
+ private long mPrevTouchTime;
+ private float mFirstTouchPosX;
+ private float mFirstTouchPosY;
+ private float mPrevTouchPosX;
+ private float mPrevTouchPosY;
+ private float mTouchVelX;
+ private float mTouchVelY;
+ private boolean mProcessTouch;
+ private boolean mTouchMoved;
+ private float mDpadIgnoreTime = 0.0f;
+ private GridCamera mCamera;
+ private GridLayer mLayer;
+ private Context mContext;
+ private Pool<Vector3f> mPool;
+ private DisplayItem[] mDisplayItems;
+ private boolean mPrevHitEdge;
+ private boolean mTouchFeedbackDelivered;
+ private GestureDetector mGestureDetector;
+
+ public GridInputProcessor(Context context, GridCamera camera, GridLayer layer, RenderView view, Pool<Vector3f> pool,
+ DisplayItem[] displayItems) {
+ mPool = pool;
+ mCamera = camera;
+ mLayer = layer;
+ mCurrentFocusSlot = Shared.INVALID;
+ mCurrentSelectedSlot = Shared.INVALID;
+ mContext = context;
+ mDisplayItems = displayItems;
+ mGestureDetector = new GestureDetector(context, this);
+ mGestureDetector.setIsLongpressEnabled(true);
+ }
+
+ public int getCurrentFocusSlot() {
+ return mCurrentFocusSlot;
+ }
+
+ public int getCurrentSelectedSlot() {
+ return mCurrentSelectedSlot;
+ }
+
+ public void setCurrentSelectedSlot(int slot) {
+ mCurrentSelectedSlot = slot;
+ GridLayer layer = mLayer;
+ layer.setState(GridLayer.STATE_FULL_SCREEN);
+ mCamera.mConvergenceSpeed = 2.0f;
+ DisplayItem displayItem = layer.getDisplayItemForSlotId(slot);
+ MediaItem item = null;
+ if (displayItem != null)
+ item = displayItem.mItemRef;
+ layer.getHud().fullscreenSelectionChanged(item, mCurrentSelectedSlot + 1, layer.getCompleteRange().end + 1);
+ }
+
+ public void onSensorChanged(RenderView view, SensorEvent event, int state) {
+ switch (event.sensor.getType()) {
+ case Sensor.TYPE_ACCELEROMETER:
+ case Sensor.TYPE_ORIENTATION:
+ float[] values = event.values;
+ float valueToUse = (mCamera.mWidth < mCamera.mHeight) ? values[0] : -values[1];
+ float tiltValue = 0.8f * mPrevTiltValueLowPass + 0.2f * valueToUse;
+ if (Math.abs(tiltValue) < 0.5f)
+ tiltValue = 0.0f;
+ if (state == GridLayer.STATE_FULL_SCREEN)
+ tiltValue = 0.0f;
+ if (tiltValue != 0.0f)
+ view.requestRender();
+ mCamera.mEyeOffsetX = -3.0f * tiltValue;
+ float shakeValue = values[1] * values[1] + values[2] * values[2];
+ mShakeValue = shakeValue - mPrevShakeValueHighPass;
+ mPrevShakeValueHighPass = shakeValue;
+ if (mShakeValue < 16.0f) {
+ mShakeValue = 0;
+ } else {
+ mShakeValue = mShakeValue * 4.0f;
+ if (mShakeValue > 200) {
+ mShakeValue = 200;
+ }
+ }
+ break;
+ }
+ }
+
+ public boolean onTouchEvent(MotionEvent event) {
+ mTouchPosX = (int) (event.getX());
+ mTouchPosY = (int) (event.getY());
+ mActionCode = event.getAction();
+ long timestamp = SystemClock.elapsedRealtime();
+ long delta = timestamp - mPrevTouchTime;
+ mPrevTouchTime = timestamp;
+ float timeElapsed = (float) delta;
+ timeElapsed = timeElapsed * 0.001f; // division by 1000 for seconds
+ switch (mActionCode) {
+ case MotionEvent.ACTION_UP:
+ if (mProcessTouch == false) {
+ touchBegan(mTouchPosX, mTouchPosY);
+ }
+ touchEnded(mTouchPosX, mTouchPosY, timeElapsed);
+ break;
+ case MotionEvent.ACTION_DOWN:
+ mPrevTouchTime = timestamp;
+ touchBegan(mTouchPosX, mTouchPosY);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ touchMoved(mTouchPosX, mTouchPosY, timeElapsed);
+ break;
+ }
+ mGestureDetector.onTouchEvent(event);
+ return true;
+ }
+
+ public boolean onKeyDown(int keyCode, KeyEvent event, int state) {
+ GridLayer layer = mLayer;
+ if (keyCode == KeyEvent.KEYCODE_BACK) {
+ if (layer.getViewIntent())
+ return false;
+ if (layer.getHud().getMode() == HudLayer.MODE_SELECT) {
+ layer.deselectAll();
+ return true;
+ }
+ if (layer.inSlideShowMode()) {
+ layer.endSlideshow();
+ layer.getHud().setAlpha(1.0f);
+ return true;
+ }
+ float zoomValue = layer.getZoomValue();
+ if (zoomValue != 1.0f) {
+ layer.setZoomValue(1.0f);
+ layer.centerCameraForSlot(mCurrentSelectedSlot, 1.0f);
+ return true;
+ }
+ layer.goBack();
+ if (state == GridLayer.STATE_MEDIA_SETS)
+ return false;
+ return true;
+ }
+ if (mDpadIgnoreTime < 0.1f)
+ return true;
+ mDpadIgnoreTime = 0.0f;
+ IndexRange bufferedVisibleRange = layer.getBufferedVisibleRange();
+ int firstBufferedVisibleSlot = bufferedVisibleRange.begin;
+ int lastBufferedVisibleSlot = bufferedVisibleRange.end;
+ int anchorSlot = layer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER);
+ if (state == GridLayer.STATE_FULL_SCREEN) {
+ if (keyCode != KeyEvent.KEYCODE_VOLUME_UP && keyCode != KeyEvent.KEYCODE_VOLUME_DOWN
+ && keyCode != KeyEvent.KEYCODE_MUTE && keyCode != KeyEvent.KEYCODE_HEADSETHOOK
+ && keyCode != KeyEvent.KEYCODE_NOTIFICATION) {
+ layer.endSlideshow();
+ }
+ boolean needsVibrate = false;
+ if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ needsVibrate = !layer.changeFocusToNextSlot(1.0f);
+ }
+ if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
+ needsVibrate = !layer.changeFocusToPreviousSlot(1.0f);
+ }
+ if (needsVibrate) {
+ vibrateShort();
+ }
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && !mCamera.isAnimating()) {
+ if (layer.getZoomValue() == 1.0f)
+ layer.zoomInToSelectedItem();
+ else
+ 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
+ layer.deselectAll();
+ }
+ } else {
+ mCurrentFocusIsPressed = false;
+ int numRows = ((GridLayoutInterface) layer.getLayoutInterface()).mNumRows;
+ if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER && mCurrentFocusSlot != Shared.INVALID) {
+ if (layer.getHud().getMode() != HudLayer.MODE_SELECT) {
+ boolean centerCamera = layer.tapGesture(mCurrentFocusSlot, false);
+ if (centerCamera) {
+ int slotId = mCurrentFocusSlot;
+ selectSlot(slotId);
+ }
+ mCurrentFocusSlot = Shared.INVALID;
+ return true;
+ } else {
+ layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true);
+ }
+ mCurrentFocusIsPressed = true;
+ } else if (keyCode == KeyEvent.KEYCODE_MENU && mCurrentFocusSlot != Shared.INVALID) {
+ if (layer.getHud().getMode() == HudLayer.MODE_NORMAL)
+ layer.enterSelectionMode();
+ else
+ layer.deselectAll();
+ } else if (mCurrentFocusSlot == Shared.INVALID) {
+ mCurrentFocusSlot = anchorSlot;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
+ mCurrentFocusSlot += numRows;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {
+ mCurrentFocusSlot -= numRows;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
+ --mCurrentFocusSlot;
+ } else if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
+ ++mCurrentFocusSlot;
+ }
+ if (mCurrentFocusSlot > lastBufferedVisibleSlot) {
+ mCurrentFocusSlot = lastBufferedVisibleSlot;
+ }
+ if (mCurrentFocusSlot < firstBufferedVisibleSlot)
+ mCurrentFocusSlot = firstBufferedVisibleSlot;
+ if (mCurrentFocusSlot != Shared.INVALID) {
+ layer.centerCameraForSlot(mCurrentFocusSlot, 1.0f);
+ }
+ }
+ return false;
+ }
+
+ private void touchBegan(int posX, int posY) {
+ mPrevTouchPosX = posX;
+ mPrevTouchPosY = posY;
+ mFirstTouchPosX = posX;
+ mFirstTouchPosY = posY;
+ mTouchVelX = 0;
+ mTouchVelY = 0;
+ mProcessTouch = true;
+ mTouchMoved = false;
+ mCamera.stopMovementInX();
+ GridLayer layer = mLayer;
+ mCurrentFocusSlot = layer.getSlotIndexForScreenPosition(posX, posY);
+ mCurrentFocusIsPressed = true;
+ mTouchFeedbackDelivered = false;
+ HudLayer hud = layer.getHud();
+ if (hud.getMode() == HudLayer.MODE_SELECT)
+ hud.closeSelectionMenu();
+ if (layer.getState() == GridLayer.STATE_FULL_SCREEN && hud.getMode() == HudLayer.MODE_SELECT) {
+ layer.deselectAll();
+ hud.setAlpha(1.0f);
+ }
+ int slotId = layer.getSlotIndexForScreenPosition(posX, posY);
+ if (slotId != Shared.INVALID && layer.getState() != GridLayer.STATE_FULL_SCREEN) {
+ vibrateShort();
+ }
+ }
+
+ private void touchMoved(int posX, int posY, float timeElapsedx) {
+ if (mProcessTouch) {
+ GridLayer layer = mLayer;
+ GridCamera camera = mCamera;
+ float deltaX = -(posX - mPrevTouchPosX); // negation since the wall
+ // moves in a direction
+ // opposite to that of
+ // the touch
+ float deltaY = -(posY - mPrevTouchPosY);
+ if (Math.abs(deltaX) >= 10.0f || Math.abs(deltaY) >= 10.0f) {
+ mTouchMoved = true;
+ }
+ Pool<Vector3f> pool = mPool;
+ Vector3f firstPosition = pool.create();
+ Vector3f lastPosition = pool.create();
+ Vector3f deltaAnchorPosition = pool.create();
+ Vector3f worldPosDelta = pool.create();
+ try {
+ deltaAnchorPosition.set(layer.getDeltaAnchorPosition());
+ LayoutInterface layout = layer.getLayoutInterface();
+ GridCameraManager.getSlotPositionForSlotIndex(0, camera, layout, deltaAnchorPosition, firstPosition);
+ int lastSlotIndex = 0;
+ IndexRange completeRange = layer.getCompleteRange();
+ synchronized (completeRange) {
+ lastSlotIndex = completeRange.end;
+ }
+ GridCameraManager.getSlotPositionForSlotIndex(lastSlotIndex, camera, layout, deltaAnchorPosition, lastPosition);
+
+ camera.convertToRelativeCameraSpace(deltaX, deltaY, 0, worldPosDelta);
+ deltaX = worldPosDelta.x;
+ deltaY = worldPosDelta.y;
+ camera.moveBy(deltaX, (layer.getZoomValue() == 1.0f) ? 0 : deltaY, 0);
+ deltaX *= camera.mScale;
+ deltaY *= camera.mScale;
+ } finally {
+ pool.delete(firstPosition);
+ pool.delete(lastPosition);
+ pool.delete(deltaAnchorPosition);
+ pool.delete(worldPosDelta);
+ }
+ if (layer.getZoomValue() == 1.0f) {
+ if (camera
+ .computeConstraints(false, (layer.getState() != GridLayer.STATE_FULL_SCREEN), firstPosition, lastPosition)) {
+ deltaX = 0.0f;
+ // vibrate
+ if (!mTouchFeedbackDelivered) {
+ mTouchFeedbackDelivered = true;
+ vibrateLong();
+ }
+ }
+ }
+ mTouchVelX = deltaX * timeElapsedx;
+ mTouchVelY = deltaY * timeElapsedx;
+ float maxVelXx = (mCamera.mWidth * 0.5f);
+ float maxVelYx = (mCamera.mHeight);
+ mTouchVelX = FloatUtils.clamp(mTouchVelX, -maxVelXx, maxVelXx);
+ mTouchVelY = FloatUtils.clamp(mTouchVelY, -maxVelYx, maxVelYx);
+ mPrevTouchPosX = posX;
+ mPrevTouchPosY = posY;
+ // you want the movement to track the finger immediately
+ if (mTouchMoved == false)
+ mCurrentFocusSlot = layer.getSlotIndexForScreenPosition(posX, posY);
+ else
+ mCurrentFocusSlot = Shared.INVALID;
+ if (!mCamera.isZAnimating()) {
+ mCamera.commitMoveInX();
+ mCamera.commitMoveInY();
+ }
+ int anchorSlotIndex = layer.getAnchorSlotIndex(GridLayer.ANCHOR_LEFT);
+ DisplayItem[] displayItems = mDisplayItems;
+ IndexRange bufferedVisibleRange = layer.getBufferedVisibleRange();
+ int firstBufferedVisibleSlot = bufferedVisibleRange.begin;
+ int lastBufferedVisibleSlot = bufferedVisibleRange.end;
+ synchronized (displayItems) {
+ if (anchorSlotIndex >= firstBufferedVisibleSlot && anchorSlotIndex <= lastBufferedVisibleSlot) {
+ DisplayItem item = displayItems[(anchorSlotIndex - firstBufferedVisibleSlot) * GridLayer.MAX_ITEMS_PER_SLOT];
+ if (item != null) {
+ layer.getHud().setTimeBarTime(item.mItemRef.mDateTakenInMs);
+ }
+ }
+ }
+ }
+ }
+
+ private void touchEnded(int posX, int posY, float timeElapsedx) {
+ if (mProcessTouch == false)
+ return;
+ int maxPixelsBeforeSwitch = mCamera.mWidth / 8;
+ mCamera.mConvergenceSpeed = 2.0f;
+ GridLayer layer = mLayer;
+ if (layer.getExpandedSlot() == Shared.INVALID && !layer.feedAboutToChange()) {
+ if (mCurrentSelectedSlot != Shared.INVALID) {
+ if (layer.getState() == GridLayer.STATE_FULL_SCREEN) {
+ if (!mTouchMoved) {
+ // tap gesture for fullscreen
+ if (layer.getZoomValue() == 1.0f)
+ layer.changeFocusToSlot(mCurrentSelectedSlot, 1.0f);
+ } else if (layer.getZoomValue() == 1.0f) {
+ // we want to snap to a new slotIndex based on where the
+ // current position is
+ if (layer.inSlideShowMode()) {
+ layer.endSlideshow();
+ }
+ float deltaX = posX - mFirstTouchPosX;
+ float deltaY = posY - mFirstTouchPosY;
+ if (deltaY != 0) {
+ // it has moved vertically
+ }
+ layer.changeFocusToSlot(mCurrentSelectedSlot, 1.0f);
+ HudLayer hud = layer.getHud();
+ if (deltaX > maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
+ layer.changeFocusToPreviousSlot(1.0f);
+ } else if (deltaX < -maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
+ layer.changeFocusToNextSlot(1.0f);
+ }
+ } else {
+ // in zoomed state
+ // we do nothing for now, but we should clamp to the
+ // image bounds
+ boolean hitEdge = layer.constrainCameraForSlot(mCurrentSelectedSlot);
+ // mPrevHitEdge = false;
+ if (hitEdge && mPrevHitEdge) {
+ float deltaX = posX - mFirstTouchPosX;
+ float deltaY = posY - mFirstTouchPosY;
+ maxPixelsBeforeSwitch *= 4;
+ if (deltaY != 0) {
+ // it has moved vertically
+ }
+ mPrevHitEdge = false;
+ HudLayer hud = layer.getHud();
+ if (deltaX > maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
+ layer.changeFocusToPreviousSlot(1.0f);
+ } else if (deltaX < -maxPixelsBeforeSwitch && hud.getMode() != HudLayer.MODE_SELECT) {
+ layer.changeFocusToNextSlot(1.0f);
+ } else {
+ mPrevHitEdge = hitEdge;
+ }
+ } else {
+ mPrevHitEdge = hitEdge;
+ }
+ }
+ }
+ } else {
+ if (!layer.feedAboutToChange() && layer.getZoomValue() == 1.0f) {
+ constrainCamera(true);
+ }
+ }
+ }
+ mCurrentFocusSlot = Shared.INVALID;
+ mCurrentFocusIsPressed = false;
+ mPrevTouchPosX = posX;
+ mPrevTouchPosY = posY;
+ mProcessTouch = false;
+ }
+
+ private void constrainCamera(boolean b) {
+ Pool<Vector3f> pool = mPool;
+ GridLayer layer = mLayer;
+ Vector3f firstPosition = pool.create();
+ Vector3f lastPosition = pool.create();
+ Vector3f deltaAnchorPosition = pool.create();
+ try {
+ deltaAnchorPosition.set(layer.getDeltaAnchorPosition());
+ GridCamera camera = mCamera;
+ LayoutInterface layout = layer.getLayoutInterface();
+ GridCameraManager.getSlotPositionForSlotIndex(0, camera, layout, deltaAnchorPosition, firstPosition);
+ int lastSlotIndex = 0;
+ IndexRange completeRange = layer.getCompleteRange();
+ synchronized (completeRange) {
+ lastSlotIndex = completeRange.end;
+ }
+ GridCameraManager.getSlotPositionForSlotIndex(lastSlotIndex, camera, layout, deltaAnchorPosition, lastPosition);
+ camera.computeConstraints(true, (layer.getState() != GridLayer.STATE_FULL_SCREEN), firstPosition, lastPosition);
+ } finally {
+ pool.delete(firstPosition);
+ pool.delete(lastPosition);
+ pool.delete(deltaAnchorPosition);
+ }
+ }
+
+ public void clearSelection() {
+ mCurrentSelectedSlot = Shared.INVALID;
+ }
+
+ public void clearFocus() {
+ mCurrentFocusSlot = Shared.INVALID;
+ }
+
+ public boolean isFocusItemPressed() {
+ return mCurrentFocusIsPressed;
+ }
+
+ public void update(float timeElapsed) {
+ mDpadIgnoreTime += timeElapsed;
+ }
+
+ public void setCurrentFocusSlot(int slotId) {
+ mCurrentSelectedSlot = slotId;
+ }
+
+ public boolean onDown(MotionEvent e) {
+ // TODO Auto-generated method stub
+ return true;
+ }
+
+ public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+ if (mCurrentSelectedSlot == Shared.INVALID) {
+ mCamera.moveYTo(0);
+ mCamera.moveZTo(0);
+ mCamera.mConvergenceSpeed = 1.0f;
+ float normalizedVelocity = velocityX * mCamera.mOneByScale;
+ // mCamera.moveBy(-velocityX * mCamera.mOneByScale * 0.25f, 0, 0);
+ // constrainCamera(true);
+ IndexRange visibleRange = mLayer.getVisibleRange();
+ int numVisibleSlots = visibleRange.end - visibleRange.begin;
+ if (numVisibleSlots > 0) {
+ float fastFlingVelocity = 20.0f;
+ int slotsToSkip = (int) (numVisibleSlots * (-normalizedVelocity / fastFlingVelocity));
+ int maxSlots = numVisibleSlots;
+ if (slotsToSkip > maxSlots)
+ slotsToSkip = maxSlots;
+ if (slotsToSkip < -maxSlots)
+ slotsToSkip = -maxSlots;
+ if (Math.abs(slotsToSkip) <= 1) {
+ if (velocityX > 0)
+ slotsToSkip = -2;
+ else if (velocityX < 0)
+ slotsToSkip = 2;
+ }
+ int slotToGetTo = mLayer.getAnchorSlotIndex(GridLayer.ANCHOR_CENTER) + slotsToSkip;
+ if (slotToGetTo < 0)
+ slotToGetTo = 0;
+ int lastSlot = mLayer.getCompleteRange().end;
+ if (slotToGetTo > lastSlot)
+ slotToGetTo = lastSlot;
+ mLayer.centerCameraForSlot(slotToGetTo, 1.0f);
+ }
+ constrainCamera(true);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void onLongPress(MotionEvent e) {
+ if (mLayer.getFeed() != null && mLayer.getFeed().isSingleImageMode()) {
+ HudLayer hud = mLayer.getHud();
+ hud.getPathBar().setHidden(true);
+ hud.getMenuBar().setHidden(true);
+ if (hud.getMode() != HudLayer.MODE_NORMAL)
+ hud.setMode(HudLayer.MODE_NORMAL);
+ }
+ if (mCurrentFocusSlot != Shared.INVALID) {
+ vibrateLong();
+ GridLayer layer = mLayer;
+ if (layer.getState() == GridLayer.STATE_FULL_SCREEN) {
+ layer.deselectAll();
+ }
+ HudLayer hud = layer.getHud();
+ hud.enterSelectionMode();
+ layer.addSlotToSelectedItems(mCurrentFocusSlot, true, true);
+ }
+ }
+
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public void onShowPress(MotionEvent e) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public boolean onSingleTapUp(MotionEvent e) {
+ GridLayer layer = mLayer;
+ int posX = (int) e.getX();
+ int posY = (int) e.getY();
+ if (mCurrentSelectedSlot != Shared.INVALID) {
+ // Fullscreen mode.
+ mCamera.mConvergenceSpeed = 2.0f;
+ int slotId = mCurrentSelectedSlot;
+ if (layer.getZoomValue() == 1.0f) {
+ layer.centerCameraForSlot(slotId, 1.0f);
+ } else {
+ layer.constrainCameraForSlot(slotId);
+ }
+ DisplayItem displayItem = layer.getDisplayItemForSlotId(slotId);
+ if (displayItem != null) {
+ final MediaItem item = displayItem.mItemRef;
+ int heightBy2 = mCamera.mHeight / 2;
+ boolean posYInBounds = (Math.abs(posY - heightBy2) < 64);
+ if (posX < 32 && posYInBounds) {
+ layer.changeFocusToPreviousSlot(1.0f);
+ } else if (posX > mCamera.mWidth - 32 && posYInBounds) {
+ layer.changeFocusToNextSlot(1.0f);
+ } else if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) {
+ Utils.playVideo(mContext, item);
+ } else {
+ // We stop any slideshow.
+ HudLayer hud = layer.getHud();
+ if (layer.inSlideShowMode()) {
+ layer.endSlideshow();
+ } else {
+ hud.setAlpha(1.0f - hud.getAlpha());
+ }
+ if (hud.getMode() == HudLayer.MODE_SELECT) {
+ hud.setAlpha(1.0f);
+ }
+ }
+ }
+ } else {
+ int slotId = layer.getSlotIndexForScreenPosition(posX, posY);
+ if (slotId != Shared.INVALID) {
+ HudLayer hud = layer.getHud();
+ if (hud.getMode() == HudLayer.MODE_SELECT) {
+ layer.addSlotToSelectedItems(slotId, true, true);
+ } else {
+ boolean centerCamera = (mCurrentSelectedSlot == Shared.INVALID) ? layer.tapGesture(slotId, false) : true;
+ if (centerCamera) {
+ // We check if this item is a video or not.
+ selectSlot(slotId);
+ }
+ }
+ } else {
+ int state = layer.getState();
+ if (state != GridLayer.STATE_FULL_SCREEN && state != GridLayer.STATE_GRID_VIEW
+ && layer.getHud().getMode() != HudLayer.MODE_SELECT) {
+ slotId = layer.getMetadataSlotIndexForScreenPosition(posX, posY);
+ if (slotId != Shared.INVALID) {
+ layer.tapGesture(slotId, true);
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ private void selectSlot(int slotId) {
+ GridLayer layer = mLayer;
+ if (layer.getState() == GridLayer.STATE_GRID_VIEW) {
+ DisplayItem displayItem = layer.getDisplayItemForSlotId(slotId);
+ if (displayItem != null) {
+ final MediaItem item = displayItem.mItemRef;
+ if (layer.getPickIntent()) {
+ // we need to return this item
+ ((Gallery) mContext).getHandler().post(new Runnable() {
+ public void run() {
+ ((Gallery) mContext).launchCropperOrFinish(item);
+ }
+ });
+ return;
+ }
+ if (item.getMediaType() == MediaItem.MEDIA_TYPE_VIDEO) {
+ Utils.playVideo(mContext, item);
+ } else {
+ mCurrentSelectedSlot = slotId;
+ layer.endSlideshow();
+ layer.setState(GridLayer.STATE_FULL_SCREEN);
+ mCamera.mConvergenceSpeed = 2.0f;
+ layer.getHud().fullscreenSelectionChanged(item, mCurrentSelectedSlot + 1, layer.getCompleteRange().end + 1);
+ }
+ }
+ }
+ }
+
+ public boolean onDoubleTap(MotionEvent e) {
+ final GridLayer layer = mLayer;
+ if (layer.getState() == GridLayer.STATE_FULL_SCREEN && !mCamera.isZAnimating()) {
+ float posX = e.getX();
+ float posY = e.getY();
+ final Vector3f retVal = new Vector3f();
+ posX -= (mCamera.mWidth / 2);
+ posY -= (mCamera.mHeight / 2);
+ mCamera.convertToRelativeCameraSpace(posX, posY, 0, retVal);
+ if (layer.getZoomValue() == 1.0f) {
+ layer.setZoomValue(3f);
+ mCamera.update(0.001f);
+ mCamera.moveBy(retVal.x, retVal.y, 0);
+ layer.constrainCameraForSlot(mCurrentSelectedSlot);
+ } else {
+ layer.setZoomValue(1.0f);
+ }
+ mCamera.mConvergenceSpeed = 2.0f;
+ } else {
+ return onSingleTapConfirmed(e);
+ }
+ return true;
+ }
+
+ public boolean onDoubleTapEvent(MotionEvent e) {
+ return false;
+ }
+
+ public boolean onSingleTapConfirmed(MotionEvent e) {
+ return false;
+ }
+
+ public boolean touchPressed() {
+ return mProcessTouch;
+ }
+
+ private void vibrateShort() {
+ // As per request by Google, this line disables vibration.
+ // mView.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+ }
+
+ private void vibrateLong() {
+ // mView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
+ }
}
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 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;
-
- private static final float SLIDESHOW_TRANSITION_TIME = 3.5f;
-
- private HudLayer mHud;
- 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();
-
- // The display primitives.
- final private GridDrawables mDrawables;
- private float mSelectedAlpha = 0.0f;
- private float mTargetAlpha = 0.0f;
-
- final private GridCamera mCamera;
- final private GridCameraManager mCameraManager;
- final private GridDrawManager mDrawManager;
- final private GridInputProcessor mInputProcessor;
-
- private boolean mFeedAboutToChange;
- private boolean mPerformingLayoutChange;
- private boolean mFeedChanged;
-
- private final LayoutInterface mLayoutInterface;
- private static final LayoutInterface sfullScreenLayoutInterface = new GridLayoutInterface(1);
-
- private MediaFeed mMediaFeed;
- private boolean mInAlbum = false;
- private int mCurrentExpandedSlot;
-
- 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 final 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 boolean mSlideshowMode;
- private boolean mNoDeleteMode = false;
- private float mTimeElapsedSinceView;
- private static final MediaBucketList sBucketList = new MediaBucketList();
- private float mTimeElapsedSinceStackViewReady;
-
- 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;
-
- 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>();
- mHud = new HudLayer(context);
- mHud.setContext(context);
- mHud.setGridLayer(this);
- mHud.getPathBar().clear();
- mHud.setGridLayer(this);
- mHud.getTimeBar().setListener(this);
- mHud.getPathBar().pushLabel(R.drawable.icon_home_small, context.getResources().getString(R.string.app_name),
- new Runnable() {
- public void run() {
- if (mHud.getAlpha() == 1.0f) {
- if (!mFeedAboutToChange) {
- setState(STATE_MEDIA_SETS);
- }
- } else {
- mHud.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);
- }
-
- public HudLayer getHud() {
- return mHud;
- }
-
- public void shutdown() {
- if (mMediaFeed != null) {
- mMediaFeed.shutdown();
- }
- mContext = null;
- sBucketList.clear();
- mView = null;
- }
-
- public void stop() {
- endSlideshow();
- mBackground.clear();
- handleLowMemory();
- }
-
- @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);
- mHud.generate(view, lists);
- }
-
- @Override
- protected void onSizeChanged() {
- mHud.setSize(mWidth, mHeight);
- mHud.setAlpha(1.0f);
- mBackground.setSize(mWidth, mHeight);
- mTimeElapsedSinceTransition = 0.0f;
- if (mView != null) {
- mView.requestRender();
- }
- }
-
- public int getState() {
- return mState;
- }
-
- 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) {
- mHud.getPathBar().pushLabel(icon, set.mNoCountTitleString, new Runnable() {
- public void run() {
- if (mFeedAboutToChange) {
- return;
- }
- if (mHud.getAlpha() == 1.0f) {
- disableLocationFiltering();
- mInputProcessor.clearSelection();
- setState(STATE_GRID_VIEW);
- } else {
- mHud.setAlpha(1.0f);
- }
- }
- });
- }
- }
- if (mState == STATE_FULL_SCREEN) {
- mHud.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) {
- mHud.getPathBar().pushLabel(R.drawable.ic_fs_details, "", new Runnable() {
- public void run() {
- if (mHud.getAlpha() == 1.0f) {
- mHud.swapFullscreenLabel();
- }
- mHud.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) {
- mHud.getPathBar().popLabel();
- }
- mHud.getPathBar().popLabel();
- mInAlbum = false;
- }
- break;
- }
- mState = state;
- mHud.onGridStateChanged();
- if (performLayout && mFeedAboutToChange == false) {
- onLayout(Shared.INVALID, Shared.INVALID, oldLayout);
- }
- if (state != STATE_FULL_SCREEN) {
- mCamera.moveYTo(0);
- mCamera.moveZTo(0);
- }
- }
-
- protected void enableLocationFiltering(String label) {
- if (mLocationFilter == false) {
- mLocationFilter = true;
- mHud.getPathBar().pushLabel(R.drawable.icon_location_small, label, new Runnable() {
- public void run() {
- if (mHud.getAlpha() == 1.0f) {
- if (mState == STATE_FULL_SCREEN) {
- mInputProcessor.clearSelection();
- setState(STATE_GRID_VIEW);
- } else {
- disableLocationFiltering();
- }
- } else {
- mHud.setAlpha(1.0f);
- }
- }
- });
- }
- }
-
- protected void disableLocationFiltering() {
- if (mLocationFilter) {
- mLocationFilter = false;
- mMediaFeed.removeFilter();
- mHud.getPathBar().popLabel();
- }
- }
-
- 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 endSlideshow() {
- mSlideshowMode = false;
- if (mWakeLock != null) {
- if (mWakeLock.isHeld()) {
- mWakeLock.release();
- }
- mWakeLock = null;
- }
- mHud.setAlpha(1.0f);
- }
-
- @Override
- public void onSensorChanged(RenderView view, SensorEvent event) {
- mInputProcessor.onSensorChanged(view, event, mState);
- }
-
- public DataSource getDataSource() {
- if (mMediaFeed != null)
- return mMediaFeed.getDataSource();
- return 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();
- }
-
- public IndexRange getVisibleRange() {
- return sVisibleRange;
- }
-
- public IndexRange getBufferedVisibleRange() {
- return sBufferedVisibleRange;
- }
-
- public IndexRange getCompleteRange() {
- return sCompleteRange;
- }
-
- 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;
- }
-
- 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);
- }
-
- 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())) {
- mHud.getPathBar().setAnimatedIcons(GridDrawables.TEXTURE_SPINNER);
- } else {
- mHud.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 && !mHud.getTimeBar().isDragged()) {
- mHud.getTimeBar().setItem(anchorDisplayItem.mItemRef);
- }
- sDisplayList.update(timeElapsed);
- mInputProcessor.update(timeElapsed);
- mSelectedAlpha = FloatUtils.animate(mSelectedAlpha, mTargetAlpha, timeElapsed * 0.5f);
- if (mState == STATE_FULL_SCREEN) {
- mHud.autoHide(true);
- } else {
- mHud.autoHide(false);
- mHud.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 (!mHud.getPathBar().getCurrentLabel().equals(expandedSet.mNoCountTitleString)) {
- mHud.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);
- 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();
- }
- }
- }
-
- @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();
- mHud.clear();
- mHud.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);
- }
-
- // 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);
- }
-
- public void renderBlended(RenderView view, GL11 gl) {
- // We draw the placeholder for all visible slots.
- if (mHud != null && mDrawManager != null) {
- mDrawManager.drawBlendedComponents(view, gl, mSelectedAlpha, mState, mHud.getMode(), mTimeElapsedSinceStackViewReady,
- mTimeElapsedSinceGridViewReady, sBucketList, mMediaFeed.getWaitingForMediaScanner() || mFeedAboutToChange
- || mMediaFeed.isLoading());
- }
- }
-
- public synchronized void onLayout(int newAnchorSlotIndex, int currentAnchorSlotIndex, LayoutInterface oldLayout) {
- if (mPerformingLayoutChange || !sDeltaAnchorPosition.equals(sDeltaAnchorPositionUncommited)) {
- return;
- }
-
- 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;
- }
-
- private void forceRecomputeVisibleRange() {
- sPreviousDataRange.begin = Shared.INVALID;
- sPreviousDataRange.end = Shared.INVALID;
- if (mView != null) {
- mView.requestRender();
- }
- }
-
- // 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)
- mHud.setFeed(feed, mState, needsLayout);
- return;
- }
-
- while (mPerformingLayoutChange == true) {
- Thread.yield();
- }
- if (mState == STATE_GRID_VIEW) {
- if (mHud != null) {
- MediaSet set = feed.getCurrentSet();
- if (set != null && !mLocationFilter)
- mHud.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;
- }
- }
- }
-
- 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)
- mHud.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 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 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;
- }
-
- // 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;
- }
-
- boolean changeFocusToNextSlot(float convergence) {
- int currentSelectedSlot = mInputProcessor.getCurrentSelectedSlot();
- boolean retVal = changeFocusToSlot(currentSelectedSlot + 1, convergence);
- if (mInputProcessor.getCurrentSelectedSlot() == currentSelectedSlot) {
- endSlideshow();
- mHud.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;
- mHud.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);
- }
-
- 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 deselectOrCancelSelectMode() {
- if (sBucketList.size() == 0) {
- mHud.cancelSelection();
- } else {
- sBucketList.clear();
- updateCountOfSelectedItems();
- }
- }
-
- public void deselectAll() {
- mHud.cancelSelection();
- sBucketList.clear();
- updateCountOfSelectedItems();
- }
-
- 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?
- }
- }
-
- 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();
- }
- }
- mHud.computeBottomMenu();
- }
-
- private void updateCountOfSelectedItems() {
- mHud.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 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;
- }
-
- 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 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;
- mHud.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;
- mHud.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);
- }
-
- public void zoomInToSelectedItem() {
- mSlideshowMode = false;
- float potentialZoomValue = getFillScreenZoomValue();
- if (mZoomValue < potentialZoomValue) {
- mZoomValue = potentialZoomValue;
- } else {
- mZoomValue *= 3.0f;
- }
- if (mZoomValue > 6.0f) {
- mZoomValue = 6.0f;
- }
- mHud.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;
- }
- mHud.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 cropSelectedItem() {
-
- }
-
- @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;
- }
-
- public boolean inSlideShowMode() {
- return mSlideshowMode;
- }
-
- public boolean noDeleteMode() {
- return mNoDeleteMode || (mMediaFeed != null && mMediaFeed.isSingleImageMode());
- }
-
- public float getZoomValue() {
- return mZoomValue;
- }
-
- public boolean feedAboutToChange() {
- return mFeedAboutToChange;
- }
-
- public boolean isInAlbumMode() {
- return mInAlbum;
- }
-
- public Vector3f getDeltaAnchorPosition() {
- return sDeltaAnchorPosition;
- }
-
- public int getExpandedSlot() {
- return mCurrentExpandedSlot;
- }
-
- public GridLayoutInterface getLayoutInterface() {
- return (GridLayoutInterface) mLayoutInterface;
- }
-
- public void setZoomValue(float f) {
- mZoomValue = f;
- centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
- }
-
- public void setPickIntent(boolean b) {
- mPickIntent = b;
- mHud.getPathBar().popLabel();
- mHud.getPathBar().pushLabel(R.drawable.icon_location_small, mContext.getResources().getString(R.string.pick),
- new Runnable() {
- public void run() {
- if (mHud.getAlpha() == 1.0f) {
- if (!mFeedAboutToChange) {
- setState(STATE_MEDIA_SETS);
- }
- } else {
- mHud.setAlpha(1.0f);
- }
- }
- });
- }
-
- 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 (mHud.getPathBar().getNumLevels() == 1) {
- mHud.getPathBar().pushLabel(R.drawable.icon_folder_small, setName, new Runnable() {
- public void run() {
- if (mFeedAboutToChange) {
- return;
- }
- if (mHud.getAlpha() == 1.0f) {
- disableLocationFiltering();
- if (mInputProcessor != null)
- mInputProcessor.clearSelection();
- setState(STATE_GRID_VIEW);
- } else {
- mHud.setAlpha(1.0f);
- }
- }
- });
- }
- }
- }
-
- public boolean getViewIntent() {
- return mViewIntent;
- }
-
- public void setSingleImage(boolean noDeleteMode) {
- mNoDeleteMode = noDeleteMode;
- mInputProcessor.setCurrentSelectedSlot(0);
- }
-
- public MediaFeed getFeed() {
- return mMediaFeed;
- }
-
- public void markDirty(int numFrames) {
- mFramesDirty = numFrames;
- }
-
- public void focusItem(String contentUri) {
- mRequestFocusContentUri = contentUri;
- mMediaFeed.updateListener(false);
- }
+ 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 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 HudLayer mHud;
+ 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();
+
+ // The display primitives.
+ final private GridDrawables mDrawables;
+ private float mSelectedAlpha = 0.0f;
+ private float mTargetAlpha = 0.0f;
+
+ final private GridCamera mCamera;
+ final private GridCameraManager mCameraManager;
+ final private GridDrawManager mDrawManager;
+ final private GridInputProcessor mInputProcessor;
+
+ private boolean mFeedAboutToChange;
+ private boolean mPerformingLayoutChange;
+ private boolean mFeedChanged;
+
+ private final LayoutInterface mLayoutInterface;
+ private static final LayoutInterface sfullScreenLayoutInterface = new GridLayoutInterface(1);
+
+ private MediaFeed mMediaFeed;
+ private boolean mInAlbum = false;
+ private int mCurrentExpandedSlot;
+
+ 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 final 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 boolean mSlideshowMode;
+ private boolean mNoDeleteMode = false;
+ private float mTimeElapsedSinceView;
+ private static final MediaBucketList sSelectedBucketList = new MediaBucketList();
+ private static final MediaBucketList sMarkedBucketList = new MediaBucketList();
+ private float mTimeElapsedSinceStackViewReady;
+
+ 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;
+
+ 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);
+ sSelectedBucketList.clear();
+
+ sVisibleItems = new ArrayList<MediaItem>();
+ mHud = new HudLayer(context);
+ mHud.setContext(context);
+ mHud.setGridLayer(this);
+ mHud.getPathBar().clear();
+ mHud.setGridLayer(this);
+ mHud.getTimeBar().setListener(this);
+ mHud.getPathBar().pushLabel(R.drawable.icon_home_small, context.getResources().getString(R.string.app_name),
+ new Runnable() {
+ public void run() {
+ if (mHud.getAlpha() == 1.0f) {
+ if (!mFeedAboutToChange) {
+ setState(STATE_MEDIA_SETS);
+ }
+ } else {
+ mHud.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);
+ }
+
+ public HudLayer getHud() {
+ return mHud;
+ }
+
+ public void shutdown() {
+ if (mMediaFeed != null) {
+ mMediaFeed.shutdown();
+ }
+ mContext = null;
+ sSelectedBucketList.clear();
+ mView = null;
+ }
+
+ public void stop() {
+ endSlideshow();
+ mBackground.clear();
+ handleLowMemory();
+ }
+
+ @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);
+ mHud.generate(view, lists);
+ }
+
+ @Override
+ protected void onSizeChanged() {
+ mHud.setSize(mWidth, mHeight);
+ mHud.setAlpha(1.0f);
+ mBackground.setSize(mWidth, mHeight);
+ mTimeElapsedSinceTransition = 0.0f;
+ if (mView != null) {
+ mView.requestRender();
+ }
+ }
+
+ public int getState() {
+ return mState;
+ }
+
+ 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) {
+ mHud.getPathBar().pushLabel(icon, set.mNoCountTitleString, new Runnable() {
+ public void run() {
+ if (mFeedAboutToChange) {
+ return;
+ }
+ if (mHud.getAlpha() == 1.0f) {
+ disableLocationFiltering();
+ mInputProcessor.clearSelection();
+ setState(STATE_GRID_VIEW);
+ } else {
+ mHud.setAlpha(1.0f);
+ }
+ }
+ });
+ }
+ }
+ if (mState == STATE_FULL_SCREEN) {
+ mHud.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) {
+ mHud.getPathBar().pushLabel(R.drawable.ic_fs_details, "", new Runnable() {
+ public void run() {
+ if (mHud.getAlpha() == 1.0f) {
+ mHud.swapFullscreenLabel();
+ }
+ mHud.setAlpha(1.0f);
+ }
+ });
+ }
+ break;
+ case STATE_MEDIA_SETS:
+ mTimeElapsedSinceStackViewReady = 0.0f;
+ if (feed != null && feedUnchanged == false) {
+ feed.restorePreviousClusteringState();
+ sMarkedBucketList.clear();
+ 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) {
+ mHud.getPathBar().popLabel();
+ }
+ mHud.getPathBar().popLabel();
+ mInAlbum = false;
+ }
+ break;
+ }
+ mState = state;
+ mHud.onGridStateChanged();
+ if (performLayout && mFeedAboutToChange == false) {
+ onLayout(Shared.INVALID, Shared.INVALID, oldLayout);
+ }
+ if (state != STATE_FULL_SCREEN) {
+ mCamera.moveYTo(0);
+ mCamera.moveZTo(0);
+ }
+ }
+
+ protected void enableLocationFiltering(String label) {
+ if (mLocationFilter == false) {
+ mLocationFilter = true;
+ mHud.getPathBar().pushLabel(R.drawable.icon_location_small, label, new Runnable() {
+ public void run() {
+ if (mHud.getAlpha() == 1.0f) {
+ if (mState == STATE_FULL_SCREEN) {
+ mInputProcessor.clearSelection();
+ setState(STATE_GRID_VIEW);
+ } else {
+ disableLocationFiltering();
+ }
+ } else {
+ mHud.setAlpha(1.0f);
+ }
+ }
+ });
+ }
+ }
+
+ protected void disableLocationFiltering() {
+ if (mLocationFilter) {
+ mLocationFilter = false;
+ mMediaFeed.removeFilter();
+ mHud.getPathBar().popLabel();
+ }
+ }
+
+ 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 endSlideshow() {
+ mSlideshowMode = false;
+ if (mWakeLock != null) {
+ if (mWakeLock.isHeld()) {
+ mWakeLock.release();
+ }
+ mWakeLock = null;
+ }
+ mHud.setAlpha(1.0f);
+ }
+
+ @Override
+ public void onSensorChanged(RenderView view, SensorEvent event) {
+ mInputProcessor.onSensorChanged(view, event, mState);
+ }
+
+ public DataSource getDataSource() {
+ if (mMediaFeed != null)
+ return mMediaFeed.getDataSource();
+ return 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();
+ }
+
+ public IndexRange getVisibleRange() {
+ return sVisibleRange;
+ }
+
+ public IndexRange getBufferedVisibleRange() {
+ return sBufferedVisibleRange;
+ }
+
+ public IndexRange getCompleteRange() {
+ return sCompleteRange;
+ }
+
+ 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;
+ }
+
+ 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);
+ }
+
+ 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())) {
+ mHud.getPathBar().setAnimatedIcons(GridDrawables.TEXTURE_SPINNER);
+ } else {
+ mHud.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 && !mHud.getTimeBar().isDragged()) {
+ mHud.getTimeBar().setItem(anchorDisplayItem.mItemRef);
+ }
+ sDisplayList.update(timeElapsed);
+ mInputProcessor.update(timeElapsed);
+ mSelectedAlpha = FloatUtils.animate(mSelectedAlpha, mTargetAlpha, timeElapsed * 0.5f);
+ if (mState == STATE_FULL_SCREEN) {
+ mHud.autoHide(true);
+ } else {
+ mHud.autoHide(false);
+ mHud.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 (!mHud.getPathBar().getCurrentLabel().equals(expandedSet.mNoCountTitleString)) {
+ mHud.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);
+ 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();
+ }
+ }
+ }
+
+ @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();
+ mHud.clear();
+ mHud.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);
+ }
+
+ // 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);
+ }
+
+ public void renderBlended(RenderView view, GL11 gl) {
+ // We draw the placeholder for all visible slots.
+ if (mHud != null && mDrawManager != null) {
+ mDrawManager.drawBlendedComponents(view, gl, mSelectedAlpha, mState, mHud.getMode(), mTimeElapsedSinceStackViewReady,
+ mTimeElapsedSinceGridViewReady, sSelectedBucketList, sMarkedBucketList, mMediaFeed.getWaitingForMediaScanner()
+ || mFeedAboutToChange || mMediaFeed.isLoading());
+ }
+ }
+
+ public synchronized void onLayout(int newAnchorSlotIndex, int currentAnchorSlotIndex, LayoutInterface oldLayout) {
+ if (mPerformingLayoutChange || !sDeltaAnchorPosition.equals(sDeltaAnchorPositionUncommited)) {
+ return;
+ }
+
+ 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;
+ }
+
+ private void forceRecomputeVisibleRange() {
+ sPreviousDataRange.begin = Shared.INVALID;
+ sPreviousDataRange.end = Shared.INVALID;
+ if (mView != null) {
+ mView.requestRender();
+ }
+ }
+
+ // 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)
+ mHud.setFeed(feed, mState, needsLayout);
+ return;
+ }
+
+ while (mPerformingLayoutChange == true) {
+ Thread.yield();
+ }
+ if (mState == STATE_GRID_VIEW) {
+ if (mHud != null) {
+ MediaSet set = feed.getCurrentSet();
+ if (set != null && !mLocationFilter)
+ mHud.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;
+ }
+ }
+ }
+
+ 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)
+ mHud.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 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 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;
+ }
+
+ // 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;
+ }
+
+ boolean changeFocusToNextSlot(float convergence) {
+ int currentSelectedSlot = mInputProcessor.getCurrentSelectedSlot();
+ boolean retVal = changeFocusToSlot(currentSelectedSlot + 1, convergence);
+ if (mInputProcessor.getCurrentSelectedSlot() == currentSelectedSlot) {
+ endSlideshow();
+ mHud.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;
+ mHud.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);
+ }
+
+ public ArrayList<MediaBucket> getSelectedBuckets() {
+ return sSelectedBucketList.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 deselectOrCancelSelectMode() {
+ if (sSelectedBucketList.size() == 0) {
+ mHud.cancelSelection();
+ } else {
+ sSelectedBucketList.clear();
+ updateCountOfSelectedItems();
+ }
+ }
+
+ public void deselectAll() {
+ mHud.cancelSelection();
+ sSelectedBucketList.clear();
+ updateCountOfSelectedItems();
+ }
+
+ 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?
+ }
+ }
+
+ void addSlotToSelectedItems(int slotId, boolean removeIfAlreadyAdded, boolean updateCount) {
+ if (mFeedAboutToChange == false) {
+ MediaFeed feed = mMediaFeed;
+ sSelectedBucketList.add(slotId, feed, removeIfAlreadyAdded);
+ if (updateCount) {
+ updateCountOfSelectedItems();
+ if (sSelectedBucketList.size() == 0)
+ deselectAll();
+ }
+ }
+ mHud.computeBottomMenu();
+ }
+
+ private void updateCountOfSelectedItems() {
+ mHud.updateNumItemsSelected(sSelectedBucketList.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 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;
+ }
+
+ 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;
+ sMarkedBucketList.add(slotIndex, feed, false);
+ 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 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;
+ mHud.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;
+ mHud.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);
+ }
+
+ public void zoomInToSelectedItem() {
+ mSlideshowMode = false;
+ float potentialZoomValue = getFillScreenZoomValue();
+ if (mZoomValue < potentialZoomValue) {
+ mZoomValue = potentialZoomValue;
+ } else {
+ mZoomValue *= 3.0f;
+ }
+ if (mZoomValue > 6.0f) {
+ mZoomValue = 6.0f;
+ }
+ mHud.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;
+ }
+ mHud.setAlpha(1.0f);
+ centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
+ }
+
+ public void rotateSelectedItems(float f) {
+ MediaBucketList bucketList = sSelectedBucketList;
+ 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() {
+
+ }
+
+ @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;
+ }
+
+ public boolean inSlideShowMode() {
+ return mSlideshowMode;
+ }
+
+ public boolean noDeleteMode() {
+ return mNoDeleteMode || (mMediaFeed != null && mMediaFeed.isSingleImageMode());
+ }
+
+ public float getZoomValue() {
+ return mZoomValue;
+ }
+
+ public boolean feedAboutToChange() {
+ return mFeedAboutToChange;
+ }
+
+ public boolean isInAlbumMode() {
+ return mInAlbum;
+ }
+
+ public Vector3f getDeltaAnchorPosition() {
+ return sDeltaAnchorPosition;
+ }
+
+ public int getExpandedSlot() {
+ return mCurrentExpandedSlot;
+ }
+
+ public GridLayoutInterface getLayoutInterface() {
+ return (GridLayoutInterface) mLayoutInterface;
+ }
+
+ public void setZoomValue(float f) {
+ mZoomValue = f;
+ centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
+ }
+
+ public void setPickIntent(boolean b) {
+ mPickIntent = b;
+ mHud.getPathBar().popLabel();
+ mHud.getPathBar().pushLabel(R.drawable.icon_location_small, mContext.getResources().getString(R.string.pick),
+ new Runnable() {
+ public void run() {
+ if (mHud.getAlpha() == 1.0f) {
+ if (!mFeedAboutToChange) {
+ setState(STATE_MEDIA_SETS);
+ }
+ } else {
+ mHud.setAlpha(1.0f);
+ }
+ }
+ });
+ }
+
+ 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 (mHud.getPathBar().getNumLevels() == 1) {
+ mHud.getPathBar().pushLabel(R.drawable.icon_folder_small, setName, new Runnable() {
+ public void run() {
+ if (mFeedAboutToChange) {
+ return;
+ }
+ if (mHud.getAlpha() == 1.0f) {
+ disableLocationFiltering();
+ if (mInputProcessor != null)
+ mInputProcessor.clearSelection();
+ setState(STATE_GRID_VIEW);
+ } else {
+ mHud.setAlpha(1.0f);
+ }
+ }
+ });
+ }
+ }
+ }
+
+ public boolean getViewIntent() {
+ return mViewIntent;
+ }
+
+ public void setSingleImage(boolean noDeleteMode) {
+ mNoDeleteMode = noDeleteMode;
+ mInputProcessor.setCurrentSelectedSlot(0);
+ }
+
+ public MediaFeed getFeed() {
+ return mMediaFeed;
+ }
+
+ public void markDirty(int numFrames) {
+ mFramesDirty = numFrames;
+ }
+
+ public void focusItem(String contentUri) {
+ mRequestFocusContentUri = contentUri;
+ mMediaFeed.updateListener(false);
+ }
}
public final class GridLayoutInterface extends LayoutInterface {
GridLayoutInterface(int numRows) {
mNumRows = numRows;
- mSpacingX = (int)(20 * Gallery.PIXEL_DENSITY);
- mSpacingY = (int)(40 * Gallery.PIXEL_DENSITY);
+ mSpacingX = (int) (20 * Gallery.PIXEL_DENSITY);
+ mSpacingY = (int) (40 * Gallery.PIXEL_DENSITY);
}
public void getPositionForSlotIndex(int slotIndex, int itemWidth, int itemHeight, Vector3f outPosition) {
import javax.microedition.khronos.opengles.GL11;
/**
- * A 2D rectangular mesh. Can be drawn textured or untextured. This version is modified from the original Grid.java (found in the
- * SpriteText package in the APIDemos Android sample) to support hardware vertex buffers.
+ * A 2D rectangular mesh. Can be drawn textured or untextured. This version is
+ * modified from the original Grid.java (found in the SpriteText package in the
+ * APIDemos Android sample) to support hardware vertex buffers.
*/
final class GridQuad {
public static GridQuad createGridQuad(float width, float height, float xOffset, float yOffset, float uExtents, float vExtents,
boolean generateOrientedQuads) {
- //generateOrientedQuads = false;
+ // generateOrientedQuads = false;
GridQuad grid = new GridQuad(generateOrientedQuads);
grid.mWidth = width;
grid.mHeight = height;
public void resizeQuad(float viewAspect, float u, float v, float imageWidth, float imageHeight) {
// given the u,v; we know the aspect ratio of the image
- // we have to change one of the co-ords depending upon the image and viewport aspect ratio
+ // we have to change one of the co-ords depending upon the image and
+ // viewport aspect ratio
mU = u;
mV = v;
float imageAspect = imageWidth / imageHeight;
}
/**
- * When the OpenGL ES device is lost, GL handles become invalidated. In that case, we just want to "forget" the old handles
- * (without explicitly deleting them) and make new ones.
+ * When the OpenGL ES device is lost, GL handles become invalidated. In that
+ * case, we just want to "forget" the old handles (without explicitly
+ * deleting them) and make new ones.
*/
public void forgetHardwareBuffers() {
mVertBufferIndex = 0;
}
/**
- * Allocates hardware buffers on the graphics card and fills them with data if a buffer has not already been previously
- * allocated. Note that this function uses the GL_OES_vertex_buffer_object extension, which is not guaranteed to be supported on
- * every device.
+ * Allocates hardware buffers on the graphics card and fills them with data
+ * if a buffer has not already been previously allocated. Note that this
+ * function uses the GL_OES_vertex_buffer_object extension, which is not
+ * guaranteed to be supported on every device.
*
* @param gl
* A pointer to the OpenGL ES context.
private int mW;
private int mH;
-
+
// This has 8 quads, 16 vertices, 22 triangles (for tristrip).
- // We have more triangles because we have to make degenerate triangles to use tri-strips
+ // We have more triangles because we have to make degenerate triangles to
+ // use tri-strips
public static final int INDEX_COUNT = 25;
private int mVertBufferIndex;
private int mIndexBufferIndex;
/*
* Initialize triangle list mesh.
*
- * [0]---[1]---------[2]---[3] ... | / | / | / | [4]---[5]---------[6]---[7] | / | | /| | / | | / | | / | | / |
- * [8]---[9]---------[10]---[11] | / | \ | \ | [12]--[13]--------[14]---[15]
+ * [0]---[1]---------[2]---[3] ... | / | / | / |
+ * [4]---[5]---------[6]---[7] | / | | /| | / | | / | | / | | / |
+ * [8]---[9]---------[10]---[11] | / | \ | \ |
+ * [12]--[13]--------[14]---[15]
*/
CharBuffer buffer = mIndexBuffer;
buffer.put(0, (char) 0);
int texIndex = index * 2;
mTexCoordBuffer.put(texIndex, u);
mTexCoordBuffer.put(texIndex + 1, v);
-
+
int secTexIndex = index * 2;
mSecTexCoordBuffer.put(secTexIndex, u);
mSecTexCoordBuffer.put(secTexIndex + 1, v);
}
/**
- * When the OpenGL ES device is lost, GL handles become invalidated. In that case, we just want to "forget" the old handles
- * (without explicitly deleting them) and make new ones.
+ * When the OpenGL ES device is lost, GL handles become invalidated. In that
+ * case, we just want to "forget" the old handles (without explicitly
+ * deleting them) and make new ones.
*/
public void forgetHardwareBuffers() {
mVertBufferIndex = 0;
buffer[0] = mTextureCoordBufferIndex;
gl11.glDeleteBuffers(1, buffer, 0);
-
+
buffer[0] = mSecTextureCoordBufferIndex;
gl11.glDeleteBuffers(1, buffer, 0);
}
/**
- * Allocates hardware buffers on the graphics card and fills them with data if a buffer has not already been previously
- * allocated. Note that this function uses the GL_OES_vertex_buffer_object extension, which is not guaranteed to be supported on
- * every device.
+ * Allocates hardware buffers on the graphics card and fills them with data
+ * if a buffer has not already been previously allocated. Note that this
+ * function uses the GL_OES_vertex_buffer_object extension, which is not
+ * guaranteed to be supported on every device.
*
* @param gl
* A pointer to the OpenGL ES context.
final int texCoordSize = mTexCoordBuffer.capacity() * 4;
mTexCoordBuffer.position(0);
gl11.glBufferData(GL11.GL_ARRAY_BUFFER, texCoordSize, mTexCoordBuffer, GL11.GL_STATIC_DRAW);
-
+
// Allocate and fill the secondary texture coordinate buffer.
gl11.glGenBuffers(1, buffer, 0);
mSecTextureCoordBufferIndex = buffer[0];
import javax.microedition.khronos.opengles.GL11;
/**
- * A 2D rectangular mesh. Can be drawn textured or untextured. This version is modified from the original Grid.java (found in the
- * SpriteText package in the APIDemos Android sample) to support hardware vertex buffers.
+ * A 2D rectangular mesh. Can be drawn textured or untextured. This version is
+ * modified from the original Grid.java (found in the SpriteText package in the
+ * APIDemos Android sample) to support hardware vertex buffers.
*/
final class GridQuadMesh {
private FloatBuffer mVertexBuffer;
}
/**
- * When the OpenGL ES device is lost, GL handles become invalidated. In that case, we just want to "forget" the old handles
- * (without explicitly deleting them) and make new ones.
+ * When the OpenGL ES device is lost, GL handles become invalidated. In that
+ * case, we just want to "forget" the old handles (without explicitly
+ * deleting them) and make new ones.
*/
public void forgetHardwareBuffers() {
mVertBufferIndex = 0;
}
/**
- * Allocates hardware buffers on the graphics card and fills them with data if a buffer has not already been previously
- * allocated. Note that this function uses the GL_OES_vertex_buffer_object extension, which is not guaranteed to be supported on
- * every device.
+ * Allocates hardware buffers on the graphics card and fills them with data
+ * if a buffer has not already been previously allocated. Note that this
+ * function uses the GL_OES_vertex_buffer_object extension, which is not
+ * guaranteed to be supported on every device.
*
* @param gl
* A pointer to the OpenGL ES context.
* limitations under the License.
*/
-
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
@SuppressWarnings("unused")
private static final String TAG = "HighlightView";
- View mContext; // The View displaying the image.
+ View mContext; // The View displaying the image.
- public static final int GROW_NONE = (1 << 0);
- public static final int GROW_LEFT_EDGE = (1 << 1);
- public static final int GROW_RIGHT_EDGE = (1 << 2);
- public static final int GROW_TOP_EDGE = (1 << 3);
+ public static final int GROW_NONE = (1 << 0);
+ public static final int GROW_LEFT_EDGE = (1 << 1);
+ public static final int GROW_RIGHT_EDGE = (1 << 2);
+ public static final int GROW_TOP_EDGE = (1 << 3);
public static final int GROW_BOTTOM_EDGE = (1 << 4);
- public static final int MOVE = (1 << 5);
+ public static final int MOVE = (1 << 5);
public HighlightView(View ctx) {
mContext = ctx;
private void init() {
android.content.res.Resources resources = mContext.getResources();
- mResizeDrawableWidth =
- resources.getDrawable(R.drawable.camera_crop_width);
- mResizeDrawableHeight =
- resources.getDrawable(R.drawable.camera_crop_height);
- mResizeDrawableDiagonal =
- resources.getDrawable(R.drawable.indicator_autocrop);
+ mResizeDrawableWidth = resources.getDrawable(R.drawable.camera_crop_width);
+ mResizeDrawableHeight = resources.getDrawable(R.drawable.camera_crop_height);
+ mResizeDrawableDiagonal = resources.getDrawable(R.drawable.indicator_autocrop);
}
boolean mIsFocused;
Rect viewDrawingRect = new Rect();
mContext.getDrawingRect(viewDrawingRect);
if (mCircle) {
- float width = mDrawRect.width();
+ float width = mDrawRect.width();
float height = mDrawRect.height();
- path.addCircle(mDrawRect.left + (width / 2),
- mDrawRect.top + (height / 2),
- width / 2,
- Path.Direction.CW);
+ path.addCircle(mDrawRect.left + (width / 2), mDrawRect.top + (height / 2), width / 2, Path.Direction.CW);
mOutlinePaint.setColor(0xFFEF04D6);
} else {
path.addRect(new RectF(mDrawRect), Path.Direction.CW);
mOutlinePaint.setColor(0xFFFF8A00);
}
canvas.clipPath(path, Region.Op.DIFFERENCE);
- canvas.drawRect(viewDrawingRect,
- hasFocus() ? mFocusPaint : mNoFocusPaint);
+ canvas.drawRect(viewDrawingRect, hasFocus() ? mFocusPaint : mNoFocusPaint);
canvas.restore();
canvas.drawPath(path, mOutlinePaint);
if (mMode == ModifyMode.Grow) {
if (mCircle) {
- int width = mResizeDrawableDiagonal.getIntrinsicWidth();
+ int width = mResizeDrawableDiagonal.getIntrinsicWidth();
int height = mResizeDrawableDiagonal.getIntrinsicHeight();
- int d = (int) Math.round(Math.cos(/*45deg*/Math.PI / 4D)
- * (mDrawRect.width() / 2D));
- int x = mDrawRect.left
- + (mDrawRect.width() / 2) + d - width / 2;
- int y = mDrawRect.top
- + (mDrawRect.height() / 2) - d - height / 2;
- mResizeDrawableDiagonal.setBounds(x, y,
- x + mResizeDrawableDiagonal.getIntrinsicWidth(),
- y + mResizeDrawableDiagonal.getIntrinsicHeight());
+ int d = (int) Math.round(Math.cos(/* 45deg */Math.PI / 4D) * (mDrawRect.width() / 2D));
+ int x = mDrawRect.left + (mDrawRect.width() / 2) + d - width / 2;
+ int y = mDrawRect.top + (mDrawRect.height() / 2) - d - height / 2;
+ mResizeDrawableDiagonal.setBounds(x, y, x + mResizeDrawableDiagonal.getIntrinsicWidth(), y
+ + mResizeDrawableDiagonal.getIntrinsicHeight());
mResizeDrawableDiagonal.draw(canvas);
} else {
- int left = mDrawRect.left + 1;
- int right = mDrawRect.right + 1;
- int top = mDrawRect.top + 4;
- int bottom = mDrawRect.bottom + 3;
-
- int widthWidth =
- mResizeDrawableWidth.getIntrinsicWidth() / 2;
- int widthHeight =
- mResizeDrawableWidth.getIntrinsicHeight() / 2;
- int heightHeight =
- mResizeDrawableHeight.getIntrinsicHeight() / 2;
- int heightWidth =
- mResizeDrawableHeight.getIntrinsicWidth() / 2;
-
- int xMiddle = mDrawRect.left
- + ((mDrawRect.right - mDrawRect.left) / 2);
- int yMiddle = mDrawRect.top
- + ((mDrawRect.bottom - mDrawRect.top) / 2);
-
- mResizeDrawableWidth.setBounds(left - widthWidth,
- yMiddle - widthHeight,
- left + widthWidth,
- yMiddle + widthHeight);
+ int left = mDrawRect.left + 1;
+ int right = mDrawRect.right + 1;
+ int top = mDrawRect.top + 4;
+ int bottom = mDrawRect.bottom + 3;
+
+ int widthWidth = mResizeDrawableWidth.getIntrinsicWidth() / 2;
+ int widthHeight = mResizeDrawableWidth.getIntrinsicHeight() / 2;
+ int heightHeight = mResizeDrawableHeight.getIntrinsicHeight() / 2;
+ int heightWidth = mResizeDrawableHeight.getIntrinsicWidth() / 2;
+
+ int xMiddle = mDrawRect.left + ((mDrawRect.right - mDrawRect.left) / 2);
+ int yMiddle = mDrawRect.top + ((mDrawRect.bottom - mDrawRect.top) / 2);
+
+ mResizeDrawableWidth.setBounds(left - widthWidth, yMiddle - widthHeight, left + widthWidth, yMiddle
+ + widthHeight);
mResizeDrawableWidth.draw(canvas);
- mResizeDrawableWidth.setBounds(right - widthWidth,
- yMiddle - widthHeight,
- right + widthWidth,
- yMiddle + widthHeight);
+ mResizeDrawableWidth.setBounds(right - widthWidth, yMiddle - widthHeight, right + widthWidth, yMiddle
+ + widthHeight);
mResizeDrawableWidth.draw(canvas);
- mResizeDrawableHeight.setBounds(xMiddle - heightWidth,
- top - heightHeight,
- xMiddle + heightWidth,
- top + heightHeight);
+ mResizeDrawableHeight.setBounds(xMiddle - heightWidth, top - heightHeight, xMiddle + heightWidth, top
+ + heightHeight);
mResizeDrawableHeight.draw(canvas);
- mResizeDrawableHeight.setBounds(xMiddle - heightWidth,
- bottom - heightHeight,
- xMiddle + heightWidth,
- bottom + heightHeight);
+ mResizeDrawableHeight.setBounds(xMiddle - heightWidth, bottom - heightHeight, xMiddle + heightWidth, bottom
+ + heightHeight);
mResizeDrawableHeight.draw(canvas);
}
}
if (mCircle) {
float distX = x - r.centerX();
float distY = y - r.centerY();
- int distanceFromCenter =
- (int) Math.sqrt(distX * distX + distY * distY);
- int radius = mDrawRect.width() / 2;
+ int distanceFromCenter = (int) Math.sqrt(distX * distX + distY * distY);
+ int radius = mDrawRect.width() / 2;
int delta = distanceFromCenter - radius;
if (Math.abs(delta) <= hysteresis) {
if (Math.abs(distY) > Math.abs(distX)) {
} else {
// verticalCheck makes sure the position is between the top and
// the bottom edge (with some tolerance). Similar for horizCheck.
- boolean verticalCheck = (y >= r.top - hysteresis)
- && (y < r.bottom + hysteresis);
- boolean horizCheck = (x >= r.left - hysteresis)
- && (x < r.right + hysteresis);
+ boolean verticalCheck = (y >= r.top - hysteresis) && (y < r.bottom + hysteresis);
+ boolean horizCheck = (x >= r.left - hysteresis) && (x < r.right + hysteresis);
// Check whether the position is near some edge(s).
- if ((Math.abs(r.left - x) < hysteresis) && verticalCheck) {
+ if ((Math.abs(r.left - x) < hysteresis) && verticalCheck) {
retval |= GROW_LEFT_EDGE;
}
- if ((Math.abs(r.right - x) < hysteresis) && verticalCheck) {
+ if ((Math.abs(r.right - x) < hysteresis) && verticalCheck) {
retval |= GROW_RIGHT_EDGE;
}
- if ((Math.abs(r.top - y) < hysteresis) && horizCheck) {
+ if ((Math.abs(r.top - y) < hysteresis) && horizCheck) {
retval |= GROW_TOP_EDGE;
}
- if ((Math.abs(r.bottom - y) < hysteresis) && horizCheck) {
+ if ((Math.abs(r.bottom - y) < hysteresis) && horizCheck) {
retval |= GROW_BOTTOM_EDGE;
}
return;
} else if (edge == MOVE) {
// Convert to image space before sending to moveBy().
- moveBy(dx * (mCropRect.width() / r.width()),
- dy * (mCropRect.height() / r.height()));
+ moveBy(dx * (mCropRect.width() / r.width()), dy * (mCropRect.height() / r.height()));
} else {
if (((GROW_LEFT_EDGE | GROW_RIGHT_EDGE) & edge) == 0) {
dx = 0;
// Convert to image space before sending to growBy().
float xDelta = dx * (mCropRect.width() / r.width());
float yDelta = dy * (mCropRect.height() / r.height());
- growBy((((edge & GROW_LEFT_EDGE) != 0) ? -1 : 1) * xDelta,
- (((edge & GROW_TOP_EDGE) != 0) ? -1 : 1) * yDelta);
+ growBy((((edge & GROW_LEFT_EDGE) != 0) ? -1 : 1) * xDelta, (((edge & GROW_TOP_EDGE) != 0) ? -1 : 1) * yDelta);
}
}
mCropRect.offset(dx, dy);
// Put the cropping rectangle inside image rectangle.
- mCropRect.offset(
- Math.max(0, mImageRect.left - mCropRect.left),
- Math.max(0, mImageRect.top - mCropRect.top));
+ mCropRect.offset(Math.max(0, mImageRect.left - mCropRect.left), Math.max(0, mImageRect.top - mCropRect.top));
- mCropRect.offset(
- Math.min(0, mImageRect.right - mCropRect.right),
- Math.min(0, mImageRect.bottom - mCropRect.bottom));
+ mCropRect.offset(Math.min(0, mImageRect.right - mCropRect.right), Math.min(0, mImageRect.bottom - mCropRect.bottom));
mDrawRect = computeLayout();
invalRect.union(mDrawRect);
if (r.width() < widthCap) {
r.inset(-(widthCap - r.width()) / 2F, 0F);
}
- float heightCap = mMaintainAspectRatio
- ? (widthCap / mInitialAspectRatio)
- : widthCap;
+ float heightCap = mMaintainAspectRatio ? (widthCap / mInitialAspectRatio) : widthCap;
if (r.height() < heightCap) {
r.inset(0F, -(heightCap - r.height()) / 2F);
}
// Returns the cropping rectangle in image space.
public Rect getCropRect() {
- return new Rect((int) mCropRect.left, (int) mCropRect.top,
- (int) mCropRect.right, (int) mCropRect.bottom);
+ return new Rect((int) mCropRect.left, (int) mCropRect.top, (int) mCropRect.right, (int) mCropRect.bottom);
}
// Maps the cropping rectangle from image space to screen space.
private Rect computeLayout() {
- RectF r = new RectF(mCropRect.left, mCropRect.top,
- mCropRect.right, mCropRect.bottom);
+ RectF r = new RectF(mCropRect.left, mCropRect.top, mCropRect.right, mCropRect.bottom);
mMatrix.mapRect(r);
- return new Rect(Math.round(r.left), Math.round(r.top),
- Math.round(r.right), Math.round(r.bottom));
+ return new Rect(Math.round(r.left), Math.round(r.top), Math.round(r.right), Math.round(r.bottom));
}
public void invalidate() {
mDrawRect = computeLayout();
}
- public void setup(Matrix m, Rect imageRect, RectF cropRect, boolean circle,
- boolean maintainAspectRatio) {
+ public void setup(Matrix m, Rect imageRect, RectF cropRect, boolean circle, boolean maintainAspectRatio) {
if (circle) {
maintainAspectRatio = true;
}
init();
}
- enum ModifyMode { None, Move, Grow }
+ enum ModifyMode {
+ None, Move, Grow
+ }
private ModifyMode mMode = ModifyMode.None;
- Rect mDrawRect; // in screen space
- private RectF mImageRect; // in image space
- RectF mCropRect; // in image space
+ Rect mDrawRect; // in screen space
+ private RectF mImageRect; // in image space
+ RectF mCropRect; // in image space
Matrix mMatrix;
private boolean mMaintainAspectRatio = false;
private final Paint mNoFocusPaint = new Paint();
private final Paint mOutlinePaint = new Paint();
}
-
MenuBar.Menu deleteMenu = new MenuBar.Menu.Builder(context.getResources().getString(R.string.delete)).icon(
R.drawable.icon_delete).options(deleteOptions).build();
- MenuBar.Menu moreMenu = new MenuBar.Menu.Builder(context.getResources().getString(R.string.more)).icon(
- R.drawable.icon_more).onSelect(new Runnable() {
- public void run() {
- buildMoreOptions();
- }
- }).build();
+ MenuBar.Menu moreMenu = new MenuBar.Menu.Builder(context.getResources().getString(R.string.more))
+ .icon(R.drawable.icon_more).onSelect(new Runnable() {
+ public void run() {
+ buildMoreOptions();
+ }
+ }).build();
mNormalBottomMenu = new MenuBar.Menu[] { shareMenu, deleteMenu, moreMenu };
mSingleViewIntentBottomMenu = new MenuBar.Menu[] { shareMenu, moreMenu };
setAlpha(1.0f);
}
}).build(), /* new MenuBar.Menu.Builder("").build(), */
- new MenuBar.Menu.Builder(context.getResources().getString(R.string.menu)).icon(R.drawable.icon_more)
- .onSingleTapUp(new Runnable() {
+ new MenuBar.Menu.Builder(context.getResources().getString(R.string.menu)).icon(R.drawable.icon_more).onSingleTapUp(
+ new Runnable() {
public void run() {
if (getAlpha() == 1.0f)
mGridLayer.enterSelectionMode();
}
}).build() });
}
-
+
public void setContext(Context context) {
if (mContext != context) {
mContext = context;
}
}
- // We are assuming that the more menu is the last item in the menu array.
+ // We are assuming that the more menu is the last item in the menu
+ // array.
int lastIndex = mSelectionMenuBottom.getMenus().length - 1;
mSelectionMenuBottom.getMenus()[lastIndex].options = options;
}
// Show the time bar in stack and grid states, except in selection mode.
mTimeBar.setHidden(fullscreenMode || selectionMode || stackMode);
- // mTimeBar.setHidden(selectionMode || (state != GridLayer.STATE_TIMELINE && state != GridLayer.STATE_GRID_VIEW));
+ // mTimeBar.setHidden(selectionMode || (state !=
+ // GridLayer.STATE_TIMELINE && state != GridLayer.STATE_GRID_VIEW));
// Hide the path bar and top-right button in selection mode.
mPathBar.setHidden(selectionMode);
public boolean onTouchEvent(MotionEvent event) {
if (mMode == MODE_SELECT) {
/*
- * setMode(MODE_NORMAL); ArrayList<MediaBucket> displayBuckets = mGridLayer.getSelectedBuckets(); // use this list, and
- * then clear the items return true;
+ * setMode(MODE_NORMAL); ArrayList<MediaBucket> displayBuckets =
+ * mGridLayer.getSelectedBuckets(); // use this list, and then clear
+ * the items return true;
*/
return false;
} else {
}
private void updateShareMenu() {
- // Get the first selected item. Wire this up to multiple-item intents when we move
+ // Get the first selected item. Wire this up to multiple-item intents
+ // when we move
// to Eclair.
ArrayList<MediaBucket> selection = mGridLayer.getSelectedBuckets();
ArrayList<Uri> uris = new ArrayList<Uri>();
mediaType = item.getMediaType();
MediaSet parentMediaSet = item.mParentMediaSet;
if (parentMediaSet != null && parentMediaSet.mPicasaAlbumId != Shared.INVALID) {
- // This will go away once http uri's are supported for all media types.
- // This ensures that just the link is shared as a text
+ // This will go away once http uri's are supported
+ // for all media types.
+ // This ensures that just the link is shared as a
+ // text
mimeType = "text/plain";
}
}
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 we are in single view mode, show the bottom menu without the
+ // delete button.
if (mGridLayer.noDeleteMode()) {
mSelectionMenuBottom.setMenus(mSingleViewIntentBottomMenu);
} else {
mSelectionMenuBottom.setMenus(mNormalBottomMenu);
}
}
-
+
public void computeBottomMenu() {
- // we need to the same for picasa albums
+ // we need to the same for picasa albums
ArrayList<MediaBucket> selection = mGridLayer.getSelectedBuckets();
Menu[] menus = mSelectionMenuBottom.getMenus();
if (menus == mSingleViewIntentBottomMenu)
- return;
+ 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;
- }
+ MediaBucket bucket = selection.get(i);
+ if (bucket.mediaSet.mPicasaAlbumId != Shared.INVALID) {
+ mSelectionMenuBottom.setMenus(mSingleViewIntentBottomMenu);
+ break;
+ }
}
}
if (mCurrentImage != image) {
if (animate) {
mFade.setValue(0f);
- mFade.animateValue(1f, 0.25f, SystemClock.uptimeMillis()); // TODO: use frame clock.
+ mFade.animateValue(1f, 0.25f, SystemClock.uptimeMillis()); // TODO:
+ // use
+ // frame
+ // clock.
mPreviousImage = mCurrentImage;
} else {
mFade.setValue(1f);
import android.util.Log;
/**
- * ImageManager is used to retrieve and store images
- * in the media content provider.
+ * ImageManager is used to retrieve and store images in the media content
+ * provider.
*/
public class ImageManager {
private static final String TAG = "ImageManager";
/**
* Enumerate type for the location of the images in gallery.
*/
- public static enum DataLocation { NONE, INTERNAL, EXTERNAL, ALL }
+ public static enum DataLocation {
+ NONE, INTERNAL, EXTERNAL, ALL
+ }
- public static final Bitmap DEFAULT_THUMBNAIL =
- Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565);
- public static final Bitmap NO_IMAGE_BITMAP =
- Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
+ public static final Bitmap DEFAULT_THUMBNAIL = Bitmap.createBitmap(32, 32, Bitmap.Config.RGB_565);
+ public static final Bitmap NO_IMAGE_BITMAP = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
public static final int SORT_ASCENDING = 1;
public static final int SORT_DESCENDING = 2;
public static final int INCLUDE_DRM_IMAGES = (1 << 1);
public static final int INCLUDE_VIDEOS = (1 << 2);
- public static final String CAMERA_IMAGE_BUCKET_NAME =
- Environment.getExternalStorageDirectory().toString()
- + "/DCIM/Camera";
- public static final String CAMERA_IMAGE_BUCKET_ID =
- getBucketId(CAMERA_IMAGE_BUCKET_NAME);
+ public static final String CAMERA_IMAGE_BUCKET_NAME = Environment.getExternalStorageDirectory().toString() + "/DCIM/Camera";
+ public static final String CAMERA_IMAGE_BUCKET_ID = getBucketId(CAMERA_IMAGE_BUCKET_NAME);
/**
* Matches code in MediaProvider.computeBucketValues. Should be a common
* imported. This is a temporary fix for bug#1655552.
*/
public static void ensureOSXCompatibleFolder() {
- File nnnAAAAA = new File(
- Environment.getExternalStorageDirectory().toString()
- + "/DCIM/100ANDRO");
+ File nnnAAAAA = new File(Environment.getExternalStorageDirectory().toString() + "/DCIM/100ANDRO");
if ((!nnnAAAAA.exists()) && (!nnnAAAAA.mkdir())) {
- Log.e(TAG, "create NNNAAAAA file: " + nnnAAAAA.getPath()
- + " failed");
+ Log.e(TAG, "create NNNAAAAA file: " + nnnAAAAA.getPath() + " failed");
}
}
cr.update(uri, values, null, null);
}
- public static Uri addImage(ContentResolver cr, String title,
- long dateTaken, double latitude, double longitude,
+ public static Uri addImage(ContentResolver cr, String title, long dateTaken, double latitude, double longitude,
int orientation, String directory, String filename) {
ContentValues values = new ContentValues(7);
values.put(Images.Media.LATITUDE, latitude);
values.put(Images.Media.LONGITUDE, longitude);
-
+
if (directory != null && filename != null) {
String value = directory + "/" + filename;
values.put(Images.Media.DATA, value);
return cr.insert(STORAGE_URI, values);
}
-
private static class AddImageCancelable extends BaseCancelable<Void> {
private final Uri mUri;
private final ContentResolver mCr;
- private final byte [] mJpegData;
+ private final byte[] mJpegData;
- public AddImageCancelable(Uri uri, ContentResolver cr,
- int orientation, Bitmap source, byte[] jpegData) {
+ public AddImageCancelable(Uri uri, ContentResolver cr, int orientation, Bitmap source, byte[] jpegData) {
if (source == null && jpegData == null || uri == null) {
throw new IllegalArgumentException("source cannot be null");
}
}
@Override
- protected Void execute() throws InterruptedException,
- ExecutionException {
+ protected Void execute() throws InterruptedException, ExecutionException {
boolean complete = false;
try {
- String[] projection = new String[] {
- ImageColumns._ID,
- ImageColumns.MINI_THUMB_MAGIC};
+ String[] projection = new String[] { ImageColumns._ID, ImageColumns.MINI_THUMB_MAGIC };
Cursor c = mCr.query(mUri, projection, null, null, null);
try {
c.moveToPosition(0);
}
}
- public static Cancelable<Void> storeImage(
- Uri uri, ContentResolver cr, int orientation,
- Bitmap source, byte [] jpegData) {
- return new AddImageCancelable(
- uri, cr, orientation, source, jpegData);
+ public static Cancelable<Void> storeImage(Uri uri, ContentResolver cr, int orientation, Bitmap source, byte[] jpegData) {
+ return new AddImageCancelable(uri, cr, orientation, source, jpegData);
}
static boolean isSingleImageMode(String uriString) {
- return !uriString.startsWith(
- MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())
- && !uriString.startsWith(
- MediaStore.Images.Media.INTERNAL_CONTENT_URI.toString());
+ return !uriString.startsWith(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())
+ && !uriString.startsWith(MediaStore.Images.Media.INTERNAL_CONTENT_URI.toString());
}
private static boolean checkFsWritable() {
// Create a temporary file to see whether a volume is really writeable.
// It's important not to put it in the root directory which may have a
// limit on the number of files.
- String directoryName =
- Environment.getExternalStorageDirectory().toString() + "/DCIM";
+ String directoryName = Environment.getExternalStorageDirectory().toString() + "/DCIM";
File directory = new File(directoryName);
if (!directory.isDirectory()) {
if (!directory.mkdirs()) {
return false;
}
}
-
+
public static boolean quickHasStorage() {
return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
}
} else {
return true;
}
- } else if (!requireWriteAccess
- && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
+ } else if (!requireWriteAccess && Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
return true;
}
return false;
}
- private static final Cursor query(final ContentResolver resolver, final Uri uri,
- final String[] projection, final String selection, final String[] selectionArgs,
- final String sortOrder) {
+ private static final Cursor query(final ContentResolver resolver, final Uri uri, final String[] projection,
+ final String selection, final String[] selectionArgs, final String sortOrder) {
try {
if (resolver == null) {
return null;
}
- return resolver.query(
- uri, projection, selection, selectionArgs, sortOrder);
- } catch (UnsupportedOperationException ex) {
+ return resolver.query(uri, projection, selection, selectionArgs, sortOrder);
+ } catch (UnsupportedOperationException ex) {
return null;
}
public static final boolean isMediaScannerScanning(final ContentResolver cr) {
boolean result = false;
- final Cursor cursor = query(cr, MediaStore.getMediaScannerUri(),
- new String [] {MediaStore.MEDIA_SCANNER_VOLUME},
- null, null, null);
+ final Cursor cursor = query(cr, MediaStore.getMediaScannerUri(), new String[] { MediaStore.MEDIA_SCANNER_VOLUME }, null,
+ null, null);
if (cursor != null) {
if (cursor.getCount() == 1) {
cursor.moveToFirst();
}
public static String getLastImageThumbPath() {
- return Environment.getExternalStorageDirectory().toString() +
- "/DCIM/.thumbnails/image_last_thumb";
+ return Environment.getExternalStorageDirectory().toString() + "/DCIM/.thumbnails/image_last_thumb";
}
public static String getLastVideoThumbPath() {
- return Environment.getExternalStorageDirectory().toString() +
- "/DCIM/.thumbnails/video_last_thumb";
+ return Environment.getExternalStorageDirectory().toString() + "/DCIM/.thumbnails/video_last_thumb";
}
}
-
private static final String TAG = "ImageViewTouchBase";
// This is the base transformation which is used to show the image
- // initially. The current computation for this shows the image in
- // it's entirety, letterboxing as needed. One could choose to
+ // initially. The current computation for this shows the image in
+ // it's entirety, letterboxing as needed. One could choose to
// show the image as cropped instead.
//
// This matrix is recomputed when we go from the thumbnail image to
private Recycler mRecycler;
@Override
- protected void onLayout(boolean changed, int left, int top,
- int right, int bottom) {
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mThisWidth = right - left;
mThisHeight = bottom - top;
// This function changes bitmap, reset base matrix according to the size
// of the bitmap, and optionally reset the supplementary matrix.
- public void setImageBitmapResetBase(final Bitmap bitmap,
- final boolean resetSupp) {
+ public void setImageBitmapResetBase(final Bitmap bitmap, final boolean resetSupp) {
setImageRotateBitmapResetBase(new RotateBitmap(bitmap), resetSupp);
}
- public void setImageRotateBitmapResetBase(final RotateBitmap bitmap,
- final boolean resetSupp) {
+ public void setImageRotateBitmapResetBase(final RotateBitmap bitmap, final boolean resetSupp) {
final int viewWidth = getWidth();
- if (viewWidth <= 0) {
+ if (viewWidth <= 0) {
mOnLayoutRunnable = new Runnable() {
public void run() {
setImageRotateBitmapResetBase(bitmap, resetSupp);
mMaxZoom = maxZoom();
}
- // Center as much as possible in one or both axis. Centering is
- // defined as follows: if the image is scaled down below the
- // view's dimensions then center it (literally). If the image
+ // Center as much as possible in one or both axis. Centering is
+ // defined as follows: if the image is scaled down below the
+ // view's dimensions then center it (literally). If the image
// is scaled larger than the view and is translated out of view
// then translate it back into view (i.e. eliminate black bars).
protected void center(boolean horizontal, boolean vertical) {
Matrix m = getImageViewMatrix();
- RectF rect = new RectF(0, 0,
- mBitmapDisplayed.getBitmap().getWidth(),
- mBitmapDisplayed.getBitmap().getHeight());
+ RectF rect = new RectF(0, 0, mBitmapDisplayed.getBitmap().getWidth(), mBitmapDisplayed.getBitmap().getHeight());
m.mapRect(rect);
float height = rect.height();
- float width = rect.width();
+ float width = rect.width();
float deltaX = 0, deltaY = 0;
matrix.postConcat(bitmap.getRotateMatrix());
matrix.postScale(scale, scale);
- matrix.postTranslate(
- (viewWidth - w * scale) / 2F,
- (viewHeight - h * scale) / 2F);
+ matrix.postTranslate((viewWidth - w * scale) / 2F, (viewHeight - h * scale) / 2F);
}
// Combine the base matrix and the supp matrix to make the final matrix.
return 1F;
}
- float fw = (float) mBitmapDisplayed.getWidth() / (float) mThisWidth;
+ float fw = (float) mBitmapDisplayed.getWidth() / (float) mThisWidth;
float fh = (float) mBitmapDisplayed.getHeight() / (float) mThisHeight;
float max = Math.max(fw, fh) * 4;
return max;
center(true, true);
}
- protected void zoomTo(final float scale, final float centerX,
- final float centerY, final float durationMs) {
+ protected void zoomTo(final float scale, final float centerX, final float centerY, final float durationMs) {
final float incrementPerMs = (scale - getScale()) / durationMs;
final float oldScale = getScale();
final long startTime = System.currentTimeMillis();
protected void zoomIn(float rate) {
if (getScale() >= mMaxZoom) {
- return; // Don't let the user zoom into the molecular level.
+ return; // Don't let the user zoom into the molecular level.
}
if (mBitmapDisplayed.getBitmap() == null) {
return;
return false;
}
- // Allows subclasses to further constrain the hit test defined by layer bounds.
+ // Allows subclasses to further constrain the hit test defined by layer
+ // bounds.
public boolean containsPoint(float x, float y) {
return true;
}
public abstract class LayoutInterface {
public abstract void getPositionForSlotIndex(int displayIndex, int itemWidth, int itemHeight, Vector3f outPosition); // the
- // positions
- // of the
- // individual
- // slots
+ // positions
+ // of the
+ // individual
+ // slots
}
public final class LoadingLayer extends Layer {
private static final float FADE_INTERVAL = 0.5f;
private static final float GRAY_VALUE = 0.1f;
- private static final int[] PRELOAD_RESOURCES_ASYNC_UNSCALED = {R.drawable.stack_frame, R.drawable.grid_frame,
- R.drawable.stack_frame_focus, R.drawable.stack_frame_gold, R.drawable.btn_location_filter_unscaled, R.drawable.videooverlay,
- R.drawable.grid_check_on, R.drawable.grid_check_off, R.drawable.icon_camera_small_unscaled, R.drawable.icon_picasa_small_unscaled};
+ private static final int[] PRELOAD_RESOURCES_ASYNC_UNSCALED = { R.drawable.stack_frame, R.drawable.grid_frame,
+ R.drawable.stack_frame_focus, R.drawable.stack_frame_gold, R.drawable.btn_location_filter_unscaled,
+ R.drawable.videooverlay, R.drawable.grid_check_on, R.drawable.grid_check_off, R.drawable.icon_camera_small_unscaled,
+ R.drawable.icon_picasa_small_unscaled };
- private static final int[] PRELOAD_RESOURCES_ASYNC_SCALED = {/*R.drawable.btn_camera_pressed, R.drawable.btn_camera_focus,
- R.drawable.fullscreen_hud_bg, R.drawable.icon_delete,
- R.drawable.icon_edit, R.drawable.icon_more, R.drawable.icon_share, R.drawable.selection_bg_upper,
- R.drawable.selection_menu_bg, R.drawable.selection_menu_bg_pressed, R.drawable.selection_menu_bg_pressed_left,
- R.drawable.selection_menu_bg_pressed_right, R.drawable.selection_menu_divider, R.drawable.timebar_bg,
- R.drawable.timebar_knob, R.drawable.timebar_knob_pressed, R.drawable.timebar_prev, R.drawable.timebar_next,
- R.drawable.mode_grid, R.drawable.mode_stack, R.drawable.icon_camera_small, R.drawable.icon_location_small,
- R.drawable.icon_picasa_small, R.drawable.icon_folder_small, R.drawable.scroller_new, R.drawable.scroller_pressed_new,
- R.drawable.btn_camera, R.drawable.btn_play, R.drawable.pathbar_bg, R.drawable.pathbar_cap, R.drawable.pathbar_join,
- R.drawable.transparent, R.drawable.icon_home_small, R.drawable.ic_fs_details,
- R.drawable.ic_spinner1, R.drawable.ic_spinner2, R.drawable.ic_spinner3, R.drawable.ic_spinner4, R.drawable.ic_spinner5,
- R.drawable.ic_spinner6, R.drawable.ic_spinner7, R.drawable.ic_spinner8*/};
+ private static final int[] PRELOAD_RESOURCES_ASYNC_SCALED = {/*
+ * R.drawable.btn_camera_pressed
+ * ,
+ * R.drawable.
+ * btn_camera_focus
+ * ,
+ * R.drawable.
+ * fullscreen_hud_bg
+ * ,
+ * R.drawable.
+ * icon_delete,
+ * R.drawable.
+ * icon_edit,
+ * R.drawable.
+ * icon_more,
+ * R.drawable.
+ * icon_share,
+ * R.drawable.
+ * selection_bg_upper
+ * ,
+ * R.drawable.
+ * selection_menu_bg
+ * ,
+ * R.drawable.
+ * selection_menu_bg_pressed
+ * ,
+ * R.drawable.
+ * selection_menu_bg_pressed_left
+ * ,
+ * R.drawable.
+ * selection_menu_bg_pressed_right
+ * ,
+ * R.drawable.
+ * selection_menu_divider
+ * ,
+ * R.drawable.
+ * timebar_bg,
+ * R.drawable.
+ * timebar_knob
+ * ,
+ * R.drawable.
+ * timebar_knob_pressed
+ * ,
+ * R.drawable.
+ * timebar_prev
+ * ,
+ * R.drawable.
+ * timebar_next
+ * ,
+ * R.drawable.
+ * mode_grid,
+ * R.drawable.
+ * mode_stack,
+ * R.drawable.
+ * icon_camera_small
+ * ,
+ * R.drawable.
+ * icon_location_small
+ * ,
+ * R.drawable.
+ * icon_picasa_small
+ * ,
+ * R.drawable.
+ * icon_folder_small
+ * ,
+ * R.drawable.
+ * scroller_new
+ * ,
+ * R.drawable.
+ * scroller_pressed_new
+ * ,
+ * R.drawable.
+ * btn_camera,
+ * R.drawable.
+ * btn_play,
+ * R.drawable
+ * .pathbar_bg,
+ * R.drawable.
+ * pathbar_cap,
+ * R.drawable.
+ * pathbar_join
+ * ,
+ * R.drawable.
+ * transparent,
+ * R.drawable.
+ * icon_home_small
+ * ,
+ * R.drawable.
+ * ic_fs_details
+ * ,
+ * R.drawable.
+ * ic_spinner1,
+ * R.drawable.
+ * ic_spinner2,
+ * R.drawable.
+ * ic_spinner3,
+ * R.drawable.
+ * ic_spinner4,
+ * R.drawable.
+ * ic_spinner5,
+ * R.drawable.
+ * ic_spinner6,
+ * R.drawable.
+ * ic_spinner7,
+ * R.drawable.
+ * ic_spinner8
+ */};
private boolean mLoaded = false;
private final FloatAnim mOpacity = new FloatAnim(1f);
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;
+ public static boolean sObserverActive = false;
private boolean mDisableImages;
private boolean mDisableVideos;
/**
- * Matches code in MediaProvider.computeBucketValues. Should be a common function.
+ * Matches code in MediaProvider.computeBucketValues. Should be a common
+ * function.
*/
public static int getBucketId(String path) {
return (path.toLowerCase().hashCode());
}
private Context mContext;
- private ContentObserver mObserver;
+ private ContentObserver mObserver;
public LocalDataSource(Context context) {
mContext = context;
Handler handler = ((Gallery) mContext).getHandler();
ContentObserver observer = new ContentObserver(handler) {
public void onChange(boolean selfChange) {
- MediaSet mediaSet = feed.getCurrentSet();
- if (mediaSet != null) {
- CacheService.markDirtyImmediate(mediaSet.mId);
- refreshUI(feed, mediaSet.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]);
- }
- }
- }
- });
+ MediaSet mediaSet = feed.getCurrentSet();
+ if (mediaSet != null) {
+ CacheService.markDirtyImmediate(mediaSet.mId);
+ refreshUI(feed, mediaSet.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]);
+ }
+ }
+ }
+ });
}
};
-
+
// Start listening.
Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
stopListeners();
}
}
-
+
private void stopListeners() {
ContentResolver cr = mContext.getContentResolver();
if (mObserver != null) {
}
sObserverActive = false;
}
-
+
protected void refreshUI(MediaFeed feed, long setIdToUse) {
if (setIdToUse == Shared.INVALID) {
return;
if (set != null && items != null) {
// We need to remove these items from the set.
int numItems = items.size();
- for (int j = 0; j < numItems; ++j) {
- MediaItem item = items.get(j);
- cr.delete(Uri.parse(item.mContentUri), null, null);
+ try {
+ for (int j = 0; j < numItems; ++j) {
+ MediaItem item = items.get(j);
+ cr.delete(Uri.parse(item.mContentUri), null, null);
+ }
+ } catch (Exception e) {
+ // If the database operation failed for any reason.
+ ;
}
set.updateNumExpectedItems();
set.generateTitle(true);
// Update the database entry.
ContentValues values = new ContentValues();
values.put(Images.ImageColumns.ORIENTATION, rotationString);
- cr.update(Uri.parse(item.mContentUri), values, null, null);
+ try {
+ cr.update(Uri.parse(item.mContentUri), values, null, null);
+ } catch (Exception e) {
+ // If the database operation fails for any reason.
+ ;
+ }
// Update the file EXIF information.
Uri uri = Uri.parse(item.mContentUri);
long id = ContentUris.parseId(target);
ContentResolver cr = context.getContentResolver();
String whereClause = Images.ImageColumns._ID + "=" + Long.toString(id);
- Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
- if (cursor != null) {
- if (cursor.moveToFirst()) {
- item = new MediaItem();
- CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
+ try {
+ Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
+ if (cursor != null) {
+ if (cursor.moveToFirst()) {
+ item = new MediaItem();
+ CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
+ }
+ cursor.close();
+ cursor = null;
}
- cursor.close();
- cursor = null;
+ } catch (Exception e) {
+ // If the database operation failed for any reason.
+ ;
}
return item;
}
long bucketId = SingleDataSource.parseBucketIdFromFileUri(fileUri);
String whereClause = Images.ImageColumns.BUCKET_ID + "=" + bucketId + " AND " + Images.ImageColumns.DATA + "='" + filepath
+ "'";
- Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
- if (cursor != null) {
- if (cursor.moveToFirst()) {
- item = new MediaItem();
- CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
+ try {
+ Cursor cursor = cr.query(Images.Media.EXTERNAL_CONTENT_URI, CacheService.PROJECTION_IMAGES, whereClause, null, null);
+ if (cursor != null) {
+ if (cursor.moveToFirst()) {
+ item = new MediaItem();
+ CacheService.populateMediaItemFromCursor(item, cr, cursor, Images.Media.EXTERNAL_CONTENT_URI.toString() + "/");
+ }
+ cursor.close();
+ cursor = null;
}
- cursor.close();
- cursor = null;
+ } catch (Exception e) {
+ // If the database operation failed for any reason.
+ ;
}
return item;
}
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
- * Math.sin(dLon / 2) * Math.sin(dLon / 2);
+ * Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS_METERS * c;
}
import android.util.Log;
/**
- * SparseArrays map longs to Objects. Unlike a normal array of Objects, there can be gaps in the indices. It is intended to be more
- * efficient than using a HashMap to map Longs to Objects.
+ * SparseArrays map longs to Objects. Unlike a normal array of Objects, there
+ * can be gaps in the indices. It is intended to be more efficient than using a
+ * HashMap to map Longs to Objects.
*
* @hide
*/
}
/**
- * Creates a new SparseArray containing no mappings that will not require any additional memory allocation to store the
- * specified number of mappings.
+ * Creates a new SparseArray containing no mappings that will not require
+ * any additional memory allocation to store the specified number of
+ * mappings.
*/
public LongSparseArray(int initialCapacity) {
initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
}
/**
- * Gets the Object mapped from the specified key, or <code>null</code> if no such mapping has been made.
+ * Gets the Object mapped from the specified key, or <code>null</code> if no
+ * such mapping has been made.
*/
public E get(long key) {
return get(key, null);
}
/**
- * Gets the Object mapped from the specified key, or the specified Object if no such mapping has been made.
+ * Gets the Object mapped from the specified key, or the specified Object if
+ * no such mapping has been made.
*/
@SuppressWarnings("unchecked")
public E get(long key, E valueIfKeyNotFound) {
}
/**
- * Adds a mapping from the specified key to the specified value, replacing the previous mapping from the specified key if there
- * was one.
+ * Adds a mapping from the specified key to the specified value, replacing
+ * the previous mapping from the specified key if there was one.
*/
public void put(long key, E value) {
int i = binarySearch(mKeys, 0, mSize, key);
}
/**
- * Returns the number of key-value mappings that this SparseArray currently stores.
+ * Returns the number of key-value mappings that this SparseArray currently
+ * stores.
*/
public int size() {
if (mGarbage) {
}
/**
- * Given an index in the range <code>0...size()-1</code>, returns the key from the <code>index</code>th key-value mapping that
- * this SparseArray stores.
+ * Given an index in the range <code>0...size()-1</code>, returns the key
+ * from the <code>index</code>th key-value mapping that this SparseArray
+ * stores.
*/
public long keyAt(int index) {
if (mGarbage) {
}
/**
- * Given an index in the range <code>0...size()-1</code>, returns the value from the <code>index</code>th key-value mapping that
- * this SparseArray stores.
+ * Given an index in the range <code>0...size()-1</code>, returns the value
+ * from the <code>index</code>th key-value mapping that this SparseArray
+ * stores.
*/
@SuppressWarnings("unchecked")
public E valueAt(int index) {
}
/**
- * Given an index in the range <code>0...size()-1</code>, sets a new value for the <code>index</code>th key-value mapping that
- * this SparseArray stores.
+ * Given an index in the range <code>0...size()-1</code>, sets a new value
+ * for the <code>index</code>th key-value mapping that this SparseArray
+ * stores.
*/
public void setValueAt(int index, E value) {
if (mGarbage) {
}
/**
- * Returns the index for which {@link #keyAt} would return the specified key, or a negative number if the specified key is not
- * mapped.
+ * Returns the index for which {@link #keyAt} would return the specified
+ * key, or a negative number if the specified key is not mapped.
*/
public int indexOfKey(long key) {
if (mGarbage) {
}
/**
- * Returns an index for which {@link #valueAt} would return the specified key, or a negative number if no keys map to the
- * specified value. Beware that this is a linear search, unlike lookups by key, and that multiple keys can map to the same value
- * and this will find only one of them.
+ * Returns an index for which {@link #valueAt} would return the specified
+ * key, or a negative number if no keys map to the specified value. Beware
+ * that this is a linear search, unlike lookups by key, and that multiple
+ * keys can map to the same value and this will find only one of them.
*/
public int indexOfValue(E value) {
if (mGarbage) {
}
/**
- * Puts a key/value pair into the array, optimizing for the case where the key is greater than all existing keys in the array.
+ * Puts a key/value pair into the array, optimizing for the case where the
+ * key is greater than all existing keys in the array.
*/
public void append(long key, E value) {
if (mSize != 0 && key <= mKeys[mSize - 1]) {
}
/**
- * Returns an empty array of the specified type. The intent is that it will return the same empty array every time to avoid
- * reallocation, although this is not guaranteed.
+ * Returns an empty array of the specified type. The intent is that it
+ * will return the same empty array every time to avoid reallocation,
+ * although this is not guaranteed.
*/
@SuppressWarnings("unchecked")
public static <T> T[] emptyArray(Class<T> kind) {
cache = Array.newInstance(kind, 0);
sCache[bucket] = cache;
- // Log.e("cache", "new empty " + kind.getName() + " at " + bucket);
+ // Log.e("cache", "new empty " + kind.getName() + " at " +
+ // bucket);
}
return (T[]) cache;
}
/**
- * Checks that value is present as at least one of the elements of the array.
+ * Checks that value is present as at least one of the elements of the
+ * array.
*
* @param array
* the array to check in
mTemp = new float[MATRIX_SIZE * 2];
glLoadIdentity();
}
-
+
public void apply(float[] mCoordsIn, float[] mCoordsOut) {
Matrix.multiplyMV(mCoordsOut, 0, mMatrix, mTop, mCoordsIn, 0);
}
- public void glFrustumf(float left, float right, float bottom, float top,
- float near, float far) {
+ public void glFrustumf(float left, float right, float bottom, float top, float near, float far) {
Matrix.frustumM(mMatrix, mTop, left, right, bottom, top, near, far);
}
- public void glFrustumx(int left, int right, int bottom, int top, int near,
- int far) {
- glFrustumf(fixedToFloat(left),fixedToFloat(right),
- fixedToFloat(bottom), fixedToFloat(top),
- fixedToFloat(near), fixedToFloat(far));
+ public void glFrustumx(int left, int right, int bottom, int top, int near, int far) {
+ glFrustumf(fixedToFloat(left), fixedToFloat(right), fixedToFloat(bottom), fixedToFloat(top), fixedToFloat(near),
+ fixedToFloat(far));
}
public void glLoadIdentity() {
}
public void glLoadMatrixx(int[] m, int offset) {
- for(int i = 0; i < MATRIX_SIZE; i++) {
+ for (int i = 0; i < MATRIX_SIZE; i++) {
mMatrix[mTop + i] = fixedToFloat(m[offset + i]);
}
}
public void glLoadMatrixx(IntBuffer m) {
- for(int i = 0; i < MATRIX_SIZE; i++) {
+ for (int i = 0; i < MATRIX_SIZE; i++) {
mMatrix[mTop + i] = fixedToFloat(m.get());
}
}
}
public void glMultMatrixx(int[] m, int offset) {
- for(int i = 0; i < MATRIX_SIZE; i++) {
+ for (int i = 0; i < MATRIX_SIZE; i++) {
mTemp[MATRIX_SIZE + i] = fixedToFloat(m[offset + i]);
}
glMultMatrixf(mTemp, MATRIX_SIZE);
}
public void glMultMatrixx(IntBuffer m) {
- for(int i = 0; i < MATRIX_SIZE; i++) {
+ for (int i = 0; i < MATRIX_SIZE; i++) {
mTemp[MATRIX_SIZE + i] = fixedToFloat(m.get());
}
glMultMatrixf(mTemp, MATRIX_SIZE);
}
- public void glOrthof(float left, float right, float bottom, float top,
- float near, float far) {
+ public void glOrthof(float left, float right, float bottom, float top, float near, float far) {
Matrix.orthoM(mMatrix, mTop, left, right, bottom, top, near, far);
}
- public void glOrthox(int left, int right, int bottom, int top, int near,
- int far) {
- glOrthof(fixedToFloat(left), fixedToFloat(right),
- fixedToFloat(bottom), fixedToFloat(top),
- fixedToFloat(near), fixedToFloat(far));
+ public void glOrthox(int left, int right, int bottom, int top, int near, int far) {
+ glOrthof(fixedToFloat(left), fixedToFloat(right), fixedToFloat(bottom), fixedToFloat(top), fixedToFloat(near),
+ fixedToFloat(far));
}
public void glPopMatrix() {
public void glPushMatrix() {
preflight_adjust(1);
- System.arraycopy(mMatrix, mTop, mMatrix, mTop + MATRIX_SIZE,
- MATRIX_SIZE);
+ System.arraycopy(mMatrix, mTop, mMatrix, mTop + MATRIX_SIZE, MATRIX_SIZE);
adjust(1);
}
private int mTop;
private float[] mTemp;
}
-
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);
return item;
}
- // Returns the first set selection (ignoring sets corresponding to item selections).
+ // Returns the first set selection (ignoring sets corresponding to item
+ // selections).
public static MediaSet getFirstSetSelection(ArrayList<MediaBucket> buckets) {
MediaSet set = null;
if (buckets != null) {
int numItems = 0;
if (bucket.mediaItems == null && bucket.mediaSet != null) {
numItems = bucket.mediaSet.getNumItems();
- // This selection reflects the bucket itself, and not the items inside the bucket (which is 0).
+ // This selection reflects the bucket itself, and not the
+ // items inside the bucket (which is 0).
if (numItems == 0) {
numItems = 1;
}
if (bucketCompare.mediaSet == mediaSetToAdd) {
// We found the MediaSet.
if (!hasExpandedMediaSet) {
- // Remove this bucket from the list since this bucket was already selected.
+ // Remove this bucket from the list since this bucket was
+ // already selected.
if (removeIfAlreadyAdded) {
selectedBuckets.remove(bucketCompare);
}
boolean foundIndex = false;
for (int j = 0; j < numPresentItems; ++j) {
if (selectedItems.get(j) == item) {
- // This index was already present, we need to remove it.
+ // This index was already present, we need to
+ // remove it.
foundIndex = true;
if (removeIfAlreadyAdded) {
selectedItems.remove(j);
return (bucket.mediaSet != null && bucket.mediaItems == null) ? true : false;
}
- // Assumption: If multiple items are selected, they must all be in the first bucket.
+ // Assumption: If multiple items are selected, they must all be in the first
+ // bucket.
protected static boolean isMultipleItemSelection(ArrayList<MediaBucket> buckets) {
if (buckets != null) {
int numBuckets = buckets.size();
import android.content.res.Resources;
/**
- * Implementation of an agglomerative based clustering where all items within a certain time cutoff are grouped into the
- * same cluster. Small adjacent clusters are merged and large individual clusters are considered for splitting.
+ * Implementation of an agglomerative based clustering where all items within a
+ * certain time cutoff are grouped into the same cluster. Small adjacent
+ * clusters are merged and large individual clusters are considered for
+ * splitting.
*
- * TODO: Limitation: Can deal with items not being added incrementally to the end of the current date range
- * but effectively assumes this is the case for efficient performance.
+ * TODO: Limitation: Can deal with items not being added incrementally to the
+ * end of the current date range but effectively assumes this is the case for
+ * efficient performance.
*/
public final class MediaClustering {
- // If 2 items are greater than 25 miles apart, they will be in different clusters.
+ // If 2 items are greater than 25 miles apart, they will be in different
+ // clusters.
private static final int GEOGRAPHIC_DISTANCE_CUTOFF_IN_MILES = 20;
// Do not want to split based on anything under 1 min.
// 3 cluster frequencies of each other.
private static int CLUSTER_SPLIT_MULTIPLIER = 3;
- // The minimum change factor in the time between items to consider a partition.
+ // The minimum change factor in the time between items to consider a
+ // partition.
// Example: (Item 3 - Item 2) / (Item 2 - Item 1).
private static final int MIN_PARTITION_CHANGE_FACTOR = 2;
- // Make the cluster split time of a large cluster half that of a regular cluster.
+ // Make the cluster split time of a large cluster half that of a regular
+ // cluster.
private static final int PARTITION_CLUSTER_SPLIT_TIME_FACTOR = 2;
private ArrayList<Cluster> mClusters;
public void setTimeRange(long timeRange, int numItems) {
if (numItems != 0) {
int meanItemsPerCluster = numItems / NUM_CLUSTERS_TARGETED;
- // Heuristic to get min and max cluster size - half and double the desired items per cluster.
+ // Heuristic to get min and max cluster size - half and double the
+ // desired items per cluster.
mMinClusterSize = meanItemsPerCluster / 2;
mMaxClusterSize = meanItemsPerCluster * 2;
mClusterSplitTime = timeRange / numItems * CLUSTER_SPLIT_MULTIPLIER;
boolean geographicallySeparateItem = false;
boolean itemAddedToCurrentCluster = false;
- // Determine if this item should go in the current cluster or be the start of a new cluster.
+ // Determine if this item should go in the current cluster or be the
+ // start of a new cluster.
if (numCurrClusterItems == 0) {
mCurrCluster.addItem(currentItem);
} else {
MediaItem prevItem = mCurrCluster.getLastItem();
- if (timeDistance(prevItem, currentItem) < mClusterSplitTime) {
- mCurrCluster.addItem(currentItem);
- itemAddedToCurrentCluster = true;
- } else if (isGeographicallySeparated(prevItem, currentItem)) {
+ if (isGeographicallySeparated(prevItem, currentItem)) {
mClusters.add(mCurrCluster);
geographicallySeparateItem = true;
} else if (numCurrClusterItems > mMaxClusterSize) {
splitAndAddCurrentCluster();
- } else if (numClusters > 0 && numCurrClusterItems < mMinClusterSize && !mCurrCluster.mGeographicallySeparatedFromPrevCluster) {
+ } else if (timeDistance(prevItem, currentItem) < mClusterSplitTime) {
+ mCurrCluster.addItem(currentItem);
+ itemAddedToCurrentCluster = true;
+ } else if (numClusters > 0 && numCurrClusterItems < mMinClusterSize
+ && !mCurrCluster.mGeographicallySeparatedFromPrevCluster) {
mergeAndAddCurrentCluster();
} else {
mClusters.add(mCurrCluster);
// The last cluster may potentially be too big or too small.
if (numCurrClusterItems > mMaxClusterSize) {
splitAndAddCurrentCluster();
- } else if (numClusters > 0 && numCurrClusterItems < mMinClusterSize && !mCurrCluster.mGeographicallySeparatedFromPrevCluster) {
+ } else if (numClusters > 0 && numCurrClusterItems < mMinClusterSize
+ && !mCurrCluster.mGeographicallySeparatedFromPrevCluster) {
mergeAndAddCurrentCluster();
} else {
mClusters.add(mCurrCluster);
mClusters.add(partitionedCluster);
} else {
mClusters.add(mCurrCluster);
- }
+ }
}
private int getPartitionIndexForCurrentCluster() {
MediaItem prevItem = currClusterItems.get(i - 1);
MediaItem currItem = currClusterItems.get(i);
MediaItem nextItem = currClusterItems.get(i + 1);
-
+
if (prevItem.isDateTakenValid() && currItem.isDateModifiedValid() && nextItem.isDateModifiedValid()) {
long diff1 = Math.abs(nextItem.mDateTakenInMs - currItem.mDateTakenInMs);
long diff2 = Math.abs(currItem.mDateTakenInMs - prevItem.mDateTakenInMs);
String maxDay = DateFormat.format(MMDDYY_FORMAT, maxTimestamp).toString();
if (minDay.substring(4).equals(maxDay.substring(4))) {
- // The items are from the same year - show at least as much granularity as abbrev_all allows.
+ // The items are from the same year - show at least as
+ // much granularity as abbrev_all allows.
mName = DateUtils.formatDateRange(context, minTimestamp, maxTimestamp, DateUtils.FORMAT_ABBREV_ALL);
- // Get a more granular date range string if the min and max timestamp are on the same day and from the current year.
+ // Get a more granular date range string if the min and
+ // max timestamp are on the same day and from the
+ // current year.
if (minDay.equals(maxDay)) {
int flags = DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_SHOW_DATE;
- // Contains the year only if the date does not correspond to the current year.
+ // Contains the year only if the date does not
+ // correspond to the current year.
String dateRangeWithOptionalYear = DateUtils.formatDateTime(context, minTimestamp, flags);
- String dateRangeWithYear = DateUtils.formatDateTime(context, minTimestamp, flags | DateUtils.FORMAT_SHOW_YEAR);
+ String dateRangeWithYear = DateUtils.formatDateTime(context, minTimestamp, flags
+ | DateUtils.FORMAT_SHOW_YEAR);
if (!dateRangeWithOptionalYear.equals(dateRangeWithYear)) {
- // This means both dates are from the same year - show the time.
- // Not enough room to display the time range. Pick the mid-point.
+ // This means both dates are from the same year
+ // - show the time.
+ // Not enough room to display the time range.
+ // Pick the mid-point.
long midTimestamp = (minTimestamp + maxTimestamp) / 2;
- mName = DateUtils.formatDateRange(context, midTimestamp, midTimestamp, DateUtils.FORMAT_SHOW_TIME | flags);
+ mName = DateUtils.formatDateRange(context, midTimestamp, midTimestamp, DateUtils.FORMAT_SHOW_TIME
+ | flags);
}
}
} else {
- // The items are not from the same year - only show month and year.
+ // The items are not from the same year - only show
+ // month and year.
int flags = DateUtils.FORMAT_NO_MONTH_DAY | DateUtils.FORMAT_ABBREV_MONTH | DateUtils.FORMAT_SHOW_DATE;
mName = DateUtils.formatDateRange(context, minTimestamp, maxTimestamp, flags);
}
// Returns true if a, b are sufficiently geographically separated.
private static boolean isGeographicallySeparated(MediaItem a, MediaItem b) {
- // If a or b are null, a or b have the default latitude, longitude values or are close enough, return false.
+ // If a or b are null, a or b have the default latitude, longitude
+ // values or are close enough, return false.
if (a != null && b != null && a.isLatLongValid() && b.isLatLongValid()) {
int distance = (int) (LocationMediaFilter.toMile(LocationMediaFilter.distanceBetween(a.mLatitude, a.mLongitude,
b.mLatitude, b.mLongitude)) + 0.5);
} else if (set != null && items != null) {
// We need to remove these items from the set.
int numItems = items.size();
- // We also need to delete the items from the cluster.
+ // We also need to delete the items from the
+ // cluster.
MediaClustering clustering = mClusterSets.get(set);
for (int j = 0; j < numItems; ++j) {
MediaItem item = items.get(j);
public void removeMediaSet(MediaSet set) {
synchronized (mMediaSets) {
- mMediaSets.remove(set);
+ mMediaSets.remove(set);
}
mMediaFeedNeedsToRun = true;
}
return;
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
DataSource dataSource = mDataSource;
- // We must wait while the SD card is mounted or the MediaScanner is running.
+ // We must wait while the SD card is mounted or the MediaScanner
+ // is running.
if (dataSource != null) {
dataSource.loadMediaSets(feed);
}
}
MediaSet set = mediaSets.get(expandedSetIndex);
if (numItemsLoaded < set.getNumExpectedItems()) {
- // TODO(Venkat) Why are we doing 4th param calculations like this?
+ // We perform calculations for a window that gets anchored to a multiple of NUM_ITEMS_LOOKAHEAD.
+ // The start of the window is 0, x, 2x, 3x ... etc where x = NUM_ITEMS_LOOKAHEAD.
dataSource.loadItemsForSet(this, set, numItemsLoaded, (requestedItems / NUM_ITEMS_LOOKAHEAD)
* NUM_ITEMS_LOOKAHEAD + NUM_ITEMS_LOOKAHEAD);
if (set.getNumExpectedItems() == 0) {
}
if (mExpandedMediaSetIndex > 0 && mediaSetIndex == Shared.INVALID) {
// We are collapsing a previously expanded media set
- if (mediaSetIndex < mMediaSets.size() && mExpandedMediaSetIndex >= 0) {
+ if (mediaSetIndex < mMediaSets.size() && mExpandedMediaSetIndex >= 0 && mExpandedMediaSetIndex < mMediaSets.size()) {
MediaSet set = mMediaSets.get(mExpandedMediaSetIndex);
if (set.getNumItems() == 0) {
set.clear();
if (mediaSetIndex < mMediaSets.size() && mediaSetIndex >= 0) {
// Notify Picasa that the user entered the album.
// MediaSet set = mMediaSets.get(mediaSetIndex);
- // PicasaService.requestSync(mContext, PicasaService.TYPE_ALBUM_PHOTOS, set.mPicasaAlbumId);
+ // PicasaService.requestSync(mContext,
+ // PicasaService.TYPE_ALBUM_PHOTOS, set.mPicasaAlbumId);
}
updateListener(true);
mMediaFeedNeedsToRun = true;
ArrayList<MediaSet> mediaSets = mMediaSets;
int numSets = mediaSets.size();
for (int i = 0; i < numSets; ++i) {
- final MediaSet thisSet = mediaSets.get(i);
+ final MediaSet thisSet = mediaSets.get(i);
if (thisSet.mId == setId) {
mediaSet.mName = thisSet.mName;
mediaSet.mHasImages = thisSet.mHasImages;
public final class MediaItem {
public static final int MEDIA_TYPE_IMAGE = 0;
public static final int MEDIA_TYPE_VIDEO = 1;
- // Approximately the year 1975 in milliseconds and seconds. Serves as a min cutoff for bad times.
+ // Approximately the year 1975 in milliseconds and seconds. Serves as a min
+ // cutoff for bad times.
public static final long MIN_VALID_DATE_IN_MS = 157680000000L;
public static final long MIN_VALID_DATE_IN_SEC = 157680000L;
- // Approximately the year 2035 in milliseconds ans seconds. Serves as a max cutoff for bad time.
+ // Approximately the year 2035 in milliseconds ans seconds. Serves as a max
+ // cutoff for bad time.
public static final long MAX_VALID_DATE_IN_MS = 2049840000000L;
public static final long MAX_VALID_DATE_IN_SEC = 2049840000L;
- // mId is not a unique identifier of the item mId is initialized to -1 in some cases.
+ // mId is not a unique identifier of the item mId is initialized to -1 in
+ // some cases.
public static final String ID = new String("id");
public long mId;
public boolean isPicassaItem() {
return (mParentMediaSet != null && mParentMediaSet.isPicassaAlbum());
}
-
+
private static final String VIDEO = "video/";
public int getMediaType() {
if (mMediaType == -1) {
// Default to image if mMimetype is null or not video.
- mMediaType = (mMimeType != null && mMimeType.startsWith(VIDEO)) ? MediaItem.MEDIA_TYPE_VIDEO : MediaItem.MEDIA_TYPE_IMAGE;
+ mMediaType = (mMimeType != null && mMimeType.startsWith(VIDEO)) ? MediaItem.MEDIA_TYPE_VIDEO
+ : MediaItem.MEDIA_TYPE_IMAGE;
}
return mMediaType;
}
if (mDisplayMimeType == null && mMimeType != null) {
int slashPos = mMimeType.indexOf('/');
if (slashPos != -1 && slashPos + 1 < mMimeType.length()) {
- mDisplayMimeType = mMimeType.substring(slashPos + 1).toUpperCase();
+ mDisplayMimeType = mMimeType.substring(slashPos + 1).toUpperCase();
} else {
mDisplayMimeType = mMimeType.toUpperCase();
}
mItem = item;
mCached = computeCache();
}
-
+
private boolean computeCache() {
final Config config = mConfig;
final MediaItem item = mItem;
final Config config = mConfig;
final MediaItem item = mItem;
- // Special case for non-MediaStore content URIs, do not cache the thumbnail.
+ // Special case for non-MediaStore content URIs, do not cache the
+ // thumbnail.
String uriString = item.mContentUri;
if (uriString != null) {
Uri uri = Uri.parse(uriString);
public boolean mHasImages;
public boolean mHasVideos;
- // The type of the media set. A smart media set is an automatically generated media set. For example, the most recently
- // viewed items media set is a media set that gets populated by the contents of a folder. A user defined media set
- // is a set that is made by the user. This would typically correspond to media items belonging to an event.
+ // The type of the media set. A smart media set is an automatically
+ // generated media set. For example, the most recently
+ // viewed items media set is a media set that gets populated by the contents
+ // of a folder. A user defined media set
+ // is a set that is made by the user. This would typically correspond to
+ // media items belonging to an event.
public int mType;
// The min and max date taken and added at timestamps.
public double mMaxLonLatitude;
public double mMaxLonLongitude = LocationMediaFilter.LON_MIN;
- // Reverse geocoding the latitude, longitude and getting an address or location.
+ // Reverse geocoding the latitude, longitude and getting an address or
+ // location.
public String mReverseGeocodedLocation;
- // Set to true if at least one item in the set has a valid latitude and longitude.
+ // Set to true if at least one item in the set has a valid latitude and
+ // longitude.
public boolean mLatLongDetermined = false;
public boolean mReverseGeocodedLocationComputed = false;
public boolean mReverseGeocodedLocationRequestMade = false;
private ArrayList<MediaItem> mItems;
public int mNumItemsLoaded = 0;
- // mNumExpectedItems is preset to how many items are expected to be in the set as it is used to visually
- // display the number of items in the set and we don't want this display to keep changing as items get loaded.
+ // mNumExpectedItems is preset to how many items are expected to be in the
+ // set as it is used to visually
+ // display the number of items in the set and we don't want this display to
+ // keep changing as items get loaded.
private int mNumExpectedItems = 0;
private boolean mNumExpectedItemsCountAccurate = false;
}
/**
- * @return underlying ArrayList of MediaItems. Use only for iteration (read operations) on the ArrayList.
+ * @return underlying ArrayList of MediaItems. Use only for iteration (read
+ * operations) on the ArrayList.
*/
public ArrayList<MediaItem> getItems() {
return mItems;
public int getNumExpectedItems() {
return mNumExpectedItems;
}
-
+
public boolean setContainsValidItems() {
if (mNumExpectedItems == 0)
return false;
mTitleString = mName + size;
if (truncateTitle) {
int length = mName.length();
- mTruncTitleString = (length > 16) ? mName.substring(0, 12) + "..." + mName.substring(length - 4, length) + size : mName + size;
+ mTruncTitleString = (length > 16) ? mName.substring(0, 12) + "..." + mName.substring(length - 4, length) + size : mName
+ + size;
mNoCountTitleString = mName;
} else {
mTruncTitleString = mTitleString;
}
/**
- * Adds a MediaItem to this set, and increments the load count. Additionally, it also recomputes
- * the location bounds and time range of the media set.
+ * Adds a MediaItem to this set, and increments the load count.
+ * Additionally, it also recomputes the location bounds and time range of
+ * the media set.
*/
public void addItem(final MediaItem item) {
- // Important to not set the parentMediaSet in here as temporary MediaSet's are occasionally
+ // Important to not set the parentMediaSet in here as temporary
+ // MediaSet's are occasionally
// created and we do not want the MediaItem updated as a result of that.
if (mItems.size() == 0) {
mItems.add(item);
}
if (dateAdded > mMaxAddedTimestamp) {
mMaxAddedTimestamp = dateAdded;
- }
+ }
}
- // Determining the latitude longitude bounds of the set and setting the location string.
+ // Determining the latitude longitude bounds of the set and setting the
+ // location string.
if (!item.isLatLongValid()) {
return;
}
/**
* Removes a MediaItem if present in the MediaSet.
*
- * @return true if the item was removed, false if removal failed or item was not present in the set.
+ * @return true if the item was removed, false if removal failed or item was
+ * not present in the set.
*/
public boolean removeItem(final MediaItem itemToRemove) {
if (mItems.remove(itemToRemove)) {
*/
public boolean isPicassaSet() {
// 2 cases:-
- // 1. This set is just a Picassa Album, and all its items are therefore from Picassa.
- // 2. This set is a random collection of items and each item is a Picassa item.
+ // 1. This set is just a Picassa Album, and all its items are therefore
+ // from Picassa.
+ // 2. This set is a random collection of items and each item is a
+ // Picassa item.
if (isPicassaAlbum()) {
return true;
- }
+ }
int numItems = mItems.size();
for (int i = 0; i < numItems; i++) {
if (!mItems.get(i).isPicassaItem()) {
MENU_TITLE_STYLE.fontSize = 17 * Gallery.PIXEL_DENSITY;
MENU_TITLE_STYLE.sizeMode = StringTexture.Config.SIZE_EXACT;
MENU_TITLE_STYLE.overflowMode = StringTexture.Config.OVERFLOW_FADE;
-
+
MENU_TITLE_STYLE_TEXT.fontSize = 15 * Gallery.PIXEL_DENSITY;
MENU_TITLE_STYLE_TEXT.xalignment = StringTexture.Config.ALIGN_HCENTER;
MENU_TITLE_STYLE_TEXT.sizeMode = StringTexture.Config.SIZE_EXACT;
mSubmenu.close(false);
}
}
-
+
@Override
protected void onSizeChanged() {
mNeedsLayout = true;
}
-
+
@Override
public void generate(RenderView view, RenderView.Lists lists) {
lists.blendedList.add(this);
mNeedsLayout = false;
}
if (mGL != gl) {
- mTextureMap.clear();
- mGL = gl;
+ mTextureMap.clear();
+ mGL = gl;
}
-
+
// Draw the background.
Texture background = view.getResource(BACKGROUND);
int backgroundHeight = background.getHeight();
- int menuHeight = (int)(HEIGHT * Gallery.PIXEL_DENSITY + 0.5f);
+ int menuHeight = (int) (HEIGHT * Gallery.PIXEL_DENSITY + 0.5f);
int extra = background.getHeight() - menuHeight;
view.draw2D(background, mX, mY - extra, mWidth, backgroundHeight);
if (canDrawHighlight()) {
drawHighlight(view, gl, touchMenu);
}
-
+
// Draw labels.
float height = mHeight;
for (int i = 0; i != numMenus; ++i) {
// Draw the icon and title.
Menu menu = menus[i];
ResourceTexture icon = view.getResource(menu.icon);
-
+
StringTexture titleTexture = (StringTexture) mTextureMap.get(menu.title);
if (titleTexture == null) {
- titleTexture = new StringTexture(menu.title, menu.config, menu.titleWidth, MENU_TITLE_STYLE.height);
+ titleTexture = new StringTexture(menu.title, menu.config, menu.titleWidth, MENU_TITLE_STYLE.height);
view.loadTexture(titleTexture);
menu.titleTexture = titleTexture;
mTextureMap.put(menu.title, titleTexture);
view.draw2D(titleTexture, menu.x + offset + iconWidth, titleY);
}
}
-
+
private void drawHighlight(RenderView view, GL11 gl, int touchMenu) {
Texture highlightLeft = view.getResource(MENU_HIGHLIGHT_LEFT);
Texture highlightMiddle = view.getResource(MENU_HIGHLIGHT_MIDDLE);
Texture highlightRight = view.getResource(MENU_HIGHLIGHT_RIGHT);
int height = highlightLeft.getHeight();
- int extra = height - (int)(HEIGHT * Gallery.PIXEL_DENSITY);
+ int extra = height - (int) (HEIGHT * Gallery.PIXEL_DENSITY);
Menu menu = mMenus[touchMenu];
- int x = menu.x + (int)(MENU_HIGHLIGHT_EDGE_INSET * Gallery.PIXEL_DENSITY);
- int width = menu.mWidth - (int)((MENU_HIGHLIGHT_EDGE_INSET * 2) * Gallery.PIXEL_DENSITY);
+ int x = menu.x + (int) (MENU_HIGHLIGHT_EDGE_INSET * Gallery.PIXEL_DENSITY);
+ int width = menu.mWidth - (int) ((MENU_HIGHLIGHT_EDGE_INSET * 2) * Gallery.PIXEL_DENSITY);
int y = (int) mY - extra;
// Draw left edge.
- view.draw2D(highlightLeft, x - MENU_HIGHLIGHT_EDGE_WIDTH * Gallery.PIXEL_DENSITY, y, MENU_HIGHLIGHT_EDGE_WIDTH * Gallery.PIXEL_DENSITY, height);
+ view.draw2D(highlightLeft, x - MENU_HIGHLIGHT_EDGE_WIDTH * Gallery.PIXEL_DENSITY, y, MENU_HIGHLIGHT_EDGE_WIDTH
+ * Gallery.PIXEL_DENSITY, height);
// Draw middle.
view.draw2D(highlightMiddle, x, y, width, height);
int y = (int) mY;
didShow = true;
submenu.setOptions(options);
- submenu.showAtPoint(x, y, (int)mWidth, (int)mHeight);
+ submenu.showAtPoint(x, y, (int) mWidth, (int) mHeight);
}
}
if (!didShow) {
// Forward event to submenu.
mSubmenu.onTouchEvent(event);
- // Leave the submenu open if the touch ends on the menu button in less than
+ // Leave the submenu open if the touch ends on the menu button in
+ // less than
// a time threshold.
long elapsed = event.getEventTime() - event.getDownTime();
if (hit != -1) {
}
private void layoutMenus() {
- mTextureMap.clear();
-
+ mTextureMap.clear();
+
Menu[] menus = mMenus;
int numMenus = menus.length;
// we do the best attempt to fit the menu items and resize them
// also, it tries to minimize different sized menu items
- // it finds the maximum width for a set of menu items, and checks whether that width
- // can be used for all the cells, else, it goes to the next maximum width, so on and
+ // it finds the maximum width for a set of menu items, and checks
+ // whether that width
+ // can be used for all the cells, else, it goes to the next maximum
+ // width, so on and
// so forth
if (numMenus != 0) {
float viewWidth = mWidth;
int occupiedWidth = 0;
int previousMaxWidth = Integer.MAX_VALUE;
int totalDesiredWidth = 0;
-
+
for (int i = 0; i < numMenus; i++) {
totalDesiredWidth += menus[i].computeRequiredWidth();
}
-
+
if (totalDesiredWidth > viewWidth) {
- // Just split the menus up by available size / nr of menus.
- int widthPerMenu = (int) Math.floor(viewWidth / numMenus);
- int x = 0;
-
- for (int i = 0; i < numMenus; i++) {
- Menu menu = menus[i];
- menu.x = x;
- menu.mWidth = widthPerMenu;
- menu.titleWidth = widthPerMenu - (20 + (menu.icon != 0 ? 45 : 0)); //TODO factor out padding etc
-
- // fix up rounding errors by adding the last pixel to the last menu.
- if (i == numMenus - 1) {
- menu.mWidth = (int) viewWidth - x;
- }
- x += widthPerMenu;
-
- }
+ // Just split the menus up by available size / nr of menus.
+ int widthPerMenu = (int) Math.floor(viewWidth / numMenus);
+ int x = 0;
+
+ for (int i = 0; i < numMenus; i++) {
+ Menu menu = menus[i];
+ menu.x = x;
+ menu.mWidth = widthPerMenu;
+ menu.titleWidth = widthPerMenu - (20 + (menu.icon != 0 ? 45 : 0)); // TODO
+ // factor
+ // out
+ // padding
+ // etc
+
+ // fix up rounding errors by adding the last pixel to the
+ // last menu.
+ if (i == numMenus - 1) {
+ menu.mWidth = (int) viewWidth - x;
+ }
+ x += widthPerMenu;
+
+ }
} else {
boolean foundANewMaxWidth = true;
int menusProcessed = 0;
-
- while (foundANewMaxWidth && menusProcessed < numMenus) {
- foundANewMaxWidth = false;
- int maxWidth = 0;
- for (int i = 0; i < numMenus; ++i) {
- int width = menus[i].computeRequiredWidth();
- if (width > maxWidth && width < previousMaxWidth) {
- foundANewMaxWidth = true;
- maxWidth = width;
- }
- }
- // can all the menus have this width
- int cumulativeWidth = maxWidth * (numMenus - menusProcessed) + occupiedWidth;
- if (cumulativeWidth < viewWidth || !foundANewMaxWidth || menusProcessed == numMenus - 1) {
- float delta = (viewWidth - cumulativeWidth) / numMenus;
- if (delta < 0) {
- delta = 0;
- }
- int x = 0;
- for (int i = 0; i < numMenus; ++i) {
- Menu menu = menus[i];
- menu.x = x;
- float width = menus[i].computeRequiredWidth();
- if (width < maxWidth) {
- width = maxWidth + delta;
- } else {
- width += delta;
- }
- menu.mWidth = (int)width;
- menu.titleWidth = StringTexture.computeTextWidthForConfig(menu.title, menu.config); //(int)menus[i].title.computeTextWidth();
- x += width;
- }
- break;
- } else {
- ++menusProcessed;
- previousMaxWidth = maxWidth;
- occupiedWidth += maxWidth;
- }
- }
+
+ while (foundANewMaxWidth && menusProcessed < numMenus) {
+ foundANewMaxWidth = false;
+ int maxWidth = 0;
+ for (int i = 0; i < numMenus; ++i) {
+ int width = menus[i].computeRequiredWidth();
+ if (width > maxWidth && width < previousMaxWidth) {
+ foundANewMaxWidth = true;
+ maxWidth = width;
+ }
+ }
+ // can all the menus have this width
+ int cumulativeWidth = maxWidth * (numMenus - menusProcessed) + occupiedWidth;
+ if (cumulativeWidth < viewWidth || !foundANewMaxWidth || menusProcessed == numMenus - 1) {
+ float delta = (viewWidth - cumulativeWidth) / numMenus;
+ if (delta < 0) {
+ delta = 0;
+ }
+ int x = 0;
+ for (int i = 0; i < numMenus; ++i) {
+ Menu menu = menus[i];
+ menu.x = x;
+ float width = menus[i].computeRequiredWidth();
+ if (width < maxWidth) {
+ width = maxWidth + delta;
+ } else {
+ width += delta;
+ }
+ menu.mWidth = (int) width;
+ menu.titleWidth = StringTexture.computeTextWidthForConfig(menu.title, menu.config); // (int)menus[i].title.computeTextWidth();
+ x += width;
+ }
+ break;
+ } else {
+ ++menusProcessed;
+ previousMaxWidth = maxWidth;
+ occupiedWidth += maxWidth;
+ }
+ }
}
}
}
private int x;
private int mWidth;
private static final float ICON_WIDTH = 45.0f;
-
+
public static final class Builder {
private final String title;
private StringTexture.Config config;
private Menu(Builder builder) {
config = builder.config;
- title = builder.title; //new StringTexture(builder.title, config);
+ title = builder.title; // new StringTexture(builder.title, config);
icon = builder.icon;
onSelect = builder.onSelect;
onDeselect = builder.onDeselect;
width += (ICON_WIDTH); // * Gallery.PIXEL_DENSITY);
}
if (title != null) {
- width += StringTexture.computeTextWidthForConfig(title, config);//title.computeTextWidth();
+ width += StringTexture.computeTextWidthForConfig(title, config);// title.computeTextWidth();
}
// pad it
width += 20;
width = HEIGHT;
return width;
}
-
+
}
public void onSelectionChanged(PopupMenu menu, int selectedIndex) {
public class MonitoredActivity extends Activity {
- private final ArrayList<LifeCycleListener> mListeners =
- new ArrayList<LifeCycleListener>();
+ private final ArrayList<LifeCycleListener> mListeners = new ArrayList<LifeCycleListener>();
public static interface LifeCycleListener {
public void onActivityCreated(MonitoredActivity activity);
+
public void onActivityDestroyed(MonitoredActivity activity);
+
public void onActivityPaused(MonitoredActivity activity);
+
public void onActivityResumed(MonitoredActivity activity);
+
public void onActivityStarted(MonitoredActivity activity);
+
public void onActivityStopped(MonitoredActivity activity);
}
}
public void addLifeCycleListener(LifeCycleListener listener) {
- if (mListeners.contains(listener)) return;
+ if (mListeners.contains(listener))
+ return;
mListeners.add(listener);
}
}
}
}
-
* limitations under the License.
*/
-
import android.app.Activity;
import android.content.Intent;
import android.content.pm.ActivityInfo;
/**
* This activity plays a video from a specified URI.
*/
-public class MovieView extends Activity {
+public class MovieView extends Activity {
@SuppressWarnings("unused")
private static final String TAG = "MovieView";
}
};
if (intent.hasExtra(MediaStore.EXTRA_SCREEN_ORIENTATION)) {
- int orientation = intent.getIntExtra(
- MediaStore.EXTRA_SCREEN_ORIENTATION,
- ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
+ int orientation = intent.getIntExtra(MediaStore.EXTRA_SCREEN_ORIENTATION, ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
if (orientation != getRequestedOrientation()) {
setRequestedOrientation(orientation);
}
}
- mFinishOnCompletion = intent.getBooleanExtra(
- MediaStore.EXTRA_FINISH_ON_COMPLETION, true);
+ mFinishOnCompletion = intent.getBooleanExtra(MediaStore.EXTRA_FINISH_ON_COMPLETION, true);
}
@Override
super.onResume();
}
}
-
* limitations under the License.
*/
-
import android.app.AlertDialog;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.widget.MediaController;
import android.widget.VideoView;
-public class MovieViewControl implements MediaPlayer.OnErrorListener,
- MediaPlayer.OnCompletionListener {
+public class MovieViewControl implements MediaPlayer.OnErrorListener, MediaPlayer.OnCompletionListener {
@SuppressWarnings("unused")
private static final String TAG = "MovieViewControl";
// Copied from MediaPlaybackService in the Music Player app. Should be
// public, but isn't.
- private static final String SERVICECMD =
- "com.android.music.musicservicecommand";
+ private static final String SERVICECMD = "com.android.music.musicservicecommand";
private static final String CMDNAME = "command";
private static final String CMDPAUSE = "pause";
}
}
};
-
- public static String formatDuration(final Context context,
- int durationMs) {
+
+ public static String formatDuration(final Context context, int durationMs) {
int duration = durationMs / 1000;
int h = duration / 3600;
int m = (duration - h * 3600) / 60;
int s = duration - (h * 3600 + m * 60);
String durationValue;
if (h == 0) {
- durationValue = String.format(
- context.getString(R.string.details_ms), m, s);
+ durationValue = String.format(context.getString(R.string.details_ms), m, s);
} else {
- durationValue = String.format(
- context.getString(R.string.details_hms), h, m, s);
+ durationValue = String.format(context.getString(R.string.details_hms), h, m, s);
}
return durationValue;
}
// For streams that we expect to be slow to start up, show a
// progress spinner until playback starts.
String scheme = mUri.getScheme();
- if ("http".equalsIgnoreCase(scheme)
- || "rtsp".equalsIgnoreCase(scheme)) {
+ if ("http".equalsIgnoreCase(scheme) || "rtsp".equalsIgnoreCase(scheme)) {
mHandler.postDelayed(mPlayingChecker, 250);
} else {
mProgressView.setVisibility(View.GONE);
if (bookmark != null) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle(R.string.resume_playing_title);
- builder.setMessage(String.format(
- context.getString(R.string.resume_playing_message),
- formatDuration(context, bookmark)));
+ builder
+ .setMessage(String
+ .format(context.getString(R.string.resume_playing_message), formatDuration(context, bookmark)));
builder.setOnCancelListener(new OnCancelListener() {
public void onCancel(DialogInterface dialog) {
onCompletion();
- }});
- builder.setPositiveButton(R.string.resume_playing_resume,
- new OnClickListener() {
+ }
+ });
+ builder.setPositiveButton(R.string.resume_playing_resume, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mVideoView.seekTo(bookmark);
mVideoView.start();
- }});
- builder.setNegativeButton(R.string.resume_playing_restart,
- new OnClickListener() {
+ }
+ });
+ builder.setNegativeButton(R.string.resume_playing_restart, new OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mVideoView.start();
- }});
+ }
+ });
builder.show();
} else {
mVideoView.start();
private static boolean uriSupportsBookmarks(Uri uri) {
String scheme = uri.getScheme();
String authority = uri.getAuthority();
- return ("content".equalsIgnoreCase(scheme)
- && MediaStore.AUTHORITY.equalsIgnoreCase(authority));
+ return ("content".equalsIgnoreCase(scheme) && MediaStore.AUTHORITY.equalsIgnoreCase(authority));
}
private Integer getBookmark() {
return null;
}
- String[] projection = new String[] {
- Video.VideoColumns.DURATION,
- Video.VideoColumns.BOOKMARK};
+ String[] projection = new String[] { Video.VideoColumns.DURATION, Video.VideoColumns.BOOKMARK };
try {
- Cursor cursor = mContentResolver.query(
- mUri, projection, null, null, null);
+ Cursor cursor = mContentResolver.query(mUri, projection, null, null, null);
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
int duration = getCursorInteger(cursor, 0);
int bookmark = getCursorInteger(cursor, 1);
- if ((bookmark < TWO_MINUTES)
- || (duration < FIVE_MINUTES)
- || (bookmark > (duration - ONE_MINUTE))) {
+ if ((bookmark < TWO_MINUTES) || (duration < FIVE_MINUTES) || (bookmark > (duration - ONE_MINUTE))) {
return null;
}
return Integer.valueOf(bookmark);
public void onCompletion() {
}
}
-
mComponents.add(new Component(icon, label, action, 0));
recomputeComponents();
}
-
+
public void setAnimatedIcons(final int[] icons) {
final int numComponents = mComponents.size();
for (int i = 0; i < numComponents; ++i) {
pushLabel(component.icon, label, component.action);
}
}
-
+
public String getCurrentLabel() {
final ArrayList<Component> components = mComponents;
int lastIndex = components.size() - 1;
float xOffset = 5 * Gallery.PIXEL_DENSITY;
// Draw the label.
final int[] icons = component.animatedIcons;
-
+
// Cycles animated icons.
- final int iconId = (icons != null && icons.length > 0) ? icons[(int) (component.timeElapsed * 20.0f)
- % icons.length] : component.icon;
+ final int iconId = (icons != null && icons.length > 0) ? icons[(int) (component.timeElapsed * 20.0f) % icons.length]
+ : component.icon;
final Texture icon = view.getResource(iconId);
if (icon != null) {
view.loadTexture(icon);
public class PhotoAppWidgetBind extends Activity {
private static final String TAG = "PhotoAppWidgetBind";
- private static final String EXTRA_APPWIDGET_BITMAPS =
- "com.android.camera.appwidgetbitmaps";
+ private static final String EXTRA_APPWIDGET_BITMAPS = "com.android.camera.appwidgetbitmaps";
@Override
protected void onCreate(Bundle icicle) {
final Intent intent = getIntent();
final Bundle extras = intent.getExtras();
- final int[] appWidgetIds =
- extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
- final ArrayList<Bitmap> bitmaps =
- extras.getParcelableArrayList(EXTRA_APPWIDGET_BITMAPS);
+ final int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
+ final ArrayList<Bitmap> bitmaps = extras.getParcelableArrayList(EXTRA_APPWIDGET_BITMAPS);
- if (appWidgetIds == null || bitmaps == null
- || appWidgetIds.length != bitmaps.size()) {
+ if (appWidgetIds == null || bitmaps == null || appWidgetIds.length != bitmaps.size()) {
Log.e(TAG, "Problem parsing photo widget bind request");
return;
}
helper.setPhoto(appWidgetId, bitmaps.get(i));
// Push newly updated widget to surface
- RemoteViews views =
- PhotoAppWidgetProvider.buildUpdate(this, appWidgetId,
- helper);
+ RemoteViews views = PhotoAppWidgetProvider.buildUpdate(this, appWidgetId, helper);
appWidgetManager.updateAppWidget(new int[] { appWidgetId }, views);
}
helper.close();
}
}
-
// Someone is requesting that we configure the given mAppWidgetId, which
// means we prompt the user to pick and crop a photo.
- mAppWidgetId = getIntent().getIntExtra(
- AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
+ mAppWidgetId = getIntent().getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
if (mAppWidgetId == -1) {
setResult(Activity.RESULT_CANCELED);
finish();
}
@Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == RESULT_OK && mAppWidgetId != -1) {
// Store the cropped photo in our database
Bitmap bitmap = (Bitmap) data.getParcelableExtra("data");
resultCode = Activity.RESULT_OK;
// Push newly updated widget to surface
- RemoteViews views = PhotoAppWidgetProvider.buildUpdate(this,
- mAppWidgetId, helper);
- AppWidgetManager appWidgetManager =
- AppWidgetManager.getInstance(this);
- appWidgetManager.updateAppWidget(new int[] {mAppWidgetId},
- views);
+ RemoteViews views = PhotoAppWidgetProvider.buildUpdate(this, mAppWidgetId, helper);
+ AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
+ appWidgetManager.updateAppWidget(new int[] { mAppWidgetId }, views);
}
helper.close();
} else {
}
}
-
private static final boolean LOGD = true;
@Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager,
- int[] appWidgetIds) {
+ public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// Update each requested appWidgetId with its unique photo
PhotoDatabaseHelper helper = new PhotoDatabaseHelper(context);
for (int appWidgetId : appWidgetIds) {
int[] specificAppWidget = new int[] { appWidgetId };
RemoteViews views = buildUpdate(context, appWidgetId, helper);
if (LOGD) {
- Log.d(TAG, "sending out views=" + views
- + " for id=" + appWidgetId);
+ Log.d(TAG, "sending out views=" + views + " for id=" + appWidgetId);
}
appWidgetManager.updateAppWidget(specificAppWidget, views);
}
/**
* Load photo for given widget and build {@link RemoteViews} for it.
*/
- static RemoteViews buildUpdate(Context context, int appWidgetId,
- PhotoDatabaseHelper helper) {
+ static RemoteViews buildUpdate(Context context, int appWidgetId, PhotoDatabaseHelper helper) {
RemoteViews views = null;
Bitmap bitmap = helper.getPhoto(appWidgetId);
if (bitmap != null) {
- views = new RemoteViews(context.getPackageName(),
- R.layout.photo_frame);
+ views = new RemoteViews(context.getPackageName(), R.layout.photo_frame);
views.setImageViewBitmap(R.id.photo, bitmap);
}
return views;
@Override
public void onCreate(SQLiteDatabase db) {
- db.execSQL("CREATE TABLE " + TABLE_PHOTOS + " (" +
- FIELD_APPWIDGET_ID + " INTEGER PRIMARY KEY," +
- FIELD_PHOTO_BLOB + " BLOB" +
- ");");
+ db.execSQL("CREATE TABLE " + TABLE_PHOTOS + " (" + FIELD_APPWIDGET_ID + " INTEGER PRIMARY KEY," + FIELD_PHOTO_BLOB
+ + " BLOB" + ");");
}
@Override
- public void onUpgrade(SQLiteDatabase db, int oldVersion,
- int newVersion) {
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
int version = oldVersion;
if (version != DATABASE_VERSION) {
ContentValues values = new ContentValues();
values.put(PhotoDatabaseHelper.FIELD_APPWIDGET_ID, appWidgetId);
- values.put(PhotoDatabaseHelper.FIELD_PHOTO_BLOB,
- out.toByteArray());
+ values.put(PhotoDatabaseHelper.FIELD_PHOTO_BLOB, out.toByteArray());
SQLiteDatabase db = getWritableDatabase();
- db.insertOrThrow(PhotoDatabaseHelper.TABLE_PHOTOS, null,
- values);
+ db.insertOrThrow(PhotoDatabaseHelper.TABLE_PHOTOS, null, values);
success = true;
} catch (SQLiteException e) {
return success;
}
- static final String[] PHOTOS_PROJECTION = {
- FIELD_PHOTO_BLOB,
- };
+ static final String[] PHOTOS_PROJECTION = { FIELD_PHOTO_BLOB, };
static final int INDEX_PHOTO_BLOB = 0;
Bitmap bitmap = null;
try {
SQLiteDatabase db = getReadableDatabase();
- String selection = String.format("%s=%d", FIELD_APPWIDGET_ID,
- appWidgetId);
- c = db.query(TABLE_PHOTOS, PHOTOS_PROJECTION, selection, null,
- null, null, null, null);
+ String selection = String.format("%s=%d", FIELD_APPWIDGET_ID, appWidgetId);
+ c = db.query(TABLE_PHOTOS, PHOTOS_PROJECTION, selection, null, null, null, null, null);
if (c != null && LOGD) {
Log.d(TAG, "getPhoto query count=" + c.getCount());
if (c != null && c.moveToFirst()) {
byte[] data = c.getBlob(INDEX_PHOTO_BLOB);
if (data != null) {
- bitmap = BitmapFactory.decodeByteArray(data, 0,
- data.length);
+ bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
}
}
} catch (SQLiteException e) {
public void deletePhoto(int appWidgetId) {
try {
SQLiteDatabase db = getWritableDatabase();
- String whereClause = String.format("%s=%d", FIELD_APPWIDGET_ID,
- appWidgetId);
+ String whereClause = String.format("%s=%d", FIELD_APPWIDGET_ID, appWidgetId);
db.delete(TABLE_PHOTOS, whereClause, null);
} catch (SQLiteException e) {
Log.e(TAG, "Could not delete photo from database", e);
}
}
-
-
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case SHOW_PROGRESS: {
- CharSequence c = getText(R.string.wallpaper);
- mProgressDialog = ProgressDialog.show(Photographs.this,
- "", c, true, false);
- break;
- }
- case FINISH: {
- closeProgressDialog();
- setResult(RESULT_OK);
- finish();
- break;
- }
+ case SHOW_PROGRESS: {
+ CharSequence c = getText(R.string.wallpaper);
+ mProgressDialog = ProgressDialog.show(Photographs.this, "", c, true, false);
+ break;
+ }
+ case FINISH: {
+ closeProgressDialog();
+ setResult(RESULT_OK);
+ finish();
+ break;
+ }
}
}
};
private final Context mContext;
private final File mFile;
- public SetWallpaperThread(Bitmap bitmap, Handler handler,
- Context context, File file) {
+ public SetWallpaperThread(Bitmap bitmap, Handler handler, Context context, File file) {
mBitmap = bitmap;
mHandler = handler;
mContext = context;
Uri imageToUse = getIntent().getData();
if (imageToUse != null) {
Intent intent = new Intent();
- intent.setClassName("com.cooliris.media",
- "com.cooliris.media.CropImage");
+ intent.setClassName("com.cooliris.media", "com.cooliris.media.CropImage");
intent.setData(imageToUse);
formatIntent(intent);
startActivityForResult(intent, CROP_DONE);
int width = getWallpaperDesiredMinimumWidth();
int height = getWallpaperDesiredMinimumHeight();
- intent.putExtra("outputX", width);
- intent.putExtra("outputY", height);
- intent.putExtra("aspectX", width);
- intent.putExtra("aspectY", height);
- intent.putExtra("scale", true);
+ intent.putExtra("outputX", width);
+ intent.putExtra("outputY", height);
+ intent.putExtra("aspectX", width);
+ intent.putExtra("aspectY", height);
+ intent.putExtra("scale", true);
intent.putExtra("noFaceDetection", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTempFile));
intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.name());
}
@Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- if ((requestCode == PHOTO_PICKED || requestCode == CROP_DONE)
- && (resultCode == RESULT_OK) && (data != null)) {
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if ((requestCode == PHOTO_PICKED || requestCode == CROP_DONE) && (resultCode == RESULT_OK) && (data != null)) {
try {
InputStream s = new FileInputStream(mTempFile);
try {
Bitmap bitmap = BitmapFactory.decodeStream(s);
if (bitmap == null) {
- Log.e(LOG_TAG, "Failed to set wallpaper. "
- + "Couldn't get bitmap for path "
- + mTempFile);
+ Log.e(LOG_TAG, "Failed to set wallpaper. " + "Couldn't get bitmap for path " + mTempFile);
} else {
mHandler.sendEmptyMessage(SHOW_PROGRESS);
- new SetWallpaperThread(
- bitmap, mHandler, this, mTempFile).start();
+ new SetWallpaperThread(bitmap, mHandler, this, mTempFile).start();
}
mDoLaunch = false;
} finally {
public PicasaDataSource(final Context context) {
mContext = context;
}
-
+
public static final HashMap<String, Boolean> getAccountStatus(final Context context) {
- final Account[] accounts = PicasaApi.getAccounts(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) {
boolean isEnabled = ContentResolver.getSyncAutomatically(account, PicasaContentProvider.AUTHORITY);
String username = account.name.toLowerCase();
if (username.contains("@gmail.") || username.contains("@googlemail.")) {
- // Strip the domain from GMail accounts for canonicalization. TODO: is there an official way?
+ // 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));
}
public void loadMediaSets(final MediaFeed feed) {
- // 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) {
+ // 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.
+ // Force permission dialog to be displayed if necessary. TODO: remove
+ // this after signed by Google.
PicasaApi.getAccounts(mContext);
- // Ensure that users are up to date. TODO: also listen for accounts changed broadcast.
+ // Ensure that users are up to date. TODO: also listen for accounts
+ // changed broadcast.
PicasaService.requestSync(mContext, PicasaService.TYPE_USERS_ALBUMS, 0);
final Handler handler = ((Gallery) mContext).getHandler();
final ContentObserver albumObserver = new ContentObserver(handler) {
final ArrayList<MediaSet> picasaSets = new ArrayList<MediaSet>(numAlbums);
do {
albumSchema.cursorToObject(cursor, album);
- String userLowerCase = album.user.toLowerCase();
+ String userLowerCase = album.syncAccount.toLowerCase();
final Boolean accountEnabledObj = accountsEnabled.get(userLowerCase);
final boolean accountEnabled = (accountEnabledObj == null) ? false : accountEnabledObj.booleanValue();
if (accountEnabled) {
mPopupTexture.setNeedsDraw();
setPosition(clampedX, y);
- // Fade in the menu if it is not already visible, otherwise snap to the new location.
+ // Fade in the menu if it is not already visible, otherwise snap to the
+ // new location.
// if (!mShow) {
mShow = true;
setHidden(false);
backing.eraseColor(0);
mBackground.draw(canvas, mBackgroundRect, SRC_PAINT);
- // Stamp the popup triangle over the appropriate region ignoring alpha.
+ // Stamp the popup triangle over the appropriate region ignoring
+ // alpha.
Bitmap triangle = mTriangleBottom;
canvas.drawBitmap(triangle, mTriangleX, height - triangle.getHeight() - 1, SRC_PAINT);
@SuppressWarnings("unchecked")
private final ReferenceQueue mUnreferencedTextureQueue = new ReferenceQueue();
- // Frame time in milliseconds and delta since last frame in seconds. Uses SystemClock.getUptimeMillis().
+ // Frame time in milliseconds and delta since last frame in seconds. Uses
+ // SystemClock.getUptimeMillis().
private long mFrameTime = 0;
private float mFrameInterval = 0.0f;
private float mAlpha;
private void clearTextureArray(SparseArray<ResourceTexture> array) {
/*
- * final int size = array.size(); for (int i = 0; i < size; ++i) { ResourceTexture texture = array.get(array.keyAt(i)); if
- * (texture != null) { texture.clear(); } }
+ * final int size = array.size(); for (int i = 0; i < size; ++i) {
+ * ResourceTexture texture = array.get(array.keyAt(i)); if (texture !=
+ * null) { texture.clear(); } }
*/
array.clear();
}
int height = bitmap.getHeight();
texture.mWidth = width;
texture.mHeight = height;
- // Create a padded bitmap if the natural size is not a power of 2.
+ // Create a padded bitmap if the natural size is not a power of
+ // 2.
if (!Shared.isPowerOf2(width) || !Shared.isPowerOf2(height)) {
int paddedWidth = Shared.nextPowerOf2(width);
int paddedHeight = Shared.nextPowerOf2(height);
canvas.drawBitmap(bitmap, 0, 0, null);
bitmap.recycle();
bitmap = padded;
- // Store normalized width and height for use in texture coordinates.
+ // Store normalized width and height for use in texture
+ // coordinates.
texture.mNormalizedWidth = (float) width / (float) paddedWidth;
texture.mNormalizedHeight = (float) height / (float) paddedHeight;
} else {
texture.mState = Texture.STATE_LOADING;
// Push the texture onto the load input queue.
- Deque<Texture> inputQueue = (texture.isUncachedVideo()) ? sLoadInputQueueVideo : (texture.isCached()) ? sLoadInputQueueCached : sLoadInputQueue;;
+ Deque<Texture> inputQueue = (texture.isUncachedVideo()) ? sLoadInputQueueVideo
+ : (texture.isCached()) ? sLoadInputQueueCached : sLoadInputQueue;
+ ;
synchronized (inputQueue) {
if (highPriority) {
inputQueue.addFirst(texture);
gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_RGB, GL11.GL_INTERPOLATE);
gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_ALPHA, GL11.GL_INTERPOLATE);
- // Specify the interpolation factor via the alpha component of GL_TEXTURE_ENV_COLOR.
+ // Specify the interpolation factor via the alpha component of
+ // GL_TEXTURE_ENV_COLOR.
final float[] color = { 1f, 1f, 1f, ratio };
gl.glTexEnvfv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, color, 0);
gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_RGB, GL11.GL_INTERPOLATE);
gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_COMBINE_ALPHA, GL11.GL_INTERPOLATE);
- // Specify the interpolation factor via the alpha component of GL_TEXTURE_ENV_COLOR.
+ // Specify the interpolation factor via the alpha component of
+ // GL_TEXTURE_ENV_COLOR.
final float[] color = { 1f, 1f, 1f, ratio };
gl.glTexEnvfv(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_COLOR, color, 0);
gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_LINEAR);
GLUtils.texImage2D(GL11.GL_TEXTURE_2D, 0, bitmap, 0);
glError = gl.glGetError();
-
+
bitmap.recycle();
if (glError == GL11.GL_OUT_OF_MEMORY) {
handleLowMemory();
}
if (glError != GL11.GL_NO_ERROR) {
- // There was an error, we need to retry this texture at some later time
+ // There was an error, we need to retry this texture at some
+ // later time
Log.i(TAG, "Texture creation fail, glError " + glError);
texture.mId = 0;
texture.mBitmap = null;
if (isDirty) {
requestRender();
}
-
+
// Clear the depth buffer.
gl.glClear(GL11.GL_DEPTH_BUFFER_BIT);
gl.glEnable(GL11.GL_SCISSOR_TEST);
layer.renderOpaque(this, gl);
}
}
-
+
// Run the blended pass.
gl.glEnable(GL11.GL_BLEND);
final ArrayList<Layer> blendedList = lists.blendedList;
}
}
- /** Called when the OpenGL surface is recreated without destroying the context. */
+ /**
+ * Called when the OpenGL surface is recreated without destroying the
+ * context.
+ */
public void onSurfaceChanged(GL10 gl1, int width, int height) {
GL11 gl = (GL11) gl1;
mFirstDraw = false;
gl.glMatrixMode(GL11.GL_MODELVIEW);
}
- /** Called when the context is created, possibly after automatic destruction. */
+ /**
+ * Called when the context is created, possibly after automatic destruction.
+ */
public void onSurfaceCreated(GL10 gl1, EGLConfig config) {
// Clear the resource texture cache.
clearCache();
gl.glEnable(GL11.GL_TEXTURE_2D);
gl.glTexEnvf(GL11.GL_TEXTURE_ENV, GL11.GL_TEXTURE_ENV_MODE, GL11.GL_REPLACE);
- // Set up state for multitexture operations. Since multitexture is currently used
- // only for layered crossfades the needed state can be factored out into one-time
- // initialization. This section may need to be folded into drawMixed2D() if multitexture
+ // Set up state for multitexture operations. Since multitexture is
+ // currently used
+ // only for layered crossfades the needed state can be factored out into
+ // one-time
+ // initialization. This section may need to be folded into drawMixed2D()
+ // if multitexture
// is used for other effects.
// Enable Vertex Arrays
}
// Wait for the render thread to process this event.
if (mTouchEventQueue.size() > 8 && event.getAction() == MotionEvent.ACTION_MOVE)
- return true;
+ return true;
synchronized (mTouchEventQueue) {
MotionEvent eventCopy = MotionEvent.obtain(event);
mTouchEventQueue.addLast(eventCopy);
/*
* if (mGL == null) { return; }
*
- * // Wait for the render thread to process this event. try { synchronized (this) { mCurrentFocusEventGain = gainFocus;
- * mCurrentFocusEventDirection = direction; mCurrentEventType = EVENT_FOCUS; do { wait(); } while (mCurrentEventType !=
- * EVENT_NONE); } } catch (InterruptedException e) { // Stop waiting for the render thread if interrupted. }
+ * // Wait for the render thread to process this event. try {
+ * synchronized (this) { mCurrentFocusEventGain = gainFocus;
+ * mCurrentFocusEventDirection = direction; mCurrentEventType =
+ * EVENT_FOCUS; do { wait(); } while (mCurrentEventType != EVENT_NONE);
+ * } } catch (InterruptedException e) { // Stop waiting for the render
+ * thread if interrupted. }
*/
requestRender();
}
public void run() {
Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- Deque<Texture> inputQueue = (sVideoTextureLoadThread == this) ? sLoadInputQueueVideo : ((sCachedTextureLoadThread == this) ? sLoadInputQueueCached : sLoadInputQueue);
+ Deque<Texture> inputQueue = (sVideoTextureLoadThread == this) ? sLoadInputQueueVideo
+ : ((sCachedTextureLoadThread == this) ? sLoadInputQueueCached : sLoadInputQueue);
Deque<Texture> outputQueue = sLoadOutputQueue;
try {
for (;;) {
import android.content.Context;
import android.location.Address;
+import android.location.Criteria;
import android.location.Geocoder;
+import android.location.Location;
+import android.location.LocationManager;
import android.os.Process;
public final class ReverseGeocoder extends Thread {
private static final int MAX_COUNTRY_NAME_LENGTH = 8;
- // If two points are within 50 miles of each other, use "Around Palo Alto, CA" or "Around Mountain View, CA".
- // instead of directly jumping to the next level and saying "California, US".
+ // If two points are within 20 miles of each other, use
+ // "Around Palo Alto, CA" or "Around Mountain View, CA".
+ // instead of directly jumping to the next level and saying
+ // "California, US".
private static final int MAX_LOCALITY_MILE_RANGE = 20;
private static final Deque<MediaSet> sQueue = new Deque<MediaSet>();
private static final DiskCache sGeoCache = new DiskCache("geocoder-cache");
private static final String TAG = "ReverseGeocoder";
+ private static Criteria LOCATION_CRITERIA = new Criteria();
+ private static Address sCurrentAddress; // last known address
+
+ static {
+ LOCATION_CRITERIA.setAccuracy(Criteria.ACCURACY_COARSE);
+ LOCATION_CRITERIA.setPowerRequirement(Criteria.NO_REQUIREMENT);
+ LOCATION_CRITERIA.setBearingRequired(false);
+ LOCATION_CRITERIA.setSpeedRequired(false);
+ LOCATION_CRITERIA.setAltitudeRequired(false);
+ }
private Geocoder mGeocoder;
private final Context mContext;
public void enqueue(MediaSet set) {
Deque<MediaSet> inQueue = sQueue;
synchronized (inQueue) {
- inQueue.addLast(set);
+ inQueue.addFirst(set);
inQueue.notify();
}
}
protected String computeMostGranularCommonLocation(final MediaSet set) {
// The overall min and max latitudes and longitudes of the set.
double setMinLatitude = set.mMinLatLatitude;
- double setMinLongitude = set.mMinLonLongitude;
+ double setMinLongitude = set.mMinLatLongitude;
double setMaxLatitude = set.mMaxLatLatitude;
- double setMaxLongitude = set.mMaxLonLongitude;
+ double setMaxLongitude = set.mMaxLatLongitude;
+ if (Math.abs(set.mMaxLatLatitude - set.mMinLatLatitude) < Math.abs(set.mMaxLonLongitude - set.mMinLonLongitude)) {
+ setMinLatitude = set.mMinLonLatitude;
+ setMinLongitude = set.mMinLonLongitude;
+ setMaxLatitude = set.mMaxLonLatitude;
+ setMaxLongitude = set.mMaxLonLongitude;
+ }
Address addr1 = lookupAddress(setMinLatitude, setMinLongitude);
Address addr2 = lookupAddress(setMaxLatitude, setMaxLongitude);
+ if (addr1 == null)
+ addr1 = addr2;
+ if (addr2 == null)
+ addr2 = addr1;
if (addr1 == null || addr2 == null) {
return null;
}
- // Look at the first line of the address.
- String closestCommonLocation = valueIfEqual(addr1.getAddressLine(0), addr2.getAddressLine(0));
- if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
- return closestCommonLocation;
+ // Get current location, we decide the granularity of the string based
+ // on this.
+ LocationManager locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+ Location location = null;
+ List<String> providers = locationManager.getAllProviders();
+ for (int i = 0; i < providers.size(); ++i) {
+ String provider = providers.get(i);
+ location = (provider != null) ? locationManager.getLastKnownLocation(provider) : null;
+ if (location != null)
+ break;
}
-
- // Compare thoroughfare (street address) next.
- closestCommonLocation = valueIfEqual(addr1.getThoroughfare(), addr2.getThoroughfare());
- if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
- return closestCommonLocation;
+ String currentCity = "";
+ String currentAdminArea = "";
+ String currentCountry = Locale.getDefault().getCountry();
+ if (location != null) {
+ Address currentAddress = lookupAddress(location.getLatitude(), location.getLongitude());
+ if (currentAddress == null) {
+ currentAddress = sCurrentAddress;
+ } else {
+ sCurrentAddress = currentAddress;
+ }
+ if (currentAddress != null && currentAddress.getCountryCode() != null) {
+ currentCity = currentAddress.getLocality();
+ currentCountry = currentAddress.getCountryCode();
+ currentAdminArea = currentAddress.getAdminArea();
+ }
}
- // Feature names can sometimes be useful like "Golden Gate Bridge" but can also be
- // degenerate for street address (like just the house number).
- closestCommonLocation = valueIfEqual(addr1.getFeatureName(), addr2.getFeatureName());
- if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
- try {
- Integer.parseInt(closestCommonLocation);
- closestCommonLocation = null;
- } catch (final NumberFormatException nfe) {
- // The feature name is not an integer, allow and continue.
+ String closestCommonLocation = null;
+
+ if (currentCity.equals(addr1.getLocality()) || currentCity.equals(addr2.getLocality())) {
+ String otherCity = currentCity;
+ if (currentCity.equals(addr1.getLocality())) {
+ otherCity = addr2.getLocality();
+ if ("null".equals(otherCity) || otherCity == null) {
+ otherCity = addr2.getAdminArea();
+ if (!currentCountry.equals(addr2.getCountryCode())) {
+ otherCity += " " + addr2.getCountryCode();
+ }
+ }
+ addr2 = addr1;
+ } else {
+ otherCity = addr1.getLocality();
+ if ("null".equals(otherCity) || otherCity == null) {
+ otherCity = addr1.getAdminArea() + " " + addr1.getCountryCode();
+ ;
+ if (!currentCountry.equals(addr1.getCountryCode())) {
+ otherCity += " " + addr1.getCountryCode();
+ }
+ }
+ addr1 = addr2;
+ }
+ closestCommonLocation = valueIfEqual(addr1.getAddressLine(0), addr2.getAddressLine(0));
+ if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
+ if (!currentCity.equals(otherCity)) {
+ closestCommonLocation += " - " + otherCity;
+ }
+ return closestCommonLocation;
+ }
+
+ // Compare thoroughfare (street address) next.
+ closestCommonLocation = valueIfEqual(addr1.getThoroughfare(), addr2.getThoroughfare());
+ if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
return closestCommonLocation;
}
}
closestCommonLocation = valueIfEqual(addr1.getLocality(), addr2.getLocality());
if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
String adminArea = addr1.getAdminArea();
- if (adminArea != null && adminArea.length() > 0) {
- closestCommonLocation += ", " + adminArea;
+ String countryCode = addr1.getCountryCode();
+ if (adminArea != null && adminArea.length() > 0 && !adminArea.equals(currentAdminArea)) {
+ if (!countryCode.equals(currentCountry)) {
+ closestCommonLocation += ", " + adminArea + " " + countryCode;
+ } else {
+ closestCommonLocation += ", " + adminArea;
+ }
}
return closestCommonLocation;
}
- // Just choose one of the localities if within a 50 mile radius.
- int distance = (int) LocationMediaFilter.toMile(LocationMediaFilter.distanceBetween(setMinLatitude, setMinLongitude,
- setMaxLatitude, setMaxLongitude));
- if (distance < MAX_LOCALITY_MILE_RANGE) {
- // Try each of the points and just return the first one to have a valid address.
- Address minLatAddress = lookupAddress(setMinLatitude, set.mMinLatLongitude);
- closestCommonLocation = getLocalityAdminForAddress(minLatAddress, true);
- if (closestCommonLocation != null) {
- return closestCommonLocation;
+ // If the admin area is the same as the current location, we hide it and
+ // instead show the city name.
+ if (currentAdminArea.equals(addr1.getAdminArea()) || currentAdminArea.equals(addr2.getAdminArea())) {
+ String addr1Locality = addr2.getLocality();
+ String addr2Locality = addr2.getLocality();
+ if (addr1Locality == null || "null".equals(addr1Locality)) {
+ addr1Locality = addr2Locality;
}
- Address minLonAddress = lookupAddress(set.mMinLonLatitude, setMinLongitude);
- closestCommonLocation = getLocalityAdminForAddress(minLonAddress, true);
- if (closestCommonLocation != null) {
+ if (addr2Locality == null || "null".equals(addr2Locality)) {
+ addr2Locality = addr1Locality;
+ }
+ if (addr1Locality != null && !"null".equals(addr1Locality)) {
+ closestCommonLocation = addr1.getLocality() + " - " + addr2.getLocality();
return closestCommonLocation;
}
- Address maxLatAddress = lookupAddress(setMaxLatitude, set.mMaxLatLongitude);
- closestCommonLocation = getLocalityAdminForAddress(maxLatAddress, true);
+ }
+
+ // Just choose one of the localities if within a MAX_LOCALITY_MILE_RANGE
+ // mile radius.
+ int distance = (int) LocationMediaFilter.toMile(LocationMediaFilter.distanceBetween(setMinLatitude, setMinLongitude,
+ setMaxLatitude, setMaxLongitude));
+ if (distance < MAX_LOCALITY_MILE_RANGE) {
+ // Try each of the points and just return the first one to have a
+ // valid address.
+ closestCommonLocation = getLocalityAdminForAddress(addr1, true);
if (closestCommonLocation != null) {
return closestCommonLocation;
}
- Address maxLonAddress = lookupAddress(set.mMaxLonLatitude, setMaxLongitude);
- closestCommonLocation = getLocalityAdminForAddress(maxLonAddress, true);
+ closestCommonLocation = getLocalityAdminForAddress(addr2, true);
if (closestCommonLocation != null) {
return closestCommonLocation;
}
closestCommonLocation = valueIfEqual(addr1.getAdminArea(), addr2.getAdminArea());
if (closestCommonLocation != null && !("null".equals(closestCommonLocation))) {
String countryCode = addr1.getCountryCode();
- if (countryCode != null && countryCode.length() > 0) {
- closestCommonLocation += ", " + countryCode;
+ if (!countryCode.equals(currentCountry)) {
+ if (countryCode != null && countryCode.length() > 0) {
+ closestCommonLocation += " " + countryCode;
+ }
}
return closestCommonLocation;
}
// There is no intersection, let's choose a nicer name.
String addr1Country = addr1.getCountryName();
String addr2Country = addr2.getCountryName();
+ if (addr1Country == null)
+ addr1Country = addr1.getCountryCode();
+ if (addr2Country == null)
+ addr2Country = addr2.getCountryCode();
+ if (addr1Country == null || addr2Country == null)
+ return null;
if (addr1Country.length() > MAX_COUNTRY_NAME_LENGTH || addr2Country.length() > MAX_COUNTRY_NAME_LENGTH) {
closestCommonLocation = addr1.getCountryCode() + " - " + addr2.getCountryCode();
} else {
Address addr = lookupAddress(latitude, longitude);
if (addr != null) {
- // Look at the first line of the address, thorough fare and feature name in order and pick one.
+ // Look at the first line of the address, thorough fare and feature
+ // name in order and pick one.
location = addr.getAddressLine(0);
if (location != null && !("null".equals(location))) {
numDetails++;
String localityAdminStr = addr.getLocality();
if (localityAdminStr != null && !("null".equals(localityAdminStr))) {
if (approxLocation) {
- // TODO: Uncomment these lines as soon as we may translations for R.string.around.
- // localityAdminStr = mContext.getResources().getString(R.string.around) + " " + localityAdminStr;
+ // TODO: Uncomment these lines as soon as we may translations
+ // for R.string.around.
+ // localityAdminStr =
+ // mContext.getResources().getString(R.string.around) + " " +
+ // localityAdminStr;
}
String adminArea = addr.getAdminArea();
if (adminArea != null && adminArea.length() > 0) {
byte[] cachedLocation = sGeoCache.get(locationKey, 0);
Address address = null;
if (cachedLocation == null || cachedLocation.length == 0) {
- List<Address> addresses = mGeocoder.getFromLocation(latitude, longitude, 1);
- if (!addresses.isEmpty()) {
- address = addresses.get(0);
- ByteArrayOutputStream bos = new ByteArrayOutputStream();
- DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(bos, 256));
- Locale locale = address.getLocale();
- Utils.writeUTF(dos, locale.getLanguage());
- Utils.writeUTF(dos, locale.getCountry());
- Utils.writeUTF(dos, locale.getVariant());
-
- Utils.writeUTF(dos, address.getThoroughfare());
- int numAddressLines = address.getMaxAddressLineIndex();
- dos.writeInt(numAddressLines);
- for (int i = 0; i < numAddressLines; ++i) {
- Utils.writeUTF(dos, address.getAddressLine(i));
+ try {
+ List<Address> addresses = mGeocoder.getFromLocation(latitude, longitude, 1);
+ if (!addresses.isEmpty()) {
+ address = addresses.get(0);
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(bos, 256));
+ Locale locale = address.getLocale();
+ Utils.writeUTF(dos, locale.getLanguage());
+ Utils.writeUTF(dos, locale.getCountry());
+ Utils.writeUTF(dos, locale.getVariant());
+
+ Utils.writeUTF(dos, address.getThoroughfare());
+ int numAddressLines = address.getMaxAddressLineIndex();
+ dos.writeInt(numAddressLines);
+ for (int i = 0; i < numAddressLines; ++i) {
+ Utils.writeUTF(dos, address.getAddressLine(i));
+ }
+ Utils.writeUTF(dos, address.getFeatureName());
+ Utils.writeUTF(dos, address.getLocality());
+ Utils.writeUTF(dos, address.getAdminArea());
+ Utils.writeUTF(dos, address.getSubAdminArea());
+
+ Utils.writeUTF(dos, address.getCountryName());
+ Utils.writeUTF(dos, address.getCountryCode());
+ Utils.writeUTF(dos, address.getPostalCode());
+ Utils.writeUTF(dos, address.getPhone());
+ Utils.writeUTF(dos, address.getUrl());
+
+ dos.flush();
+ sGeoCache.put(locationKey, bos.toByteArray());
+ dos.close();
}
- Utils.writeUTF(dos, address.getFeatureName());
- Utils.writeUTF(dos, address.getLocality());
- Utils.writeUTF(dos, address.getAdminArea());
- Utils.writeUTF(dos, address.getSubAdminArea());
-
- Utils.writeUTF(dos, address.getCountryName());
- Utils.writeUTF(dos, address.getCountryCode());
- Utils.writeUTF(dos, address.getPostalCode());
- Utils.writeUTF(dos, address.getPhone());
- Utils.writeUTF(dos, address.getUrl());
-
- dos.flush();
- sGeoCache.put(locationKey, bos.toByteArray());
- dos.close();
+ } finally {
+
}
} else {
// Parsing the address from the byte stream.
public boolean onKeyUp(int keyCode, KeyEvent event) {
return false;
}
-
+
public void handleLowMemory() {
-
+
}
- }
+}
public static boolean isPowerOf2(int n) {
return (n & -n) == n;
}
-
+
/**
- * @param i : running variable
+ * @param i
+ * : running variable
* @return 0, +1, -1, +2, -2, +3, -3 ..
*/
public static int midPointIterator(int i) {
if (i != 0) {
- int tick = ((i-1)/2) + 1;
- int pass = ((i-1)%2 == 0) ? 1 : -1;
+ int tick = ((i - 1) / 2) + 1;
+ int pass = ((i - 1) % 2 == 0) ? 1 : -1;
return tick * pass;
}
return 0;
}
return value;
}
-
- public static long clamp(long value, long min, long max) {
- if (value < min) {
+
+ public static long clamp(long value, long min, long max) {
+ if (value < min) {
value = min;
} else if (value > max) {
value = max;
}
return value;
- }
+ }
public static float scaleToFit(float srcWidth, float srcHeight, float outerWidth, float outerHeight, boolean clipToFit) {
float scaleX = outerWidth / srcWidth;
return (clipToFit ? scaleX > scaleY : scaleX < scaleY) ? scaleX : scaleY;
}
- // Returns an angle between 0 and 360 degrees independent of the input angle.
+ // Returns an angle between 0 and 360 degrees independent of the input
+ // angle.
public static float normalizePositive(float angleToRotate) {
if (angleToRotate == 0.0f) {
return 0.0f;
}
return ExifInterface.ORIENTATION_NORMAL;
}
-
+
public static float exifOrientationToDegrees(int exifOrientation) {
- if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
- return 90;
- } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
- return 180;
- } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
- return 270;
- }
- return 0;
+ if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_90) {
+ return 90;
+ } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_180) {
+ return 180;
+ } else if (exifOrientation == ExifInterface.ORIENTATION_ROTATE_270) {
+ return 270;
+ }
+ return 0;
}
}
public float getBaselineHeight() {
return mBaselineHeight;
}
-
+
@Override
public boolean isCached() {
return true;
public void shutdown() {
}
-
+
public boolean isSingleImage() {
- return mSingleUri;
+ return mSingleUri;
}
private static boolean isSingleImageMode(String uriString) {
for (int i = 1; i < numItems; ++i) {
MediaItem thisItem = items.get(i);
String filePath = Uri.fromFile(new File(thisItem.mFilePath)).toString();
- if (item.mId == thisItem.mId || ((item.mContentUri != null && thisItem.mContentUri != null) && (item.mContentUri.equals(thisItem.mContentUri)
- || item.mContentUri.equals(filePath)))) {
+ if (item.mId == thisItem.mId
+ || ((item.mContentUri != null && thisItem.mContentUri != null) && (item.mContentUri
+ .equals(thisItem.mContentUri) || item.mContentUri.equals(filePath)))) {
items.remove(thisItem);
--parentSet.mNumItemsLoaded;
break;
final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
final ContentResolver cr = mContext.getContentResolver();
String where = null;
- Cursor cursor = cr.query(uriImages, CacheService.PROJECTION_IMAGES, where, null, null);
- if (cursor != null && cursor.moveToFirst()) {
- parentSet.setNumExpectedItems(cursor.getCount());
- do {
- if (Thread.interrupted()) {
- return;
+ try {
+ Cursor cursor = cr.query(uriImages, CacheService.PROJECTION_IMAGES, where, null, null);
+ if (cursor != null && cursor.moveToFirst()) {
+ parentSet.setNumExpectedItems(cursor.getCount());
+ do {
+ if (Thread.interrupted()) {
+ return;
+ }
+ final MediaItem item = new MediaItem();
+ CacheService.populateMediaItemFromCursor(item, cr, cursor, CacheService.BASE_CONTENT_STRING_IMAGES);
+ feed.addItemToMediaSet(item, parentSet);
+ } while (cursor.moveToNext());
+ if (cursor != null) {
+ cursor.close();
+ cursor = null;
}
- final MediaItem item = new MediaItem();
- CacheService.populateMediaItemFromCursor(item, cr, cursor, CacheService.BASE_CONTENT_STRING_IMAGES);
- feed.addItemToMediaSet(item, parentSet);
- } while (cursor.moveToNext());
- if (cursor != null) {
- cursor.close();
- cursor = null;
+ parentSet.updateNumExpectedItems();
+ parentSet.generateTitle(true);
}
- parentSet.updateNumExpectedItems();
- parentSet.generateTitle(true);
+ } catch (Exception e) {
+ // If the database operation failed for any reason.
+ ;
}
} else {
CacheService.loadMediaItemsIntoMediaFeed(feed, parentSet, rangeStart, rangeEnd, true, true);
import android.util.Log;
/**
- * A variant of MergeCursor that sorts the cursors being merged. If decent performance is ever obtained, it can be put back under
- * android.database.
+ * A variant of MergeCursor that sorts the cursors being merged. If decent
+ * performance is ever obtained, it can be put back under android.database.
*/
public class SortCursor extends AbstractCursor {
private static final String TAG = "SortCursor";
return true;
/*
- * Find the right cursor Because the client of this cursor (the listadapter/view) tends to jump around in the cursor
- * somewhat, a simple cache strategy is used to avoid having to search all cursors from the start. TODO: investigate
- * strategies for optimizing random access and reverse-order access.
+ * Find the right cursor Because the client of this cursor (the
+ * listadapter/view) tends to jump around in the cursor somewhat, a
+ * simple cache strategy is used to avoid having to search all cursors
+ * from the start. TODO: investigate strategies for optimizing random
+ * access and reverse-order access.
*/
int cache_entry = newPosition % ROWCACHESIZE;
private static final Paint sPaint = new Paint();
public static int computeTextWidthForConfig(String string, Config config) {
- return computeTextWidthForConfig(config.fontSize, config.bold ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT, string);
+ return computeTextWidthForConfig(config.fontSize, config.bold ? Typeface.DEFAULT_BOLD : Typeface.DEFAULT, string);
}
-
+
public static int computeTextWidthForConfig(float textSize, Typeface typeface, String string) {
Paint paint = sPaint;
synchronized (paint) {
paint.setTypeface(typeface);
paint.setTextSize(textSize);
// 10 pixel buffer to compensate for the shade at the end.
- return (int)(10.0f * Gallery.PIXEL_DENSITY) + (int)FloatMath.ceil(paint.measureText(string));
+ return (int) (10.0f * Gallery.PIXEL_DENSITY) + (int) FloatMath.ceil(paint.measureText(string));
}
}
public StringTexture(String string, Config config) {
this(string, config, config.width, config.height);
}
-
+
public StringTexture(String string, Config config, int width, int height) {
mString = string;
mConfig = config;
return 0;
}
}
-
+
@Override
public boolean isCached() {
return true;
int descent = metrics.descent + padding;
int backWidth = mWidth;
int backHeight = mHeight;
-
+
String string = mString;
Rect bounds = new Rect();
paint.getTextBounds(string, 0, string.length(), bounds);
-
+
if (config.sizeMode == Config.SIZE_BOUNDS_TO_TEXT) {
// do something else
backWidth = bounds.width() + 2 * padding;
int height = descent - ascent;
backHeight = height + padding;
- }
+ }
if (backWidth <= 0 || backHeight <= 0)
return null;
Bitmap bitmap = Bitmap.createBitmap(backWidth, backHeight, bmConfig);
Canvas canvas = new Canvas(bitmap);
// for top
- int x = (config.xalignment == Config.ALIGN_LEFT) ? padding
- : (config.xalignment == Config.ALIGN_RIGHT ? backWidth - padding : backWidth / 2);
+ int x = (config.xalignment == Config.ALIGN_LEFT) ? padding : (config.xalignment == Config.ALIGN_RIGHT ? backWidth - padding
+ : backWidth / 2);
int y = (config.yalignment == Config.ALIGN_TOP) ? -metrics.top + padding
: ((config.yalignment == Config.ALIGN_BOTTOM) ? (backHeight - descent)
: ((int) backHeight - (descent + ascent)) / 2);
// bitmap.eraseColor(0xff00ff00);
canvas.drawText(stringToDraw, x, y, paint);
-
+
if (bounds.width() > backWidth && config.overflowMode == Config.OVERFLOW_FADE) {
- // Fade the right edge of the string if the text overflows. TODO: BIDI text should fade on the left.
+ // Fade the right edge of the string if the text overflows. TODO:
+ // BIDI text should fade on the left.
float gradientLeft = backWidth - Config.FADE_WIDTH;
- LinearGradient gradient = new LinearGradient(gradientLeft, 0, backWidth, 0, 0xffffffff,
- 0x00ffffff, Shader.TileMode.CLAMP);
+ LinearGradient gradient = new LinearGradient(gradientLeft, 0, backWidth, 0, 0xffffffff, 0x00ffffff,
+ Shader.TileMode.CLAMP);
paint = new Paint();
paint.setShader(gradient);
paint.setDither(true);
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
canvas.drawRect(gradientLeft, 0, backWidth, backHeight, paint);
}
-
+
mBaselineHeight = padding + metrics.bottom;
return bitmap;
}
-
+
public static final class Config {
public static final int SIZE_EXACT = 0;
public static final int SIZE_TEXT_TO_BOUNDS = 1;
public static final int SIZE_BOUNDS_TO_TEXT = 2;
-
+
public static final int OVERFLOW_CLIP = 0;
public static final int OVERFLOW_ELLIPSIZE = 1;
public static final int OVERFLOW_FADE = 2;
-
+
public static final int ALIGN_HCENTER = 0;
public static final int ALIGN_LEFT = 1;
public static final int ALIGN_RIGHT = 2;
public static final int ALIGN_TOP = 3;
public static final int ALIGN_BOTTOM = 4;
public static final int ALIGN_VCENTER = 5;
-
+
private static final int FADE_WIDTH = 30;
-
+
public static final Config DEFAULT_CONFIG_SCALED = new Config();
public static final Config DEFAULT_CONFIG_TRUNCATED = new Config(SIZE_TEXT_TO_BOUNDS);
public float g = 1f;
public float b = 1f;
public float a = 1f;
- public int shadowRadius = 4 * (int)Gallery.PIXEL_DENSITY;
+ public int shadowRadius = 4 * (int) Gallery.PIXEL_DENSITY;
public boolean underline = false;
public boolean bold = false;
public boolean italic = false;
public boolean strikeThrough = false;
- public int width = 256; // TODO: there is no good default for this, require explicit specification.
+ public int width = 256; // TODO: there is no good default for this,
+ // require explicit specification.
public int height = 32;
public int xalignment = ALIGN_LEFT;
public int yalignment = ALIGN_VCENTER;
public boolean isCached() {
return false;
}
-
+
public final void clear() {
mId = 0;
mState = STATE_UNLOADED;
mBitmap = null;
}
}
-
+
public final boolean isLoaded() {
return mState == STATE_LOADED;
}
mBackgroundRect = new Rect();
SRC_PAINT.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
}
-
+
public void regenerateStringsForContext(Context context) {
// Create textures for month names.
String[] months = context.getResources().getStringArray(R.array.months_abbreviated);
if (month != lastMonth) {
lastMonth = month;
lastDayBlock = -1;
- marker = new Marker(dx, time.getTimeInMillis(), year, month, dayBlock,
- Marker.TYPE_MONTH, increment);
+ marker = new Marker(dx, time.getTimeInMillis(), year, month, dayBlock, Marker.TYPE_MONTH, increment);
dx = addMarker(marker);
} else if (dayBlock != lastDayBlock) {
lastDayBlock = dayBlock;
if (dayBlock != 0) {
- marker = new Marker(dx, time.getTimeInMillis(), year, month, dayBlock,
- Marker.TYPE_DAY, increment);
+ marker = new Marker(dx, time.getTimeInMillis(), year, month, dayBlock, Marker.TYPE_DAY, increment);
dx = addMarker(marker);
}
} else {
}
/*
- * private float getKnobXForPosition(float position) { return position * (mTotalWidth - mKnob.getWidth()); }
+ * private float getKnobXForPosition(float position) { return position *
+ * (mTotalWidth - mKnob.getWidth()); }
*
- * private float getPositionForKnobX(float knobX) { return Math.max(0f, Math.min(1f, knobX / (mTotalWidth - mKnob.getWidth())));
- * }
+ * private float getPositionForKnobX(float knobX) { return Math.max(0f,
+ * Math.min(1f, knobX / (mTotalWidth - mKnob.getWidth()))); }
*
- * private float getScrollForPosition(float position) { return position * (mTotalWidth - mWidth);// - (1f - 2f * position) *
- * MARKER_SPACING_PIXELS; }
+ * private float getScrollForPosition(float position) { return position *
+ * (mTotalWidth - mWidth);// - (1f - 2f * position) * MARKER_SPACING_PIXELS;
+ * }
*/
private float getScrollForPosition(float position) {
}
HttpEntity entity = httpResponse.getEntity();
if (entity != null) {
- // Wrap the entity input stream in a GZIP decoder if necessary.
+ // Wrap the entity input stream in a GZIP decoder if
+ // necessary.
contentInput = entity.getContent();
}
}
return null;
}
}
-
+
public static String writeHttpDataInDirectory(Context context, String uri, String path) {
long crc64 = Utils.Crc64Long(uri);
if (!isCached(crc64, 1024)) {
}
}
}
-
+
public static void invalidateCache(long crc64, int maxResolution) {
String file = createFilePathFromCrc64(crc64, maxResolution);
if (file != null && crc64 != 0) {
package com.cooliris.media;
-
import android.app.ProgressDialog;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
*/
public class Util {
private static final String TAG = "db.Util";
- private static final String MAPS_PACKAGE_NAME =
- "com.google.android.apps.maps";
- private static final String MAPS_CLASS_NAME =
- "com.google.android.maps.MapsActivity";
-
+ private static final String MAPS_PACKAGE_NAME = "com.google.android.apps.maps";
+ private static final String MAPS_CLASS_NAME = "com.google.android.maps.MapsActivity";
private Util() {
}
public static Bitmap rotate(Bitmap b, int degrees) {
if (degrees != 0 && b != null) {
Matrix m = new Matrix();
- m.setRotate(degrees,
- (float) b.getWidth() / 2, (float) b.getHeight() / 2);
+ m.setRotate(degrees, (float) b.getWidth() / 2, (float) b.getHeight() / 2);
try {
- Bitmap b2 = Bitmap.createBitmap(
- b, 0, 0, b.getWidth(), b.getHeight(), m, true);
+ Bitmap b2 = Bitmap.createBitmap(b, 0, 0, b.getWidth(), b.getHeight(), m, true);
if (b != b2) {
b.recycle();
b = b2;
return b;
}
- public static Bitmap transform(Matrix scaler,
- Bitmap source,
- int targetWidth,
- int targetHeight,
- boolean scaleUp) {
+ public static Bitmap transform(Matrix scaler, Bitmap source, int targetWidth, int targetHeight, boolean scaleUp) {
int deltaX = source.getWidth() - targetWidth;
int deltaY = source.getHeight() - targetHeight;
if (!scaleUp && (deltaX < 0 || deltaY < 0)) {
/*
* In this case the bitmap is smaller, at least in one dimension,
- * than the target. Transform it by placing as much of the image
- * as possible into the target and leaving the top/bottom or
- * left/right (or both) black.
+ * than the target. Transform it by placing as much of the image as
+ * possible into the target and leaving the top/bottom or left/right
+ * (or both) black.
*/
- Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight,
- Bitmap.Config.ARGB_8888);
+ Bitmap b2 = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(b2);
int deltaXHalf = Math.max(0, deltaX / 2);
int deltaYHalf = Math.max(0, deltaY / 2);
- Rect src = new Rect(
- deltaXHalf,
- deltaYHalf,
- deltaXHalf + Math.min(targetWidth, source.getWidth()),
- deltaYHalf + Math.min(targetHeight, source.getHeight()));
- int dstX = (targetWidth - src.width()) / 2;
+ Rect src = new Rect(deltaXHalf, deltaYHalf, deltaXHalf + Math.min(targetWidth, source.getWidth()), deltaYHalf
+ + Math.min(targetHeight, source.getHeight()));
+ int dstX = (targetWidth - src.width()) / 2;
int dstY = (targetHeight - src.height()) / 2;
- Rect dst = new Rect(
- dstX,
- dstY,
- targetWidth - dstX,
- targetHeight - dstY);
+ Rect dst = new Rect(dstX, dstY, targetWidth - dstX, targetHeight - dstY);
c.drawBitmap(source, src, dst, null);
return b2;
}
float bitmapHeightF = source.getHeight();
float bitmapAspect = bitmapWidthF / bitmapHeightF;
- float viewAspect = (float) targetWidth / targetHeight;
+ float viewAspect = (float) targetWidth / targetHeight;
if (bitmapAspect > viewAspect) {
float scale = targetHeight / bitmapHeightF;
Bitmap b1;
if (scaler != null) {
// this is used for minithumb and crop, so we want to filter here.
- b1 = Bitmap.createBitmap(source, 0, 0,
- source.getWidth(), source.getHeight(), scaler, true);
+ b1 = Bitmap.createBitmap(source, 0, 0, source.getWidth(), source.getHeight(), scaler, true);
} else {
b1 = source;
}
int dx1 = Math.max(0, b1.getWidth() - targetWidth);
int dy1 = Math.max(0, b1.getHeight() - targetHeight);
- Bitmap b2 = Bitmap.createBitmap(
- b1,
- dx1 / 2,
- dy1 / 2,
- targetWidth,
- targetHeight);
+ Bitmap b2 = Bitmap.createBitmap(b1, dx1 / 2, dy1 / 2, targetWidth, targetHeight);
if (b1 != source) {
b1.recycle();
/**
* Creates a centered bitmap of the desired size. Recycles the input.
+ *
* @param source
*/
- public static Bitmap extractMiniThumb(
- Bitmap source, int width, int height) {
+ public static Bitmap extractMiniThumb(Bitmap source, int width, int height) {
return Util.extractMiniThumb(source, width, height, true);
}
- public static Bitmap extractMiniThumb(
- Bitmap source, int width, int height, boolean recycle) {
+ public static Bitmap extractMiniThumb(Bitmap source, int width, int height, boolean recycle) {
if (source == null) {
return null;
}
return miniThumbnail;
}
-
- public static <T> int indexOf(T [] array, T s) {
+ public static <T> int indexOf(T[] array, T s) {
for (int i = 0; i < array.length; i++) {
if (array[i].equals(s)) {
return i;
}
public static void closeSilently(Closeable c) {
- if (c == null) return;
+ if (c == null)
+ return;
try {
c.close();
} catch (Throwable t) {
}
public static void closeSilently(ParcelFileDescriptor c) {
- if (c == null) return;
+ if (c == null)
+ return;
try {
c.close();
} catch (Throwable t) {
return a == b || a.equals(b);
}
- private static class BackgroundJob
- extends MonitoredActivity.LifeCycleAdapter implements Runnable {
+ private static class BackgroundJob extends MonitoredActivity.LifeCycleAdapter implements Runnable {
private final MonitoredActivity mActivity;
private final ProgressDialog mDialog;
private final Runnable mCleanupRunner = new Runnable() {
public void run() {
mActivity.removeLifeCycleListener(BackgroundJob.this);
- if (mDialog.getWindow() != null) mDialog.dismiss();
+ if (mDialog.getWindow() != null)
+ mDialog.dismiss();
}
};
- public BackgroundJob(MonitoredActivity activity, Runnable job,
- ProgressDialog dialog, Handler handler) {
+ public BackgroundJob(MonitoredActivity activity, Runnable job, ProgressDialog dialog, Handler handler) {
mActivity = activity;
mDialog = dialog;
mJob = job;
}
}
-
@Override
public void onActivityDestroyed(MonitoredActivity activity) {
// We get here only when the onDestroyed being called before
}
}
- public static void startBackgroundJob(MonitoredActivity activity,
- String title, String message, Runnable job, Handler handler) {
+ public static void startBackgroundJob(MonitoredActivity activity, String title, String message, Runnable job, Handler handler) {
// Make the progress dialog uncancelable, so that we can gurantee
// the thread will be done before the activity getting destroyed.
- ProgressDialog dialog = ProgressDialog.show(
- activity, title, message, true, false);
+ ProgressDialog dialog = ProgressDialog.show(activity, title, message, true, false);
new Thread(new BackgroundJob(activity, job, dialog, handler)).start();
}
// Returns an intent which is used for "set as" menu items.
public static Intent createSetAsIntent(Uri uri, String mimeType) {
- // Infer MIME type if missing for file URLs.
- if (uri.getScheme().equals("file")) {
- String path = uri.getPath();
- int lastDotIndex = path.lastIndexOf('.');
- if (lastDotIndex != -1) {
- mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
- uri.getPath().substring(lastDotIndex + 1).toLowerCase());
- }
- }
-
+ // Infer MIME type if missing for file URLs.
+ if (uri.getScheme().equals("file")) {
+ String path = uri.getPath();
+ int lastDotIndex = path.lastIndexOf('.');
+ if (lastDotIndex != -1) {
+ mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
+ uri.getPath().substring(lastDotIndex + 1).toLowerCase());
+ }
+ }
+
Intent intent = new Intent(Intent.ACTION_ATTACH_DATA);
intent.setDataAndType(uri, mimeType);
intent.putExtra("mimeType", mimeType);
// it in GMM instead. For those platforms which have no GMM installed,
// the default Maps application will be chosen.
-
public static void openMaps(Context context, double latitude, double longitude) {
try {
// Try to open the GMM first
// the MapView to the specified location, but we need a marker
// for further operations (routing to/from).
// The q=(lat, lng) syntax is suggested by geo-team.
- String url = String.format(
- "http://maps.google.com/maps?f=q&q=(%s,%s)", latitude, longitude);
- ComponentName compName =
- new ComponentName(MAPS_PACKAGE_NAME, MAPS_CLASS_NAME);
- Intent mapsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url))
- .setComponent(compName);
+ String url = String.format("http://maps.google.com/maps?f=q&q=(%s,%s)", latitude, longitude);
+ ComponentName compName = new ComponentName(MAPS_PACKAGE_NAME, MAPS_CLASS_NAME);
+ Intent mapsIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)).setComponent(compName);
context.startActivity(mapsIntent);
} catch (ActivityNotFoundException e) {
// Use the "geo intent" if no GMM is installed
return null;
long crc = Crc64Long(in);
/*
- * The output is done in two parts to avoid problems with architecture-dependent word order
+ * The output is done in two parts to avoid problems with
+ * architecture-dependent word order
*/
int low = ((int) crc) & 0xffffffff;
int high = ((int) (crc >> 32)) & 0xffffffff;
}
return string;
}
-
+
// Copies src file to dst file.
// If the dst file does not exist, it is created
public static void Copy(File src, File dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
-
+
// Transfer bytes from in to out
byte[] buf = new byte[1024];
int len;
return true;
return false;
}
-
+
@Override
public String toString() {
- return (new String("(" + x + ", " + y + ", " + z + ")" ));
+ return (new String("(" + x + ", " + y + ", " + z + ")"));
}
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
- case SHOW_PROGRESS: {
- CharSequence c = getText(R.string.wallpaper);
- mProgressDialog = ProgressDialog.show(Wallpaper.this,
- "", c, true, false);
- break;
- }
- case FINISH: {
- closeProgressDialog();
- setResult(RESULT_OK);
- finish();
- break;
- }
+ case SHOW_PROGRESS: {
+ CharSequence c = getText(R.string.wallpaper);
+ mProgressDialog = ProgressDialog.show(Wallpaper.this, "", c, true, false);
+ break;
+ }
+ case FINISH: {
+ closeProgressDialog();
+ setResult(RESULT_OK);
+ finish();
+ break;
+ }
}
}
};
private final Context mContext;
private final File mFile;
- public SetWallpaperThread(Bitmap bitmap, Handler handler,
- Context context, File file) {
+ public SetWallpaperThread(Bitmap bitmap, Handler handler, Context context, File file) {
mBitmap = bitmap;
mHandler = handler;
mContext = context;
Uri imageToUse = getIntent().getData();
if (imageToUse != null) {
Intent intent = new Intent();
- intent.setClassName("com.cooliris.media",
- "com.cooliris.media.CropImage");
+ intent.setClassName("com.cooliris.media", "com.cooliris.media.CropImage");
intent.setData(imageToUse);
formatIntent(intent);
startActivityForResult(intent, CROP_DONE);
int width = getWallpaperDesiredMinimumWidth();
int height = getWallpaperDesiredMinimumHeight();
- intent.putExtra("outputX", width);
- intent.putExtra("outputY", height);
- intent.putExtra("aspectX", width);
- intent.putExtra("aspectY", height);
- intent.putExtra("scale", true);
+ intent.putExtra("outputX", width);
+ intent.putExtra("outputY", height);
+ intent.putExtra("aspectX", width);
+ intent.putExtra("aspectY", height);
+ intent.putExtra("scale", true);
intent.putExtra("noFaceDetection", true);
intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(mTempFile));
intent.putExtra("outputFormat", Bitmap.CompressFormat.PNG.name());
}
@Override
- protected void onActivityResult(int requestCode, int resultCode,
- Intent data) {
- if ((requestCode == PHOTO_PICKED || requestCode == CROP_DONE)
- && (resultCode == RESULT_OK) && (data != null)) {
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if ((requestCode == PHOTO_PICKED || requestCode == CROP_DONE) && (resultCode == RESULT_OK) && (data != null)) {
try {
InputStream s = new FileInputStream(mTempFile);
try {
Bitmap bitmap = BitmapFactory.decodeStream(s);
if (bitmap == null) {
- Log.e(LOG_TAG, "Failed to set wallpaper. "
- + "Couldn't get bitmap for path "
- + mTempFile);
+ Log.e(LOG_TAG, "Failed to set wallpaper. " + "Couldn't get bitmap for path " + mTempFile);
} else {
mHandler.sendEmptyMessage(SHOW_PROGRESS);
- new SetWallpaperThread(
- bitmap, mHandler, this, mTempFile).start();
+ new SetWallpaperThread(bitmap, mHandler, this, mTempFile).start();
}
mDoLaunch = false;
} finally {
public static final EntrySchema SCHEMA = new EntrySchema(AlbumEntry.class);
/**
- * The user account that is the sync source for this entry. Must be set before insert/update.
+ * The user account that is the sync source for this entry. Must be set
+ * before insert/update.
*/
@Column(Columns.SYNC_ACCOUNT)
public String syncAccount;
-
+
/**
* The ETag for the album/photos GData feed.
*/
@Column(Columns.PHOTOS_ETAG)
- public String photosEtag = null;
-
+ public String photosEtag = null;
+
/**
- * True if the contents of the album need to be synchronized. Must be set before insert/update.
+ * True if the contents of the album need to be synchronized. Must be set
+ * before insert/update.
*/
@Column(Columns.PHOTOS_DIRTY)
public boolean photosDirty;
-
+
/**
* The "edit" URI of the album.
*/
@Column(Columns.EDIT_URI)
public String editUri;
-
+
/**
* The album owner.
*/
/**
* The title of the album.
*/
- @Column(value=Columns.TITLE)
+ @Column(value = Columns.TITLE)
public String title;
-
+
/**
* A short summary of the contents of the album.
*/
- @Column(value=Columns.SUMMARY)
+ @Column(value = Columns.SUMMARY)
public String summary;
-
+
/**
* The date the album was created.
*/
@Column(Columns.DATE_PUBLISHED)
public long datePublished;
-
+
/**
* The date the album was last updated.
*/
@Column(Columns.DATE_UPDATED)
public long dateUpdated;
-
+
/**
- * The date the album entry was last edited. May be more recent than dateUpdated.
+ * The date the album entry was last edited. May be more recent than
+ * dateUpdated.
*/
@Column(Columns.DATE_EDITED)
public long dateEdited;
-
+
/**
* The number of photos in the album.
*/
@Column(Columns.NUM_PHOTOS)
public int numPhotos;
-
+
/**
* The number of bytes of storage that this album uses.
*/
@Column(Columns.BYTES_USED)
public long bytesUsed;
-
+
/**
* The user-specified location associated with the album.
*/
@Column(Columns.LOCATION_STRING)
public String locationString;
-
+
/**
* The thumbnail URL associated with the album.
*/
@Column(Columns.THUMBNAIL_URL)
public String thumbnailUrl;
-
+
/**
* A link to the HTML page associated with the album.
*/
@Column(Columns.HTML_PAGE_URL)
public String htmlPageUrl;
-
+
/**
* Column names specific to album entries.
*/
public static final class Columns extends PicasaApi.Columns {
public static final String PHOTOS_ETAG = "photos_etag";
- public static final String USER = "user";
+ public static final String USER = "user";
public static final String BYTES_USED = "bytes_used";
public static final String NUM_PHOTOS = "num_photos";
public static final String LOCATION_STRING = "location_string";
public static final String PHOTOS_DIRTY = "photos_dirty";
}
-
+
/**
* Resets values to defaults for object reuse.
*/
thumbnailUrl = null;
htmlPageUrl = null;
}
-
+
/**
- * Sets the property value corresponding to the given XML element, if applicable.
+ * Sets the property value corresponding to the given XML element, if
+ * applicable.
*/
@Override
public void setPropertyFromXml(String uri, String localName, Attributes attrs, String content) {
char localNameChar = localName.charAt(0);
if (uri.equals(GDataParser.GPHOTO_NAMESPACE)) {
switch (localNameChar) {
- case 'i':
- if (localName.equals("id")) {
- id = Long.parseLong(content);
- }
- break;
- case 'u':
- if (localName.equals("user")) {
- user = content;
- }
- break;
- case 'n':
- if (localName.equals("numphotos")) {
- numPhotos = Integer.parseInt(content);
- }
- break;
- case 'b':
- if (localName.equals("bytesUsed")) {
- bytesUsed = Long.parseLong(content);
- }
- break;
+ case 'i':
+ if (localName.equals("id")) {
+ id = Long.parseLong(content);
+ }
+ break;
+ case 'u':
+ if (localName.equals("user")) {
+ user = content;
+ }
+ break;
+ case 'n':
+ if (localName.equals("numphotos")) {
+ numPhotos = Integer.parseInt(content);
+ }
+ break;
+ case 'b':
+ if (localName.equals("bytesUsed")) {
+ bytesUsed = Long.parseLong(content);
+ }
+ break;
}
} else if (uri.equals(GDataParser.ATOM_NAMESPACE)) {
switch (localNameChar) {
- case 't':
- if (localName.equals("title")) {
- title = content;
- }
- break;
- case 's':
- if (localName.equals("summary")) {
- summary = content;
- }
- break;
- case 'p':
- if (localName.equals("published")) {
- datePublished = GDataParser.parseAtomTimestamp(content);
- }
- break;
- case 'u':
- if (localName.equals("updated")) {
- dateUpdated = GDataParser.parseAtomTimestamp(content);
- }
- break;
- case 'l':
- if (localName.equals("link")) {
- String rel = attrs.getValue("", "rel");
- String href = attrs.getValue("", "href");
- if (rel.equals("alternate") && attrs.getValue("", "type").equals("text/html")) {
- htmlPageUrl = href;
- } else if (rel.equals("edit")) {
- editUri = href;
- }
+ case 't':
+ if (localName.equals("title")) {
+ title = content;
+ }
+ break;
+ case 's':
+ if (localName.equals("summary")) {
+ summary = content;
+ }
+ break;
+ case 'p':
+ if (localName.equals("published")) {
+ datePublished = GDataParser.parseAtomTimestamp(content);
+ }
+ break;
+ case 'u':
+ if (localName.equals("updated")) {
+ dateUpdated = GDataParser.parseAtomTimestamp(content);
+ }
+ break;
+ case 'l':
+ if (localName.equals("link")) {
+ String rel = attrs.getValue("", "rel");
+ String href = attrs.getValue("", "href");
+ if (rel.equals("alternate") && attrs.getValue("", "type").equals("text/html")) {
+ htmlPageUrl = href;
+ } else if (rel.equals("edit")) {
+ editUri = href;
}
- break;
+ }
+ break;
}
} else if (uri.equals(GDataParser.APP_NAMESPACE)) {
if (localName.equals("edited")) {
import org.xml.sax.Attributes;
public abstract class Entry {
- public static final String[] ID_PROJECTION = {"_id"};
-
- // The primary key of the entry.
+ public static final String[] ID_PROJECTION = { "_id" };
+
+ // The primary key of the entry.
@Column("_id")
public long id = 0;
public @interface Table {
String value();
}
-
+
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String value();
+
boolean indexed() default false;
+
boolean fullText() default false;
}
public void clear() {
id = 0;
}
-
+
public void setPropertyFromXml(String uri, String localName, Attributes attrs, String content) {
throw new UnsupportedOperationException("Entry class does not support XML parsing");
}
public static final int TYPE_FLOAT = 5;
public static final int TYPE_DOUBLE = 6;
public static final int TYPE_BLOB = 7;
- public static final String SQLITE_TYPES[] = { "TEXT", "INTEGER", "INTEGER", "INTEGER",
- "INTEGER", "REAL", "REAL", "NONE" };
+ public static final String SQLITE_TYPES[] = { "TEXT", "INTEGER", "INTEGER", "INTEGER", "INTEGER", "REAL", "REAL", "NONE" };
private static final String TAG = "SchemaInfo";
private static final String FULL_TEXT_INDEX_SUFFIX = "_fulltext";
}
private void logExecSql(SQLiteDatabase db, String sql) {
- //Log.i(TAG, sql);
+ // Log.i(TAG, sql);
db.execSQL(sql);
}
int columnIndex = column.projectionIndex;
Field field = column.field;
switch (column.type) {
- case TYPE_STRING:
- field.set(object, cursor.getString(columnIndex));
- break;
- case TYPE_BOOLEAN:
- field.setBoolean(object, cursor.getShort(columnIndex) == 1);
- break;
- case TYPE_SHORT:
- field.setShort(object, cursor.getShort(columnIndex));
- break;
- case TYPE_INT:
- field.setInt(object, cursor.getInt(columnIndex));
- break;
- case TYPE_LONG:
- field.setLong(object, cursor.getLong(columnIndex));
- break;
- case TYPE_FLOAT:
- field.setFloat(object, cursor.getFloat(columnIndex));
- break;
- case TYPE_DOUBLE:
- field.setDouble(object, cursor.getDouble(columnIndex));
- break;
- case TYPE_BLOB:
- field.set(object, cursor.getBlob(columnIndex));
- break;
+ case TYPE_STRING:
+ field.set(object, cursor.getString(columnIndex));
+ break;
+ case TYPE_BOOLEAN:
+ field.setBoolean(object, cursor.getShort(columnIndex) == 1);
+ break;
+ case TYPE_SHORT:
+ field.setShort(object, cursor.getShort(columnIndex));
+ break;
+ case TYPE_INT:
+ field.setInt(object, cursor.getInt(columnIndex));
+ break;
+ case TYPE_LONG:
+ field.setLong(object, cursor.getLong(columnIndex));
+ break;
+ case TYPE_FLOAT:
+ field.setFloat(object, cursor.getFloat(columnIndex));
+ break;
+ case TYPE_DOUBLE:
+ field.setDouble(object, cursor.getDouble(columnIndex));
+ break;
+ case TYPE_BLOB:
+ field.set(object, cursor.getBlob(columnIndex));
+ break;
}
}
} catch (IllegalArgumentException e) {
String columnName = column.name;
Field field = column.field;
switch (column.type) {
- case TYPE_STRING:
- values.put(columnName, (String)field.get(object));
- break;
- case TYPE_BOOLEAN:
- values.put(columnName, field.getBoolean(object));
- break;
- case TYPE_SHORT:
- values.put(columnName, field.getShort(object));
- break;
- case TYPE_INT:
- values.put(columnName, field.getInt(object));
- break;
- case TYPE_LONG:
- values.put(columnName, field.getLong(object));
- break;
- case TYPE_FLOAT:
- values.put(columnName, field.getFloat(object));
- break;
- case TYPE_DOUBLE:
- values.put(columnName, field.getDouble(object));
- break;
- case TYPE_BLOB:
- values.put(columnName, (byte[])field.get(object));
- break;
+ case TYPE_STRING:
+ values.put(columnName, (String) field.get(object));
+ break;
+ case TYPE_BOOLEAN:
+ values.put(columnName, field.getBoolean(object));
+ break;
+ case TYPE_SHORT:
+ values.put(columnName, field.getShort(object));
+ break;
+ case TYPE_INT:
+ values.put(columnName, field.getInt(object));
+ break;
+ case TYPE_LONG:
+ values.put(columnName, field.getLong(object));
+ break;
+ case TYPE_FLOAT:
+ values.put(columnName, field.getFloat(object));
+ break;
+ case TYPE_DOUBLE:
+ values.put(columnName, field.getDouble(object));
+ break;
+ case TYPE_BLOB:
+ values.put(columnName, (byte[]) field.get(object));
+ break;
}
}
} catch (IllegalArgumentException e) {
}
public boolean queryWithId(SQLiteDatabase db, long id, Entry entry) {
- Cursor cursor = db.query(mTableName, mProjection, "_id=?",
- new String[] { Long.toString(id) }, null, null, null);
+ Cursor cursor = db.query(mTableName, mProjection, "_id=?", new String[] { Long.toString(id) }, null, null, null);
boolean success = false;
if (cursor.moveToFirst()) {
cursorToObject(cursor, entry);
logExecSql(db, sql.toString());
sql.setLength(0);
- // Build an insert statement that will automatically keep the FTS table in sync.
+ // Build an insert statement that will automatically keep the FTS
+ // table in sync.
StringBuilder insertSql = new StringBuilder("INSERT OR REPLACE INTO ");
insertSql.append(ftsTableName);
insertSql.append(" (_id");
for (int i = 0; i != fields.length; ++i) {
// Get column metadata from the annotation.
Field field = fields[i];
- Entry.Column info = ((AnnotatedElement)field).getAnnotation(Entry.Column.class);
+ Entry.Column info = ((AnnotatedElement) field).getAnnotation(Entry.Column.class);
if (info == null) {
continue;
}
} else if (fieldType == byte[].class) {
type = TYPE_BLOB;
} else {
- throw new IllegalArgumentException("Unsupported field type for column: " +
- fieldType.getName());
+ throw new IllegalArgumentException("Unsupported field type for column: " + fieldType.getName());
}
// Add the column to the array.
int index = columns.size();
- columns.add(new ColumnInfo(info.value(), type, info.indexed(), info.fullText(), field,
- index));
+ columns.add(new ColumnInfo(info.value(), type, info.indexed(), info.fullText(), field, index));
}
// Return a list.
public final Field field;
public final int projectionIndex;
- public ColumnInfo(String name, int type, boolean indexed, boolean fullText, Field field,
- int projectionIndex) {
+ public ColumnInfo(String name, int type, boolean indexed, boolean fullText, Field field, int projectionIndex) {
this.name = name.toLowerCase();
this.type = type;
this.indexed = indexed;
public static final HttpParams HTTP_PARAMS;
public static final ThreadSafeClientConnManager HTTP_CONNECTION_MANAGER;
- private final DefaultHttpClient mHttpClient = new DefaultHttpClient(HTTP_CONNECTION_MANAGER,
- HTTP_PARAMS);
+ private final DefaultHttpClient mHttpClient = new DefaultHttpClient(HTTP_CONNECTION_MANAGER, HTTP_PARAMS);
private String mAuthToken;
static {
public void setAuthToken(String authToken) {
mAuthToken = authToken;
}
-
+
public void get(String feedUrl, Operation operation) throws IOException {
callMethod(new HttpGet(feedUrl), operation);
}
- public void post(String feedUrl, byte[] data, String contentType, Operation operation)
- throws IOException {
+ public void post(String feedUrl, byte[] data, String contentType, Operation operation) throws IOException {
ByteArrayEntity entity = getCompressedEntity(data);
entity.setContentType(contentType);
HttpPost post = new HttpPost(feedUrl);
callMethod(post, operation);
}
- public void put(String feedUrl, byte[] data, String contentType, Operation operation)
- throws IOException {
+ public void put(String feedUrl, byte[] data, String contentType, Operation operation) throws IOException {
ByteArrayEntity entity = getCompressedEntity(data);
entity.setContentType(contentType);
HttpPost post = new HttpPost(feedUrl);
callMethod(post, operation);
}
- public void putStream(String feedUrl, InputStream stream, String contentType,
- Operation operation) throws IOException {
+ public void putStream(String feedUrl, InputStream stream, String contentType, Operation operation) throws IOException {
InputStreamEntity entity = new InputStreamEntity(stream, -1);
entity.setContentType(contentType);
HttpPost post = new HttpPost(feedUrl);
callMethod(post, operation);
}
- private void callMethod(HttpUriRequest request, Operation operation)
- throws IOException {
+ private void callMethod(HttpUriRequest request, Operation operation) throws IOException {
// Specify GData protocol version 2.0.
request.addHeader("GData-Version", "2");
}
}
}
-
+
// Return the stream if successful.
Header etagHeader = httpResponse.getFirstHeader("ETag");
operation.outStatus = status;
public static final String GML_NAMESPACE = "http://www.opengis.net/gml";
private static final String FEED_ELEMENT = "feed";
private static final String ENTRY_ELEMENT = "entry";
-
+
private static final int STATE_DOCUMENT = 0;
private static final int STATE_FEED = 1;
private static final int STATE_ENTRY = 2;
-
+
private static final int NUM_LEVELS = 5;
-
+
private Entry mEntry = null;
private EntryHandler mHandler = null;
private int mState = STATE_DOCUMENT;
private String[] mName = new String[NUM_LEVELS];
private AttributesImpl[] mAttributes = new AttributesImpl[NUM_LEVELS];
private final StringBuilder mValue = new StringBuilder(128);
-
+
public interface EntryHandler {
void handleEntry(Entry entry);
}
-
+
public GDataParser() {
AttributesImpl[] attributes = mAttributes;
for (int i = 0; i != NUM_LEVELS; ++i) {
attributes[i] = new AttributesImpl();
}
}
-
+
public void setEntry(Entry entry) {
mEntry = entry;
}
-
+
public void setHandler(EntryHandler handler) {
mHandler = handler;
}
-
+
public static long parseAtomTimestamp(String timestamp) {
Time time = new Time();
time.parse3339(timestamp);
return time.toMillis(true);
}
-
+
public void startElement(String uri, String localName, String qName, Attributes attrs) throws SAXException {
switch (mState) {
- case STATE_DOCUMENT:
- // Expect an atom:feed element.
- if (uri.equals(ATOM_NAMESPACE) && localName.equals(FEED_ELEMENT)) {
- mState = STATE_FEED;
- } else {
- throw new SAXException();
- }
- break;
- case STATE_FEED:
- // Expect a feed property element or an atom:entry element.
- if (uri.equals(ATOM_NAMESPACE) && localName.equals(ENTRY_ELEMENT)) {
- mState = STATE_ENTRY;
- mEntry.clear();
- } else {
- startProperty(uri, localName, attrs);
- }
- break;
- case STATE_ENTRY:
+ case STATE_DOCUMENT:
+ // Expect an atom:feed element.
+ if (uri.equals(ATOM_NAMESPACE) && localName.equals(FEED_ELEMENT)) {
+ mState = STATE_FEED;
+ } else {
+ throw new SAXException();
+ }
+ break;
+ case STATE_FEED:
+ // Expect a feed property element or an atom:entry element.
+ if (uri.equals(ATOM_NAMESPACE) && localName.equals(ENTRY_ELEMENT)) {
+ mState = STATE_ENTRY;
+ mEntry.clear();
+ } else {
startProperty(uri, localName, attrs);
- break;
+ }
+ break;
+ case STATE_ENTRY:
+ startProperty(uri, localName, attrs);
+ break;
}
}
-
+
public void endElement(String uri, String localName, String qName) throws SAXException {
if (mLevel > 0) {
// Handle property exit.
endProperty();
- } else {
+ } else {
// Handle state exit.
switch (mState) {
- case STATE_DOCUMENT:
- throw new SAXException();
- case STATE_FEED:
- mState = STATE_DOCUMENT;
- break;
- case STATE_ENTRY:
- mState = STATE_FEED;
- mHandler.handleEntry(mEntry);
- break;
+ case STATE_DOCUMENT:
+ throw new SAXException();
+ case STATE_FEED:
+ mState = STATE_DOCUMENT;
+ break;
+ case STATE_ENTRY:
+ mState = STATE_FEED;
+ mHandler.handleEntry(mEntry);
+ break;
}
}
}
-
+
private void startProperty(String uri, String localName, Attributes attrs) {
// Push element information onto the property stack.
int level = mLevel + 1;
}
public void skippedEntity(String name) throws SAXException {
- // Ignored.
+ // Ignored.
}
public void startDocument() throws SAXException {
public void startPrefixMapping(String prefix, String uri) throws SAXException {
// Ignored.
}
-
+
public void endPrefixMapping(String prefix) throws SAXException {
// Ignored.
}
public static final EntrySchema SCHEMA = new EntrySchema(PhotoEntry.class);
/**
- * The user account that is the sync source for this entry. Must be set before insert/update.
+ * The user account that is the sync source for this entry. Must be set
+ * before insert/update.
*/
@Column("sync_account")
public String syncAccount;
public long albumId;
/**
- * The display index of the photo within the album. Must be set before insert/update.
+ * The display index of the photo within the album. Must be set before
+ * insert/update.
*/
@Column(value = "display_index", indexed = true)
public int displayIndex;
public long dateUpdated;
/**
- * The date the photo entry was last edited. May be more recent than dateUpdated.
+ * The date the photo entry was last edited. May be more recent than
+ * dateUpdated.
*/
@Column("date_edited")
public long dateEdited;
public int height;
/**
- * The rotation of the photo in degrees, if rotation has not already been applied.
+ * The rotation of the photo in degrees, if rotation has not already been
+ * applied.
*/
@Column("rotation")
public int rotation;
public String screennailUrl;
/**
- * The "content" URL for the photo (currently 1280px, or a video). The original image URL is not fetched since "imgmax" accepts
- * one size, used to get this resource.
+ * The "content" URL for the photo (currently 1280px, or a video). The
+ * original image URL is not fetched since "imgmax" accepts one size, used
+ * to get this resource.
*/
@Column("content_url")
public String contentUrl;
}
/**
- * Sets the property value corresponding to the given XML element, if applicable.
+ * Sets the property value corresponding to the given XML element, if
+ * applicable.
*/
@Override
public void setPropertyFromXml(String uri, String localName, Attributes attrs, String content) {
// Get the token without user interaction.
authToken = accountManager.blockingGetAuthToken(account, PicasaService.SERVICE_NAME, true);
- // TODO: Remove this once the build is signed by Google, since we will always have permission.
+ // TODO: Remove this once the build is signed by Google, since
+ // we will always have permission.
// This code requests permission from the user explicitly.
if (context instanceof Activity) {
Bundle bundle = accountManager.getAuthToken(account, PicasaService.SERVICE_NAME, null, (Activity) context,
if (authToken != null) {
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?
+ // Strip the domain from GMail accounts for
+ // canonicalization. TODO: is there an official way?
username = username.substring(0, username.indexOf('@'));
}
authAccounts.add(new AuthAccount(username, authToken, account));
return RESULT_ERROR;
}
- public int getAlbumPhotos(AccountManager accountManager, SyncResult syncResult, AlbumEntry album, GDataParser.EntryHandler handler) {
+ public int getAlbumPhotos(AccountManager accountManager, SyncResult syncResult, AlbumEntry album,
+ GDataParser.EntryHandler handler) {
// Construct the query URL for user albums.
StringBuilder builder = new StringBuilder(BASE_URL);
builder.append("user/");
private final AlbumEntry mAlbumInstance = new AlbumEntry();
private SyncContext mSyncContext = null;
private Account mActiveAccount;
-
+
@Override
public void attachInfo(Context context, ProviderInfo info) {
// Initialize the provider and set the database.
public static final class Database extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "picasa.db";
public static final int DATABASE_VERSION = 83;
+
public Database(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
- // No new versions yet, if we are asked to upgrade we just reset everything.
+ // No new versions yet, if we are asked to upgrade we just reset
+ // everything.
PhotoEntry.SCHEMA.dropTables(db);
AlbumEntry.SCHEMA.dropTables(db);
UserEntry.SCHEMA.dropTables(db);
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
- // Ensure that the URI is well-formed. We currently do not allow WHERE clauses.
+ // Ensure that the URI is well-formed. We currently do not allow WHERE
+ // clauses.
List<String> path = uri.getPathSegments();
if (path.size() != 2 || !uri.getAuthority().equals(AUTHORITY) || selection != null) {
return 0;
context.finish();
return 0;
}
-
+
public void reloadAccounts() {
- mSyncContext.reloadAccounts();
+ mSyncContext.reloadAccounts();
}
-
+
public void setActiveSyncAccount(Account account) {
mActiveAccount = account;
}
-
+
public void syncUsers(SyncResult syncResult) {
- syncUsers(mSyncContext, syncResult);
+ syncUsers(mSyncContext, syncResult);
}
public void syncUsersAndAlbums(final boolean syncAlbumPhotos, SyncResult syncResult) {
SyncContext context = mSyncContext;
-
+
// Synchronize users authenticated on the device.
UserEntry[] users = syncUsers(context, syncResult);
-
+
// Synchronize albums for each user.
String activeUsername = null;
if (mActiveAccount != null) {
for (int i = 0, numUsers = users.length; i != numUsers; ++i) {
if (activeUsername != null && !context.accounts[i].user.equals(activeUsername))
continue;
- if (!ContentResolver.getSyncAutomatically(context.accounts[i].account, AUTHORITY)) continue;
+ if (!ContentResolver.getSyncAutomatically(context.accounts[i].account, AUTHORITY))
+ continue;
didSyncActiveUserName = true;
context.api.setAuth(context.accounts[i]);
syncUserAlbums(context, users[i], syncResult);
}
context.finish();
}
-
+
public static boolean isSyncEnabled(String accountName, SyncContext context) {
PicasaApi.AuthAccount[] accounts = context.accounts;
int numAccounts = accounts.length;
UserEntry entry = new UserEntry();
schema.cursorToObject(cursor, entry);
- // Find the corresponding account, or delete the row if it does not exist.
+ // Find the corresponding account, or delete the row if it does
+ // not exist.
int i;
for (i = 0; i != numUsers; ++i) {
Log.i(TAG, "Check " + accounts[i].user + " == " + entry.account);
// Build a sorted index with existing entry timestamps.
final EntryMetadata local[] = new EntryMetadata[localCount];
for (int i = 0; i != localCount; ++i) {
- cursor.moveToPosition(i); // TODO: throw exception here if returns false?
+ cursor.moveToPosition(i); // TODO: throw exception here if returns
+ // false?
local[i] = new EntryMetadata(cursor.getLong(0), cursor.getLong(1), 0);
}
cursor.close();
if (AlbumEntry.SCHEMA.queryWithId(db, cursor.getLong(0), album)) {
syncAlbumPhotos(context, account, album, syncResult);
}
-
+
// Abort if interrupted.
if (Thread.interrupted()) {
++syncResult.stats.numIoExceptions;
}
private void syncAlbumPhotos(SyncContext context, final String account, AlbumEntry album, final SyncResult syncResult) {
- Log.i(TAG, "Syncing Picasa album: " + album.title);
-
+ Log.i(TAG, "Syncing Picasa album: " + album.title);
+
// Query existing album entry (id, dateEdited) sorted by ID.
final SQLiteDatabase db = context.db;
long albumId = album.id;
null, "date_edited");
int localCount = cursor.getCount();
- // Build a sorted index with existing entry timestamps and display indexes.
+ // Build a sorted index with existing entry timestamps and display
+ // indexes.
final EntryMetadata local[] = new EntryMetadata[localCount];
final EntryMetadata key = new EntryMetadata();
for (int i = 0; i != localCount; ++i) {
- cursor.moveToPosition(i); // TODO: throw exception here if returns false?
+ cursor.moveToPosition(i); // TODO: throw exception here if returns
+ // false?
local[i] = new EntryMetadata(cursor.getLong(0), cursor.getLong(1), cursor.getInt(2));
}
cursor.close();
// Delete all albums.
db.delete(albumTableName, WHERE_ACCOUNT, whereArgs);
-
+
// Delete the user entry.
db.delete(UserEntry.SCHEMA.getTableName(), "account=?", whereArgs);
}
// List of all authenticated user accounts.
public PicasaApi.AuthAccount[] accounts;
- // A connection to the Picasa API for a specific user account. Initially null.
+ // A connection to the Picasa API for a specific user account. Initially
+ // null.
public PicasaApi api = new PicasaApi();
// A handle to the Picasa databse.
db = mDatabase.getWritableDatabase();
reloadAccounts();
}
-
+
public void reloadAccounts() {
- accounts = PicasaApi.getAuthenticatedAccounts(getContext());
+ accounts = PicasaApi.getAuthenticatedAccounts(getContext());
}
-
+
public void finish() {
// Send notifications if needed and reset state.
ContentResolver cr = getContext().getContentResolver();
public class PicasaReceiver extends BroadcastReceiver {
- private static final String TAG = "PicasaRecevier";
+ private static final String TAG = "PicasaRecevier";
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.e(TAG, "Accounts changed: " + intent);
- }
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Log.e(TAG, "Accounts changed: " + intent);
+ }
}
private static final AtomicBoolean sSyncPending = new AtomicBoolean(false);
public static void requestSync(Context context, int type, long id) {
- Bundle extras = new Bundle();
- extras.putInt(KEY_TYPE, type);
- extras.putLong(KEY_ID, id);
-
- Account[] accounts = PicasaApi.getAccounts(context);
- for (Account account : accounts) {
- ContentResolver.requestSync(account, PicasaContentProvider.AUTHORITY, extras);
- }
-
- //context.startService(new Intent(context, PicasaService.class).putExtras(extras));
+ Bundle extras = new Bundle();
+ extras.putInt(KEY_TYPE, type);
+ extras.putLong(KEY_ID, id);
+
+ Account[] accounts = PicasaApi.getAccounts(context);
+ for (Account account : accounts) {
+ ContentResolver.requestSync(account, PicasaContentProvider.AUTHORITY, extras);
+ }
+
+ // context.startService(new Intent(context,
+ // PicasaService.class).putExtras(extras));
}
public PicasaService() {
mSyncThread.start();
mSyncHandler = new Handler(mSyncThread.getLooper());
mSyncHandler.post(new Runnable() {
- public void run() {
- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
- }
+ public void run() {
+ Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
+ }
});
}
ContentProviderClient client = cr.acquireContentProviderClient(PicasaContentProvider.AUTHORITY);
return (PicasaContentProvider) client.getLocalContentProvider();
}
-
+
@Override
public int onStartCommand(final Intent intent, int flags, final int startId) {
- mSyncHandler.post(new Runnable() {
- public void run() {
- performSync(PicasaService.this, null, intent.getExtras(), new SyncResult());
- stopSelf(startId);
- }
- });
- return START_NOT_STICKY;
+ mSyncHandler.post(new Runnable() {
+ public void run() {
+ performSync(PicasaService.this, null, intent.getExtras(), new SyncResult());
+ stopSelf(startId);
+ }
+ });
+ return START_NOT_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
return new PicasaSyncAdapter(getApplicationContext()).getSyncAdapterBinder();
}
-
+
@Override
public void onDestroy() {
- mSyncThread.quit();
+ mSyncThread.quit();
}
-
+
public static boolean performSync(Context context, Account account, Bundle extras, SyncResult syncResult) {
- // Skip if another sync is pending.
- if (!sSyncPending.compareAndSet(false, true)) {
- return false;
- }
-
- // Perform the sync.
- performSyncImpl(context, account, extras, syncResult);
-
- // Mark sync as complete and notify all waiters.
- sSyncPending.set(false);
- synchronized (sSyncPending) {
- sSyncPending.notifyAll();
- }
- return true;
+ // Skip if another sync is pending.
+ if (!sSyncPending.compareAndSet(false, true)) {
+ return false;
+ }
+
+ // Perform the sync.
+ performSyncImpl(context, account, extras, syncResult);
+
+ // Mark sync as complete and notify all waiters.
+ sSyncPending.set(false);
+ synchronized (sSyncPending) {
+ sSyncPending.notifyAll();
+ }
+ return true;
}
-
+
public static void waitForPerformSync() {
synchronized (sSyncPending) {
while (sSyncPending.get()) {
}
}
}
-
+
private static void performSyncImpl(Context context, Account account, Bundle extras, SyncResult syncResult) {
- // Initialize newly added accounts to sync by default.
- String authority = PicasaContentProvider.AUTHORITY;
- if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
- if (account != null && ContentResolver.getIsSyncable(account, authority) < 0) {
- try {
- ContentResolver.setIsSyncable(account, authority, getIsSyncable(context, account) ? 1 : 0);
- } catch (OperationCanceledException e) {
- } catch (IOException e) {
- }
- }
- return;
- }
-
- // Do nothing if sync is disabled for this account. TODO: is this blocked in PicasaContentProvider too?
- if (account != null && ContentResolver.getIsSyncable(account, authority) < 0) {
- ++syncResult.stats.numSkippedEntries;
- return;
- }
-
- // Get the type of sync operation and the entity ID, if applicable. Default to synchronize all.
- int type = extras.getInt(PicasaService.KEY_TYPE, PicasaService.TYPE_USERS_ALBUMS);
- long id = extras.getLong(PicasaService.KEY_ID, -1);
-
- // Get the content provider instance and reload the list of user accounts.
- PicasaContentProvider provider = getContentProvider(context);
- provider.reloadAccounts();
-
- // Restrict sync to either a specific account or all accounts.
- provider.setActiveSyncAccount(account);
-
- // Perform the desired sync operation.
- switch (type) {
- case PicasaService.TYPE_USERS:
- provider.syncUsers(syncResult);
- break;
- case PicasaService.TYPE_USERS_ALBUMS:
- provider.syncUsersAndAlbums(true, syncResult);
- break;
- case PicasaService.TYPE_ALBUM_PHOTOS:
- provider.syncAlbumPhotos(id, true, syncResult);
- break;
- default:
- throw new IllegalArgumentException();
- }
+ // Initialize newly added accounts to sync by default.
+ String authority = PicasaContentProvider.AUTHORITY;
+ if (extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false)) {
+ if (account != null && ContentResolver.getIsSyncable(account, authority) < 0) {
+ try {
+ ContentResolver.setIsSyncable(account, authority, getIsSyncable(context, account) ? 1 : 0);
+ } catch (OperationCanceledException e) {
+ } catch (IOException e) {
+ }
+ }
+ return;
+ }
+
+ // Do nothing if sync is disabled for this account. TODO: is this
+ // blocked in PicasaContentProvider too?
+ if (account != null && ContentResolver.getIsSyncable(account, authority) < 0) {
+ ++syncResult.stats.numSkippedEntries;
+ return;
+ }
+
+ // Get the type of sync operation and the entity ID, if applicable.
+ // Default to synchronize all.
+ int type = extras.getInt(PicasaService.KEY_TYPE, PicasaService.TYPE_USERS_ALBUMS);
+ long id = extras.getLong(PicasaService.KEY_ID, -1);
+
+ // Get the content provider instance and reload the list of user
+ // accounts.
+ PicasaContentProvider provider = getContentProvider(context);
+ provider.reloadAccounts();
+
+ // Restrict sync to either a specific account or all accounts.
+ provider.setActiveSyncAccount(account);
+
+ // Perform the desired sync operation.
+ switch (type) {
+ case PicasaService.TYPE_USERS:
+ provider.syncUsers(syncResult);
+ break;
+ case PicasaService.TYPE_USERS_ALBUMS:
+ provider.syncUsersAndAlbums(true, syncResult);
+ break;
+ case PicasaService.TYPE_ALBUM_PHOTOS:
+ provider.syncAlbumPhotos(id, true, syncResult);
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
}
-
+
private static boolean getIsSyncable(Context context, Account account) throws IOException, OperationCanceledException {
try {
Account[] picasaAccounts = AccountManager.get(context).getAccountsByTypeAndFeatures(ACCOUNT_TYPE,
}
public static final class AccountChangeReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- // TODO: Need to get account list change broadcast.
- }
-
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // TODO: Need to get account list change broadcast.
+ }
+
}
}
public void setDatabase(SQLiteOpenHelper database) {
mDatabase = database;
}
-
+
public void addMapping(String authority, String path, String mimeSubtype, EntrySchema table) {
// Add the table URI mapping.
ArrayList<Mapping> mappings = mMappings;
UriMatcher matcher = mUriMatcher;
matcher.addURI(authority, path, mappings.size());
mappings.add(new Mapping(table, mimeSubtype, false));
-
+
// Add the row URI mapping.
matcher.addURI(authority, path + "/#", mappings.size());
mappings.add(new Mapping(table, mimeSubtype, true));
}
-
+
@Override
public boolean onCreate() {
- // The database may not be loaded yet since attachInfo() has not been called, so we cannot
- // check that the database opened successfully. Returns true optimistically.
+ // The database may not be loaded yet since attachInfo() has not been
+ // called, so we cannot
+ // check that the database opened successfully. Returns true
+ // optimistically.
return true;
}
-
+
@Override
public String getType(Uri uri) {
// Resolve the URI.
}
@Override
- public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
- String sortOrder) {
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
// Resolve the URI.
int match = mUriMatcher.match(uri);
if (match == UriMatcher.NO_MATCH) {
throw new IllegalArgumentException("Invalid URI: " + uri);
}
-
+
// Add the ID predicate if needed.
Mapping mapping = mMappings.get(match);
if (mapping.hasId) {
selection = whereWithId(uri, selection);
}
-
- //System.out.println("QUERY " + uri + " WHERE (" + selection + ")");
+
+ // System.out.println("QUERY " + uri + " WHERE (" + selection + ")");
// Run the query.
String tableName = mapping.table.getTableName();
- Cursor cursor = mDatabase.getReadableDatabase().query(tableName, projection, selection, selectionArgs, null, null, sortOrder);
+ Cursor cursor = mDatabase.getReadableDatabase().query(tableName, projection, selection, selectionArgs, null, null,
+ sortOrder);
cursor.setNotificationUri(getContext().getContentResolver(), uri);
return cursor;
}
-
+
@Override
public Uri insert(Uri uri, ContentValues values) {
// Resolve the URI.
throw new IllegalArgumentException("Invalid URI: " + uri);
}
- // Insert into the database, notify observers, and return the qualified URI.
+ // Insert into the database, notify observers, and return the qualified
+ // URI.
String tableName = mapping.table.getTableName();
long rowId = mDatabase.getWritableDatabase().insert(tableName, NULL_COLUMN_HACK, values);
if (rowId > 0) {
throw new SQLException("Failed to insert row at: " + uri);
}
}
-
+
@Override
public int bulkInsert(Uri uri, ContentValues[] values) {
// Resolve the URI.
notifyChange(uri);
return numInserted;
}
-
+
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// Resolve the URI.
if (match == UriMatcher.NO_MATCH) {
throw new IllegalArgumentException("Invalid URI: " + uri);
}
-
+
// Add the ID predicate if needed.
Mapping mapping = mMappings.get(match);
if (mapping.hasId) {
selection = whereWithId(uri, selection);
}
-
+
// Update the item(s) and broadcast a change notification.
SQLiteDatabase db = mDatabase.getWritableDatabase();
String tableName = mapping.table.getTableName();
if (match == UriMatcher.NO_MATCH) {
throw new IllegalArgumentException("Invalid URI: " + uri);
}
-
+
// Add the ID predicate if needed.
Mapping mapping = mMappings.get(match);
if (mapping.hasId) {
notifyChange(uri);
return count;
}
-
+
private final String whereWithId(Uri uri, String selection) {
String id = uri.getPathSegments().get(1);
StringBuilder where = new StringBuilder("_id=");
}
return where.toString();
}
-
+
private final void notifyChange(Uri uri) {
getContext().getContentResolver().notifyChange(uri, null);
}
-
+
private static final class Mapping {
public EntrySchema table;
public String mimeSubtype;
@Column("account")
public String account;
-
+
@Column("albums_etag")
public String albumsEtag;
}
import android.graphics.Bitmap;
public class RandomDataSource implements Slideshow.DataSource {
-
+
public Bitmap getBitmapForIndex(Context context, int currentSlideshowCounter) {
ImageList list = CacheService.getImageList(context);
// Once we have the id and the thumbid, we can return a bitmap
private Rect mQueuedRect;
private RectF mQueuedFrameRect;
private static final Vector3f sQueuedGrow = new Vector3f();
-
+
private long mPrevTime;
private long mTimeElapsed;
}
public void surfaceCreated(SurfaceHolder holder) {
- // We may need to make calls to super once this is a subclass of WallpaperService.
+ // We may need to make calls to super once this is a subclass of
+ // WallpaperService.
mHandler.post(mDrawFrame);
}
// We draw the source bitmap
if (mBitmap != null) {
if (mTimeElapsed > SLIDESHOW_DURATION) {
- float alpha = ((float)(mTimeElapsed - SLIDESHOW_DURATION)) / 2000.0f;
+ float alpha = ((float) (mTimeElapsed - SLIDESHOW_DURATION)) / 2000.0f;
paint.setColorFilter(null);
if (alpha < 1.0f) {
- //int val = (int)(255 * (1.0f - alpha));
- //int srcColor = Color.argb(val, 0, 0, 0);
- //PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(srcColor, Mode.SRC_IN);
- //paint.setColorFilter(null);
+ // int val = (int)(255 * (1.0f - alpha));
+ // int srcColor = Color.argb(val, 0, 0, 0);
+ // PorterDuffColorFilter colorFilter = new
+ // PorterDuffColorFilter(srcColor, Mode.SRC_IN);
+ // paint.setColorFilter(null);
}
c.drawBitmap(mBitmap, mRect, mFrameRect, paint);
if (alpha < 1.0f) {
- int val = (int)(255 * alpha);
+ int val = (int) (255 * alpha);
int srcColor = Color.argb(val, 0, 0, 0);
PorterDuffColorFilter colorFilter = new PorterDuffColorFilter(srcColor, Mode.DST_IN);
paint.setColorFilter(colorFilter);
}
-
+
c.drawBitmap(mQueuedBitmap, mQueuedRect, mQueuedFrameRect, paint);
performUpdate(mQueuedFrameRect, sQueuedGrow, delta);
if (alpha >= 1.0f) {
// We switch the image.
mRect = mQueuedRect;
mBitmap = mQueuedBitmap;
- mFrameRect = mQueuedFrameRect;
+ mFrameRect = mQueuedFrameRect;
sGrow.set(sQueuedGrow);
mQueuedBitmap = null;
mQueuedRect = null;
- mQueuedFrameRect = null;
+ mQueuedFrameRect = null;
mTimeElapsed = 0;
}
} else {
}
private void performUpdate(RectF rect, Vector3f grow, long delta) {
- float timeElapsed = ((float)(delta)) / 1000.0f;
+ float timeElapsed = ((float) (delta)) / 1000.0f;
float amountToGrowX = timeElapsed * (rect.width() / 15.0f);
float amountToGrowY = amountToGrowX * (rect.height() / rect.width());
rect.top -= amountToGrowY * grow.x;
rect.left -= amountToGrowX * grow.y;
-
+
rect.bottom += amountToGrowY * (1 - grow.x);
rect.right += amountToGrowX * (1 - grow.y);
}
mFrameRect = new RectF();
mFrameRect.right = viewWidth;
mFrameRect.bottom = viewHeight;
- sGrow.set((float)Math.random(), (float)Math.random(), 0);
+ sGrow.set((float) Math.random(), (float) Math.random(), 0);
}
}
if (mQueuedBitmap == null) {
mQueuedFrameRect = new RectF();
mQueuedFrameRect.right = viewWidth;
mQueuedFrameRect.bottom = viewHeight;
- sQueuedGrow.set((float)Math.random(), (float)Math.random(), 0);
+ sQueuedGrow.set((float) Math.random(), (float) Math.random(), 0);
}
}
}
private Rect getRectToFitBitmap(int bitmapWidth, int bitmapHeight, int viewWidth, int viewHeight) {
Rect rect = new Rect();
- float viewAspect = (float)viewHeight / viewWidth;
+ float viewAspect = (float) viewHeight / viewWidth;
float newWidth = bitmapWidth * viewAspect;
if (bitmapHeight < newWidth) {
// Vertically constrained.
newWidth = bitmapHeight / viewAspect;
- rect.set((int)(bitmapWidth/2 - newWidth/2), 0, (int)(bitmapWidth/2 + newWidth/2), bitmapHeight);
+ rect.set((int) (bitmapWidth / 2 - newWidth / 2), 0, (int) (bitmapWidth / 2 + newWidth / 2), bitmapHeight);
} else {
// Horizontally constrained
float newHeight = bitmapWidth * viewAspect;
- rect.set(0, (int)(bitmapHeight/2 - newHeight/2), bitmapWidth, (int)(bitmapHeight/2 + newHeight/2));
+ rect.set(0, (int) (bitmapHeight / 2 - newHeight / 2), bitmapWidth, (int) (bitmapHeight / 2 + newHeight / 2));
}
return rect;
}