• R/O
  • HTTP
  • SSH
  • HTTPS

提交

标签
No Tags

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-cqtcocoa誰得pythonphprubygameguibathyscaphec翻訳計画中(planning stage)omegatframeworktwittertestdomvb.netdirectxbtronarduinopreviewerゲームエンジン

packages/apps/Gallery2


Commit MetaInfo

修订版2b04f591f758b7af03c43d90e91b939cbd515506 (tree)
时间2009-12-04 12:02:18
作者Venkat Krishnaraj <venkatkrishnaraj@venk...>
CommiterDave Sparks

Log Message

Prevent locking of files when the sd card is ejected New Cache Dirty system which will work on any arbitrary directory Non-static hudlayer and pathbar TouchEventQueue has a max size before it starts dropping touch_move events Other bug fixes

更改概述

差异

--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -131,6 +131,10 @@
131131 <action android:name="android.intent.action.MEDIA_MOUNTED" />
132132 <data android:scheme="file" />
133133 </intent-filter>
134+ <intent-filter>
135+ <action android:name="android.intent.action.MEDIA_EJECT" />
136+ <data android:scheme="file" />
137+ </intent-filter>
134138 </receiver>
135139 <receiver android:name="PhotoAppWidgetProvider" android:label="@string/gadget_title">
136140 <intent-filter>
--- a/src/com/cooliris/cache/BootReceiver.java
+++ b/src/com/cooliris/cache/BootReceiver.java
@@ -1,6 +1,7 @@
11 package com.cooliris.cache;
22
33 import com.cooliris.media.LocalDataSource;
4+import com.cooliris.media.PicasaDataSource;
45 import com.cooliris.media.SingleDataSource;
56
67 import android.content.BroadcastReceiver;
@@ -50,6 +51,12 @@ public class BootReceiver extends BroadcastReceiver {
5051 ContentResolver cr = context.getContentResolver();
5152 cr.registerContentObserver(uriImages, false, localObserver);
5253 cr.registerContentObserver(uriVideos, false, localObserver);
54+ } else if (action.equals(Intent.ACTION_MEDIA_EJECT)) {
55+ LocalDataSource.sThumbnailCache.close();
56+ LocalDataSource.sThumbnailCacheVideo.close();
57+ PicasaDataSource.sThumbnailCache.close();
58+ CacheService.sAlbumCache.close();
59+ CacheService.sMetaAlbumCache.close();
5360 }
5461 }
5562 }
--- a/src/com/cooliris/cache/CacheService.java
+++ b/src/com/cooliris/cache/CacheService.java
@@ -19,6 +19,7 @@ import java.util.Locale;
1919 import java.util.concurrent.atomic.AtomicReference;
2020
2121 import android.app.IntentService;
22+import android.content.ContentProviderClient;
2223 import android.content.ContentResolver;
2324 import android.content.ContentValues;
2425 import android.content.Context;
@@ -56,7 +57,7 @@ import com.cooliris.media.Utils;
5657 public final class CacheService extends IntentService {
5758 public static final String ACTION_CACHE = "com.cooliris.cache.action.CACHE";
5859 public static final DiskCache sAlbumCache = new DiskCache("local-album-cache");
59- public static final DiskCache sMetaAlbumCache = new DiskCache("local-meta-album-cache");
60+ public static final DiskCache sMetaAlbumCache = new DiskCache("local-meta-cache");
6061
6162 private static final String TAG = "CacheService";
6263 private static ImageList sList = null;
@@ -94,7 +95,7 @@ public final class CacheService extends IntentService {
9495 Images.ImageColumns.DATA, Images.ImageColumns.ORIENTATION };
9596
9697 public static final String[] SENSE_PROJECTION = new String[] { Images.ImageColumns.BUCKET_ID,
97- "MAX(" + Images.ImageColumns.DATE_ADDED + ")" };
98+ "MAX(" + Images.ImageColumns.DATE_ADDED + "), COUNT(*)" };
9899
99100 // Must preserve order between these indices and the order of the terms in
100101 // INITIAL_PROJECTION_IMAGES and
@@ -204,10 +205,10 @@ public final class CacheService extends IntentService {
204205 if (ids != null && observer != null) {
205206 observer.onChange(ids);
206207 }
207- if (ids.length > 0) {
208+ if (ids != null && ids.length > 0) {
208209 sList = null;
210+ Log.i(TAG, "Done computing dirty sets for num " + ids.length);
209211 }
210- Log.i(TAG, "Done computing dirty sets for num " + ids.length);
211212 }
212213 });
213214 } else {
@@ -556,12 +557,10 @@ public final class CacheService extends IntentService {
556557 }
557558 byte[] bitmap = thumbnailCache.get(thumbId, timestamp);
558559 if (bitmap == null) {
559- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
560560 final long time = SystemClock.uptimeMillis();
561561 bitmap = buildThumbnailForId(context, thumbnailCache, thumbId, origId, isVideo, DEFAULT_THUMBNAIL_WIDTH,
562562 DEFAULT_THUMBNAIL_HEIGHT);
563563 Log.i(TAG, "Built thumbnail and screennail for " + origId + " in " + (SystemClock.uptimeMillis() - time));
564- Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
565564 }
566565 return bitmap;
567566 }
@@ -608,7 +607,6 @@ public final class CacheService extends IntentService {
608607 return null;
609608 }
610609 } else {
611- Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
612610 new Thread() {
613611 public void run() {
614612 try {
@@ -883,13 +881,22 @@ public final class CacheService extends IntentService {
883881 lBuffer.put(0, l);
884882 return bArray;
885883 }
884+
885+ private static final byte[] longArrayToByteArray(final long[] l) {
886+ final byte[] bArray = new byte[8 * l.length];
887+ final ByteBuffer bBuffer = ByteBuffer.wrap(bArray);
888+ final LongBuffer lBuffer = bBuffer.asLongBuffer();
889+ int numLongs = l.length;
890+ for (int i = 0; i < numLongs; ++i) {
891+ lBuffer.put(i, l[i]);
892+ }
893+ return bArray;
894+ }
886895
887896 private final static void refresh(final Context context) {
888897 // First we build the album cache.
889898 // This is the meta-data about the albums / buckets on the SD card.
890899 Log.i(TAG, "Refreshing cache.");
891- int priority = Process.getThreadPriority(Process.myTid());
892- Process.setThreadPriority(Process.THREAD_PRIORITY_MORE_FAVORABLE);
893900 sAlbumCache.deleteAll();
894901 putLocaleForAlbumCache(Locale.getDefault());
895902
@@ -944,7 +951,6 @@ public final class CacheService extends IntentService {
944951 // Now we must cache the items contained in every album / bucket.
945952 populateMediaItemsForSets(context, sets, acceleratedSets, false);
946953 sAlbumCache.delete(ALBUM_CACHE_INCOMPLETE_INDEX);
947- Process.setThreadPriority(priority);
948954
949955 // Complete any queued dirty requests
950956 processQueuedDirty(context);
@@ -973,36 +979,52 @@ public final class CacheService extends IntentService {
973979 }
974980
975981 private static final long[] computeDirtySets(final Context context) {
976- final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build();
977- final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI.buildUpon().appendQueryParameter("distinct", "true").build();
982+ final Uri uriImages = Images.Media.EXTERNAL_CONTENT_URI;
983+ final Uri uriVideos = Video.Media.EXTERNAL_CONTENT_URI;
978984 final ContentResolver cr = context.getContentResolver();
979-
980- final Cursor cursorImages = cr.query(uriImages, SENSE_PROJECTION, null, null, null);
981- final Cursor cursorVideos = cr.query(uriVideos, SENSE_PROJECTION, null, null, null);
985+ final String where = Images.ImageColumns.BUCKET_ID + "!=0) GROUP BY (" + Images.ImageColumns.BUCKET_ID + " ";
986+ final Cursor cursorImages = cr.query(uriImages, SENSE_PROJECTION, where, null, null);
987+ final Cursor cursorVideos = cr.query(uriVideos, SENSE_PROJECTION, where, null, null);
982988 Cursor[] cursors = new Cursor[2];
983989 cursors[0] = cursorImages;
984990 cursors[1] = cursorVideos;
985991 final MergeCursor cursor = new MergeCursor(cursors);
986992 long[] retVal = null;
993+ int ctr = 0;
987994 try {
988995 if (cursor.moveToFirst()) {
989996 retVal = new long[cursor.getCount()];
990- int ctr = 0;
991997 boolean allDirty = false;
992998 do {
993999 long setId = cursor.getLong(0);
994- retVal[ctr++] = setId;
995- byte[] data = sMetaAlbumCache.get(setId, 0);
996- if (data == null) {
997- // We need to refresh everything.
998- markDirty(context);
999- allDirty = true;
1000- }
1001- if (!allDirty) {
1002- long maxAdded = cursor.getLong(1);
1003- long oldMaxAdded = toLong(data);
1004- if (maxAdded > oldMaxAdded) {
1005- markDirty(context, setId);
1000+ if (allDirty) {
1001+ retVal[ctr++] = setId;
1002+ } else {
1003+ boolean contains = sAlbumCache.isDataAvailable(setId, 0);
1004+ if (!contains) {
1005+ // We need to refresh everything.
1006+ markDirty(context);
1007+ retVal[ctr++] = setId;
1008+ allDirty = true;
1009+ }
1010+ if (!allDirty) {
1011+ long maxAdded = cursor.getLong(1);
1012+ int count = cursor.getInt(2);
1013+ byte[] data = sMetaAlbumCache.get(setId, 0);
1014+ long[] dataLong = new long[2];
1015+ if (data != null) {
1016+ dataLong = toLongArray(data);
1017+ }
1018+ long oldMaxAdded = dataLong[0];
1019+ long oldCount = dataLong[1];
1020+ Log.i(TAG, "Bucket " + setId + " Old added " + oldMaxAdded + " count " + oldCount + " New added " + maxAdded + " count " + count);
1021+ if (maxAdded > oldMaxAdded || oldCount != count) {
1022+ markDirty(context, setId);
1023+ retVal[ctr++] = setId;
1024+ dataLong[0] = maxAdded;
1025+ dataLong[1] = count;
1026+ sMetaAlbumCache.put(setId, longArrayToByteArray(dataLong));
1027+ }
10061028 }
10071029 }
10081030 } while (cursor.moveToNext());
@@ -1010,8 +1032,13 @@ public final class CacheService extends IntentService {
10101032 } finally {
10111033 cursor.close();
10121034 }
1035+ sMetaAlbumCache.flush();
10131036 processQueuedDirty(context);
1014- return retVal;
1037+ long[] retValCompact = new long[ctr];
1038+ for (int i = 0; i < ctr; ++i) {
1039+ retValCompact[i] = retVal[i];
1040+ }
1041+ return retValCompact;
10151042 }
10161043
10171044 private static final void processQueuedDirty(final Context context) {
@@ -1074,7 +1101,6 @@ public final class CacheService extends IntentService {
10741101 final int approximateCountPerSet = count / numSets;
10751102 for (int i = 0; i < numSets; ++i) {
10761103 final MediaSet set = sets.get(i);
1077- set.getItems().clear();
10781104 set.setNumExpectedItems(approximateCountPerSet);
10791105 }
10801106 do {
@@ -1091,7 +1117,7 @@ public final class CacheService extends IntentService {
10911117 final long setId = sortCursor.getLong(MEDIA_BUCKET_ID_INDEX);
10921118 final MediaSet set = findSet(setId, acceleratedSets);
10931119 if (set != null) {
1094- set.getItems().add(item);
1120+ set.addItem(item);
10951121 }
10961122 } while (sortCursor.moveToNext());
10971123 }
@@ -1144,20 +1170,9 @@ public final class CacheService extends IntentService {
11441170 }
11451171 writeItemsForASet(sets.get(i));
11461172 }
1147- writeMetaAlbumCache(sets);
11481173 sAlbumCache.flush();
11491174 }
11501175
1151- private static final void writeMetaAlbumCache(ArrayList<MediaSet> sets) {
1152- final int numSets = sets.size();
1153- for (int i = 0; i < numSets; ++i) {
1154- final MediaSet set = sets.get(i);
1155- byte[] data = longToByteArray(set.mMaxAddedTimestamp);
1156- sMetaAlbumCache.put(set.mId, data);
1157- }
1158- sMetaAlbumCache.flush();
1159- }
1160-
11611176 private static final void writeItemsForASet(final MediaSet set) {
11621177 final ByteArrayOutputStream bos = new ByteArrayOutputStream();
11631178 final DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(bos, 256));
--- a/src/com/cooliris/media/Gallery.java
+++ b/src/com/cooliris/media/Gallery.java
@@ -124,7 +124,7 @@ public final class Gallery extends Activity {
124124 final ConcatenatedDataSource singleCombinedDataSource = new ConcatenatedDataSource(singleDataSource, picasaDataSource);
125125 mGridLayer.setDataSource(singleCombinedDataSource);
126126 mGridLayer.setViewIntent(true, Utils.getBucketNameFromUri(uri));
127- if (SingleDataSource.isSingleImageMode(uri.toString())) {
127+ if (singleDataSource.isSingleImage()) {
128128 mGridLayer.setSingleImage(false);
129129 } else if (slideshow) {
130130 mGridLayer.setSingleImage(true);
--- a/src/com/cooliris/media/GridLayer.java
+++ b/src/com/cooliris/media/GridLayer.java
@@ -7,7 +7,6 @@ import android.hardware.SensorEvent;
77 import android.opengl.GLU;
88 import android.os.PowerManager;
99 import android.os.PowerManager.WakeLock;
10-import android.util.Log;
1110 import android.view.KeyEvent;
1211 import android.view.MotionEvent;
1312 import android.content.Context;
@@ -29,7 +28,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
2928
3029 private static final float SLIDESHOW_TRANSITION_TIME = 3.5f;
3130
32- private static HudLayer sHud;
31+ private HudLayer mHud;
3332 private int mState;
3433 private static final IndexRange sBufferedVisibleRange = new IndexRange();
3534 private static final IndexRange sVisibleRange = new IndexRange();
@@ -133,33 +132,32 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
133132 sBucketList.clear();
134133
135134 sVisibleItems = new ArrayList<MediaItem>();
136- if (sHud == null) {
137- sHud = new HudLayer(context);
138- }
139- sHud.setContext(context);
140- sHud.setGridLayer(this);
141- sHud.getPathBar().clear();
142- sHud.setGridLayer(this);
143- sHud.getTimeBar().setListener(this);
144- sHud.getPathBar().pushLabel(R.drawable.icon_home_small, context.getResources().getString(R.string.app_name),
135+ mHud = new HudLayer(context);
136+ mHud.setContext(context);
137+ mHud.setGridLayer(this);
138+ mHud.getPathBar().clear();
139+ mHud.setGridLayer(this);
140+ mHud.getTimeBar().setListener(this);
141+ mHud.getPathBar().pushLabel(R.drawable.icon_home_small, context.getResources().getString(R.string.app_name),
145142 new Runnable() {
146143 public void run() {
147- if (sHud.getAlpha() == 1.0f) {
144+ if (mHud.getAlpha() == 1.0f) {
148145 if (!mFeedAboutToChange) {
149146 setState(STATE_MEDIA_SETS);
150147 }
151148 } else {
152- sHud.setAlpha(1.0f);
149+ mHud.setAlpha(1.0f);
153150 }
154151 }
155152 });
156153 mCameraManager = new GridCameraManager(mCamera);
157154 mDrawManager = new GridDrawManager(context, mCamera, mDrawables, sDisplayList, sDisplayItems, sDisplaySlots);
158155 mInputProcessor = new GridInputProcessor(context, mCamera, this, mView, sTempVec, sDisplayItems);
156+ setState(STATE_MEDIA_SETS);
159157 }
160158
161159 public HudLayer getHud() {
162- return sHud;
160+ return mHud;
163161 }
164162
165163 public void shutdown() {
@@ -185,13 +183,13 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
185183 mBackground.generate(view, lists);
186184 lists.blendedList.add(this);
187185 lists.hitTestList.add(this);
188- sHud.generate(view, lists);
186+ mHud.generate(view, lists);
189187 }
190188
191189 @Override
192190 protected void onSizeChanged() {
193- sHud.setSize(mWidth, mHeight);
194- sHud.setAlpha(1.0f);
191+ mHud.setSize(mWidth, mHeight);
192+ mHud.setAlpha(1.0f);
195193 mBackground.setSize(mWidth, mHeight);
196194 mTimeElapsedSinceTransition = 0.0f;
197195 if (mView != null) {
@@ -240,24 +238,24 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
240238 MediaSet set = feed.getCurrentSet();
241239 int icon = mDrawables.getIconForSet(set, true);
242240 if (set != null) {
243- sHud.getPathBar().pushLabel(icon, set.mNoCountTitleString, new Runnable() {
241+ mHud.getPathBar().pushLabel(icon, set.mNoCountTitleString, new Runnable() {
244242 public void run() {
245243 if (mFeedAboutToChange) {
246244 return;
247245 }
248- if (sHud.getAlpha() == 1.0f) {
246+ if (mHud.getAlpha() == 1.0f) {
249247 disableLocationFiltering();
250248 mInputProcessor.clearSelection();
251249 setState(STATE_GRID_VIEW);
252250 } else {
253- sHud.setAlpha(1.0f);
251+ mHud.setAlpha(1.0f);
254252 }
255253 }
256254 });
257255 }
258256 }
259257 if (mState == STATE_FULL_SCREEN) {
260- sHud.getPathBar().popLabel();
258+ mHud.getPathBar().popLabel();
261259 }
262260 break;
263261 case STATE_TIMELINE:
@@ -276,12 +274,12 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
276274 layoutInterface.mSpacingX = (int) (40 * Gallery.PIXEL_DENSITY);
277275 layoutInterface.mSpacingY = (int) (40 * Gallery.PIXEL_DENSITY);
278276 if (mState != STATE_FULL_SCREEN) {
279- sHud.getPathBar().pushLabel(R.drawable.ic_fs_details, "", new Runnable() {
277+ mHud.getPathBar().pushLabel(R.drawable.ic_fs_details, "", new Runnable() {
280278 public void run() {
281- if (sHud.getAlpha() == 1.0f) {
282- sHud.swapFullscreenLabel();
279+ if (mHud.getAlpha() == 1.0f) {
280+ mHud.swapFullscreenLabel();
283281 }
284- sHud.setAlpha(1.0f);
282+ mHud.setAlpha(1.0f);
285283 }
286284 });
287285 }
@@ -300,15 +298,15 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
300298 layoutInterface.mSpacingY = (int) (70 * Gallery.PIXEL_DENSITY * yStretch);
301299 if (mInAlbum) {
302300 if (mState == STATE_FULL_SCREEN) {
303- sHud.getPathBar().popLabel();
301+ mHud.getPathBar().popLabel();
304302 }
305- sHud.getPathBar().popLabel();
303+ mHud.getPathBar().popLabel();
306304 mInAlbum = false;
307305 }
308306 break;
309307 }
310308 mState = state;
311- sHud.onGridStateChanged();
309+ mHud.onGridStateChanged();
312310 if (performLayout && mFeedAboutToChange == false) {
313311 onLayout(Shared.INVALID, Shared.INVALID, oldLayout);
314312 }
@@ -321,9 +319,9 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
321319 protected void enableLocationFiltering(String label) {
322320 if (mLocationFilter == false) {
323321 mLocationFilter = true;
324- sHud.getPathBar().pushLabel(R.drawable.icon_location_small, label, new Runnable() {
322+ mHud.getPathBar().pushLabel(R.drawable.icon_location_small, label, new Runnable() {
325323 public void run() {
326- if (sHud.getAlpha() == 1.0f) {
324+ if (mHud.getAlpha() == 1.0f) {
327325 if (mState == STATE_FULL_SCREEN) {
328326 mInputProcessor.clearSelection();
329327 setState(STATE_GRID_VIEW);
@@ -331,7 +329,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
331329 disableLocationFiltering();
332330 }
333331 } else {
334- sHud.setAlpha(1.0f);
332+ mHud.setAlpha(1.0f);
335333 }
336334 }
337335 });
@@ -342,7 +340,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
342340 if (mLocationFilter) {
343341 mLocationFilter = false;
344342 mMediaFeed.removeFilter();
345- sHud.getPathBar().popLabel();
343+ mHud.getPathBar().popLabel();
346344 }
347345 }
348346
@@ -383,7 +381,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
383381 }
384382 mWakeLock = null;
385383 }
386- sHud.setAlpha(1.0f);
384+ mHud.setAlpha(1.0f);
387385 }
388386
389387 @Override
@@ -490,9 +488,9 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
490488 hud.setMode(HudLayer.MODE_NORMAL);
491489 }
492490 if (view.elapsedLoadingExpensiveTextures() > 150 || (mMediaFeed != null && mMediaFeed.getWaitingForMediaScanner())) {
493- sHud.getPathBar().setAnimatedIcons(GridDrawables.TEXTURE_SPINNER);
491+ mHud.getPathBar().setAnimatedIcons(GridDrawables.TEXTURE_SPINNER);
494492 } else {
495- sHud.getPathBar().setAnimatedIcons(null);
493+ mHud.getPathBar().setAnimatedIcons(null);
496494 }
497495
498496 // In that case, we need to commit the respective Display Items when the
@@ -500,17 +498,17 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
500498 GridCamera camera = mCamera;
501499 camera.update(timeElapsed);
502500 DisplayItem anchorDisplayItem = getAnchorDisplayItem(ANCHOR_CENTER);
503- if (anchorDisplayItem != null && !sHud.getTimeBar().isDragged()) {
504- sHud.getTimeBar().setItem(anchorDisplayItem.mItemRef);
501+ if (anchorDisplayItem != null && !mHud.getTimeBar().isDragged()) {
502+ mHud.getTimeBar().setItem(anchorDisplayItem.mItemRef);
505503 }
506504 sDisplayList.update(timeElapsed);
507505 mInputProcessor.update(timeElapsed);
508506 mSelectedAlpha = FloatUtils.animate(mSelectedAlpha, mTargetAlpha, timeElapsed * 0.5f);
509507 if (mState == STATE_FULL_SCREEN) {
510- sHud.autoHide(true);
508+ mHud.autoHide(true);
511509 } else {
512- sHud.autoHide(false);
513- sHud.setAlpha(1.0f);
510+ mHud.autoHide(false);
511+ mHud.setAlpha(1.0f);
514512 }
515513 GridQuad[] fullscreenQuads = GridDrawables.sFullscreenGrid;
516514 int numFullScreenQuads = fullscreenQuads.length;
@@ -670,8 +668,8 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
670668 if (mState == STATE_GRID_VIEW) {
671669 MediaSet expandedSet = mMediaFeed.getExpandedMediaSet();
672670 if (expandedSet != null) {
673- if (!sHud.getPathBar().getCurrentLabel().equals(expandedSet.mNoCountTitleString)) {
674- sHud.getPathBar().changeLabel(expandedSet.mNoCountTitleString);
671+ if (!mHud.getPathBar().getCurrentLabel().equals(expandedSet.mNoCountTitleString)) {
672+ mHud.getPathBar().changeLabel(expandedSet.mNoCountTitleString);
675673 }
676674 }
677675 }
@@ -688,13 +686,13 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
688686 if (itemUri != null && mRequestFocusContentUri != null) {
689687 if (itemUri.equals(mRequestFocusContentUri)) {
690688 mInputProcessor.setCurrentSelectedSlot(i);
691- mRequestFocusContentUri = null;
692689 break;
693690 }
694691 }
695692 }
696693 }
697694 }
695+ mRequestFocusContentUri = null;
698696 }
699697 }
700698 } finally {
@@ -726,8 +724,8 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
726724 @Override
727725 public void onSurfaceCreated(RenderView view, GL11 gl) {
728726 sDisplayList.clear();
729- sHud.clear();
730- sHud.reset();
727+ mHud.clear();
728+ mHud.reset();
731729 GridDrawables.sStringTextureTable.clear();
732730 mDrawables.onSurfaceCreated(view, gl);
733731 mBackground.clear();
@@ -780,8 +778,8 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
780778
781779 public void renderBlended(RenderView view, GL11 gl) {
782780 // We draw the placeholder for all visible slots.
783- if (sHud != null && mDrawManager != null) {
784- mDrawManager.drawBlendedComponents(view, gl, mSelectedAlpha, mState, sHud.getMode(), mTimeElapsedSinceStackViewReady,
781+ if (mHud != null && mDrawManager != null) {
782+ mDrawManager.drawBlendedComponents(view, gl, mSelectedAlpha, mState, mHud.getMode(), mTimeElapsedSinceStackViewReady,
785783 mTimeElapsedSinceGridViewReady, sBucketList, mMediaFeed.getWaitingForMediaScanner() || mFeedAboutToChange
786784 || mMediaFeed.isLoading());
787785 }
@@ -857,7 +855,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
857855 mFeedChanged = true;
858856 forceRecomputeVisibleRange();
859857 if (mState == STATE_GRID_VIEW || mState == STATE_FULL_SCREEN)
860- sHud.setFeed(feed, mState, needsLayout);
858+ mHud.setFeed(feed, mState, needsLayout);
861859 return;
862860 }
863861
@@ -865,10 +863,10 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
865863 Thread.yield();
866864 }
867865 if (mState == STATE_GRID_VIEW) {
868- if (sHud != null) {
866+ if (mHud != null) {
869867 MediaSet set = feed.getCurrentSet();
870868 if (set != null && !mLocationFilter)
871- sHud.getPathBar().changeLabel(set.mNoCountTitleString);
869+ mHud.getPathBar().changeLabel(set.mNoCountTitleString);
872870 }
873871 }
874872 DisplayItem[] displayItems = sDisplayItems;
@@ -953,7 +951,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
953951 mFeedChanged = true;
954952 if (feed != null) {
955953 if (mState == STATE_GRID_VIEW || mState == STATE_FULL_SCREEN)
956- sHud.setFeed(feed, mState, needsLayout);
954+ mHud.setFeed(feed, mState, needsLayout);
957955 }
958956 if (mView != null) {
959957 mView.requestRender();
@@ -1058,7 +1056,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
10581056 boolean retVal = changeFocusToSlot(currentSelectedSlot + 1, convergence);
10591057 if (mInputProcessor.getCurrentSelectedSlot() == currentSelectedSlot) {
10601058 endSlideshow();
1061- sHud.setAlpha(1.0f);
1059+ mHud.setAlpha(1.0f);
10621060 }
10631061 return retVal;
10641062 }
@@ -1070,7 +1068,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
10701068 DisplayItem displayItem = sDisplayItems[index * MAX_ITEMS_PER_SLOT];
10711069 if (displayItem != null) {
10721070 MediaItem item = displayItem.mItemRef;
1073- sHud.fullscreenSelectionChanged(item, slotId + 1, sCompleteRange.end + 1);
1071+ mHud.fullscreenSelectionChanged(item, slotId + 1, sCompleteRange.end + 1);
10741072 if (slotId != Shared.INVALID && slotId <= sCompleteRange.end) {
10751073 mInputProcessor.setCurrentFocusSlot(slotId);
10761074 centerCameraForSlot(slotId, convergence);
@@ -1106,7 +1104,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
11061104
11071105 public void deselectOrCancelSelectMode() {
11081106 if (sBucketList.size() == 0) {
1109- sHud.cancelSelection();
1107+ mHud.cancelSelection();
11101108 } else {
11111109 sBucketList.clear();
11121110 updateCountOfSelectedItems();
@@ -1114,7 +1112,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
11141112 }
11151113
11161114 public void deselectAll() {
1117- sHud.cancelSelection();
1115+ mHud.cancelSelection();
11181116 sBucketList.clear();
11191117 updateCountOfSelectedItems();
11201118 }
@@ -1141,11 +1139,11 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
11411139 deselectAll();
11421140 }
11431141 }
1144- sHud.computeBottomMenu();
1142+ mHud.computeBottomMenu();
11451143 }
11461144
11471145 private void updateCountOfSelectedItems() {
1148- sHud.updateNumItemsSelected(sBucketList.size());
1146+ mHud.updateNumItemsSelected(sBucketList.size());
11491147 }
11501148
11511149 public int getMetadataSlotIndexForScreenPosition(int posX, int posY) {
@@ -1244,7 +1242,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
12441242 mZoomValue = 1.0f;
12451243 centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
12461244 mTimeElapsedSinceView = SLIDESHOW_TRANSITION_TIME - 1.0f;
1247- sHud.setAlpha(0);
1245+ mHud.setAlpha(0);
12481246 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
12491247 mWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "GridView.Slideshow");
12501248 mWakeLock.acquire();
@@ -1252,7 +1250,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
12521250
12531251 public void enterSelectionMode() {
12541252 mSlideshowMode = false;
1255- sHud.enterSelectionMode();
1253+ mHud.enterSelectionMode();
12561254 int currentSlot = mInputProcessor.getCurrentSelectedSlot();
12571255 if (currentSlot == Shared.INVALID) {
12581256 currentSlot = mInputProcessor.getCurrentFocusSlot();
@@ -1275,7 +1273,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
12751273 if (mZoomValue > 6.0f) {
12761274 mZoomValue = 6.0f;
12771275 }
1278- sHud.setAlpha(1.0f);
1276+ mHud.setAlpha(1.0f);
12791277 centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
12801278 }
12811279
@@ -1289,7 +1287,7 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
12891287 if (mZoomValue < 1.0f) {
12901288 mZoomValue = 1.0f;
12911289 }
1292- sHud.setAlpha(1.0f);
1290+ mHud.setAlpha(1.0f);
12931291 centerCameraForSlot(mInputProcessor.getCurrentSelectedSlot(), 1.0f);
12941292 }
12951293
@@ -1373,16 +1371,16 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
13731371
13741372 public void setPickIntent(boolean b) {
13751373 mPickIntent = b;
1376- sHud.getPathBar().popLabel();
1377- sHud.getPathBar().pushLabel(R.drawable.icon_location_small, mContext.getResources().getString(R.string.pick),
1374+ mHud.getPathBar().popLabel();
1375+ mHud.getPathBar().pushLabel(R.drawable.icon_location_small, mContext.getResources().getString(R.string.pick),
13781376 new Runnable() {
13791377 public void run() {
1380- if (sHud.getAlpha() == 1.0f) {
1378+ if (mHud.getAlpha() == 1.0f) {
13811379 if (!mFeedAboutToChange) {
13821380 setState(STATE_MEDIA_SETS);
13831381 }
13841382 } else {
1385- sHud.setAlpha(1.0f);
1383+ mHud.setAlpha(1.0f);
13861384 }
13871385 }
13881386 });
@@ -1398,19 +1396,19 @@ public final class GridLayer extends RootLayer implements MediaFeed.Listener, Ti
13981396 mMediaFeed.expandMediaSet(0);
13991397 setState(STATE_GRID_VIEW);
14001398 // We need to make sure we haven't pushed the same label twice
1401- if (sHud.getPathBar().getNumLevels() == 1) {
1402- sHud.getPathBar().pushLabel(R.drawable.icon_folder_small, setName, new Runnable() {
1399+ if (mHud.getPathBar().getNumLevels() == 1) {
1400+ mHud.getPathBar().pushLabel(R.drawable.icon_folder_small, setName, new Runnable() {
14031401 public void run() {
14041402 if (mFeedAboutToChange) {
14051403 return;
14061404 }
1407- if (sHud.getAlpha() == 1.0f) {
1405+ if (mHud.getAlpha() == 1.0f) {
14081406 disableLocationFiltering();
14091407 if (mInputProcessor != null)
14101408 mInputProcessor.clearSelection();
14111409 setState(STATE_GRID_VIEW);
14121410 } else {
1413- sHud.setAlpha(1.0f);
1411+ mHud.setAlpha(1.0f);
14141412 }
14151413 }
14161414 });
--- a/src/com/cooliris/media/HudLayer.java
+++ b/src/com/cooliris/media/HudLayer.java
@@ -29,8 +29,8 @@ public final class HudLayer extends Layer {
2929 private final ImageButton mTopRightButton = new ImageButton();
3030 private final ImageButton mZoomInButton = new ImageButton();
3131 private final ImageButton mZoomOutButton = new ImageButton();
32- private static PathBarLayer sPathBar;
33- private static TimeBar sTimeBar;
32+ private PathBarLayer mPathBar;
33+ private TimeBar mTimeBar;
3434 private MenuBar.Menu[] mNormalBottomMenu = null;
3535 private MenuBar.Menu[] mSingleViewIntentBottomMenu = null;
3636 private final MenuBar mSelectionMenuBottom;
@@ -103,9 +103,9 @@ public final class HudLayer extends Layer {
103103
104104 HudLayer(Context context) {
105105 mAlpha = 1.0f;
106- if (sTimeBar == null) {
107- sTimeBar = new TimeBar(context);
108- sPathBar = new PathBarLayer();
106+ if (mTimeBar == null) {
107+ mTimeBar = new TimeBar(context);
108+ mPathBar = new PathBarLayer();
109109 }
110110 mTopRightButton.setSize((int) (100 * Gallery.PIXEL_DENSITY), (int) (94 * Gallery.PIXEL_DENSITY));
111111
@@ -191,7 +191,7 @@ public final class HudLayer extends Layer {
191191 public void setContext(Context context) {
192192 if (mContext != context) {
193193 mContext = context;
194- sTimeBar.regenerateStringsForContext(context);
194+ mTimeBar.regenerateStringsForContext(context);
195195 }
196196 }
197197
@@ -416,8 +416,8 @@ public final class HudLayer extends Layer {
416416 final float height = mHeight;
417417 closeSelectionMenu();
418418
419- sTimeBar.setPosition(0f, height - TimeBar.HEIGHT * Gallery.PIXEL_DENSITY);
420- sTimeBar.setSize(width, TimeBar.HEIGHT * Gallery.PIXEL_DENSITY);
419+ mTimeBar.setPosition(0f, height - TimeBar.HEIGHT * Gallery.PIXEL_DENSITY);
420+ mTimeBar.setSize(width, TimeBar.HEIGHT * Gallery.PIXEL_DENSITY);
421421 mSelectionMenuTop.setPosition(0f, 0);
422422 mSelectionMenuTop.setSize(width, MenuBar.HEIGHT * Gallery.PIXEL_DENSITY);
423423 mSelectionMenuBottom.setPosition(0f, height - MenuBar.HEIGHT * Gallery.PIXEL_DENSITY);
@@ -426,7 +426,7 @@ public final class HudLayer extends Layer {
426426 mFullscreenMenu.setPosition(0f, height - MenuBar.HEIGHT * Gallery.PIXEL_DENSITY);
427427 mFullscreenMenu.setSize(width, MenuBar.HEIGHT * Gallery.PIXEL_DENSITY);
428428
429- sPathBar.setPosition(0f, -4f * Gallery.PIXEL_DENSITY);
429+ mPathBar.setPosition(0f, -4f * Gallery.PIXEL_DENSITY);
430430 computeSizeForPathbar();
431431
432432 mTopRightButton.setPosition(width - mTopRightButton.getWidth(), 0f);
@@ -438,12 +438,12 @@ public final class HudLayer extends Layer {
438438 float pathBarWidth = mWidth
439439 - ((mGridLayer.getState() == GridLayer.STATE_FULL_SCREEN) ? 32 * Gallery.PIXEL_DENSITY
440440 : 120 * Gallery.PIXEL_DENSITY);
441- sPathBar.setSize(pathBarWidth, FloatMath.ceil(39 * Gallery.PIXEL_DENSITY));
442- sPathBar.recomputeComponents();
441+ mPathBar.setSize(pathBarWidth, FloatMath.ceil(39 * Gallery.PIXEL_DENSITY));
442+ mPathBar.recomputeComponents();
443443 }
444444
445445 public void setFeed(MediaFeed feed, int state, boolean needsLayout) {
446- sTimeBar.setFeed(feed, state, needsLayout);
446+ mTimeBar.setFeed(feed, state, needsLayout);
447447 }
448448
449449 public void onGridStateChanged() {
@@ -465,11 +465,11 @@ public final class HudLayer extends Layer {
465465 mZoomOutButton.setHidden(mFullscreenMenu.isHidden());
466466
467467 // Show the time bar in stack and grid states, except in selection mode.
468- sTimeBar.setHidden(fullscreenMode || selectionMode || stackMode);
468+ mTimeBar.setHidden(fullscreenMode || selectionMode || stackMode);
469469 // mTimeBar.setHidden(selectionMode || (state != GridLayer.STATE_TIMELINE && state != GridLayer.STATE_GRID_VIEW));
470470
471471 // Hide the path bar and top-right button in selection mode.
472- sPathBar.setHidden(selectionMode);
472+ mPathBar.setHidden(selectionMode);
473473 mTopRightButton.setHidden(selectionMode || fullscreenMode);
474474 computeSizeForPathbar();
475475
@@ -505,11 +505,11 @@ public final class HudLayer extends Layer {
505505 }
506506
507507 public TimeBar getTimeBar() {
508- return sTimeBar;
508+ return mTimeBar;
509509 }
510510
511511 public PathBarLayer getPathBar() {
512- return sPathBar;
512+ return mPathBar;
513513 }
514514
515515 public GridLayer getGridLayer() {
@@ -576,11 +576,11 @@ public final class HudLayer extends Layer {
576576 mTopRightButton.generate(view, lists);
577577 mZoomInButton.generate(view, lists);
578578 mZoomOutButton.generate(view, lists);
579- sTimeBar.generate(view, lists);
579+ mTimeBar.generate(view, lists);
580580 mSelectionMenuTop.generate(view, lists);
581581 mSelectionMenuBottom.generate(view, lists);
582582 mFullscreenMenu.generate(view, lists);
583- sPathBar.generate(view, lists);
583+ mPathBar.generate(view, lists);
584584 // mLoadingLayer.generate(view, lists);
585585 mView = view;
586586 }
@@ -619,7 +619,7 @@ public final class HudLayer extends Layer {
619619
620620 void reset() {
621621 mLoadingLayer.reset();
622- sTimeBar.regenerateStringsForContext(mContext);
622+ mTimeBar.regenerateStringsForContext(mContext);
623623 }
624624
625625 public void fullscreenSelectionChanged(MediaItem item, int index, int count) {
@@ -633,7 +633,7 @@ public final class HudLayer extends Layer {
633633 mCachedCaption = item.mCaption;
634634 mCachedPosition = location;
635635 mCachedCurrentLabel = location;
636- sPathBar.changeLabel(location);
636+ mPathBar.changeLabel(location);
637637 }
638638
639639 private void updateShareMenu() {
@@ -745,7 +745,7 @@ public final class HudLayer extends Layer {
745745
746746 public void swapFullscreenLabel() {
747747 mCachedCurrentLabel = (mCachedCurrentLabel == mCachedCaption || mCachedCaption == null) ? mCachedPosition : mCachedCaption;
748- sPathBar.changeLabel(mCachedCurrentLabel);
748+ mPathBar.changeLabel(mCachedCurrentLabel);
749749 }
750750
751751 public void clear() {
--- a/src/com/cooliris/media/MediaFeed.java
+++ b/src/com/cooliris/media/MediaFeed.java
@@ -242,7 +242,9 @@ public final class MediaFeed implements Runnable {
242242 }
243243
244244 public void removeMediaSet(MediaSet set) {
245- mMediaSets.remove(set);
245+ synchronized (mMediaSets) {
246+ mMediaSets.remove(set);
247+ }
246248 mMediaFeedNeedsToRun = true;
247249 }
248250
@@ -434,7 +436,7 @@ public final class MediaFeed implements Runnable {
434436 }
435437 if (expandedSetIndex == Shared.INVALID) {
436438 // We purge the sets outside this visibleRange.
437- int numSets = mMediaSets.size();
439+ int numSets = mediaSets.size();
438440 IndexRange visibleRange = mVisibleRange;
439441 IndexRange bufferedRange = mBufferedRange;
440442 boolean scanMediaSets = true;
@@ -463,7 +465,7 @@ public final class MediaFeed implements Runnable {
463465 }
464466 }
465467 }
466- numSets = mMediaSets.size();
468+ numSets = mediaSets.size();
467469 for (int i = 0; i < numSets; ++i) {
468470 MediaSet set = mediaSets.get(i);
469471 if (i >= bufferedRange.begin && i <= bufferedRange.end) {
--- a/src/com/cooliris/media/MediaSet.java
+++ b/src/com/cooliris/media/MediaSet.java
@@ -167,12 +167,12 @@ public class MediaSet {
167167 mMaxTimestamp = dateTaken;
168168 }
169169 } else if (item.isDateAddedValid()) {
170- long dateTaken = item.mDateAddedInSec * 1000;
171- if (dateTaken < mMinAddedTimestamp) {
172- mMinAddedTimestamp = dateTaken;
170+ long dateAdded = item.mDateAddedInSec * 1000;
171+ if (dateAdded < mMinAddedTimestamp) {
172+ mMinAddedTimestamp = dateAdded;
173173 }
174- if (dateTaken > mMaxAddedTimestamp) {
175- mMaxAddedTimestamp = dateTaken;
174+ if (dateAdded > mMaxAddedTimestamp) {
175+ mMaxAddedTimestamp = dateAdded;
176176 }
177177 }
178178
--- a/src/com/cooliris/media/RenderView.java
+++ b/src/com/cooliris/media/RenderView.java
@@ -864,6 +864,8 @@ public final class RenderView extends GLSurfaceView implements GLSurfaceView.Ren
864864 return false;
865865 }
866866 // Wait for the render thread to process this event.
867+ if (mTouchEventQueue.size() > 8 && event.getAction() == MotionEvent.ACTION_MOVE)
868+ return true;
867869 synchronized (mTouchEventQueue) {
868870 MotionEvent eventCopy = MotionEvent.obtain(event);
869871 mTouchEventQueue.addLast(eventCopy);
--- a/src/com/cooliris/media/SingleDataSource.java
+++ b/src/com/cooliris/media/SingleDataSource.java
@@ -60,8 +60,12 @@ public class SingleDataSource implements DataSource {
6060 public void shutdown() {
6161
6262 }
63+
64+ public boolean isSingleImage() {
65+ return mSingleUri;
66+ }
6367
64- public static boolean isSingleImageMode(String uriString) {
68+ private static boolean isSingleImageMode(String uriString) {
6569 return !uriString.equals(MediaStore.Images.Media.EXTERNAL_CONTENT_URI.toString())
6670 && !uriString.equals(MediaStore.Images.Media.INTERNAL_CONTENT_URI.toString());
6771 }