summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera
diff options
context:
space:
mode:
authorAndroid (Google) Code Review <android-gerrit@google.com>2009-05-12 23:54:40 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2009-05-12 23:54:40 -0700
commit4af352aa53952e4c69563aee95c87140bd528f71 (patch)
treea20aa6e041648a7bf1090747cc46951a1cd5a53c /src/com/android/camera
parentbdaaf5ea009b8b652c7a638e6bc94bfc01da921b (diff)
parent341ad98e59d92769e1cc8ba68fa86c72dce0543b (diff)
downloadLegacyCamera-4af352aa53952e4c69563aee95c87140bd528f71.zip
LegacyCamera-4af352aa53952e4c69563aee95c87140bd528f71.tar.gz
LegacyCamera-4af352aa53952e4c69563aee95c87140bd528f71.tar.bz2
Merge change 1440 into donut
* changes: Make ImageLoader load image in order.
Diffstat (limited to 'src/com/android/camera')
-rw-r--r--src/com/android/camera/GridViewSpecial.java92
-rw-r--r--src/com/android/camera/ImageLoader.java97
-rw-r--r--src/com/android/camera/Util.java6
3 files changed, 109 insertions, 86 deletions
diff --git a/src/com/android/camera/GridViewSpecial.java b/src/com/android/camera/GridViewSpecial.java
index 23fd063..87751b3 100644
--- a/src/com/android/camera/GridViewSpecial.java
+++ b/src/com/android/camera/GridViewSpecial.java
@@ -38,6 +38,8 @@ import android.widget.Scroller;
import java.util.HashMap;
+import static com.android.camera.Util.Assert;
+
class GridViewSpecial extends View {
private static final String TAG = "GridViewSpecial";
@@ -140,28 +142,28 @@ class GridViewSpecial extends View {
};
public void setLoader(ImageLoader loader) {
- assert mRunning == false;
+ Assert(mRunning == false);
mLoader = loader;
}
public void setListener(Listener listener) {
- assert mRunning == false;
+ Assert(mRunning == false);
mListener = listener;
}
public void setDrawAdapter(DrawAdapter adapter) {
- assert mRunning == false;
+ Assert(mRunning == false);
mDrawAdapter = adapter;
}
public void setImageList(IImageList list) {
- assert mRunning == false;
+ Assert(mRunning == false);
mAllImages = list;
mCount = mAllImages.getCount();
}
public void setSizeChoice(int choice) {
- assert mRunning == false;
+ Assert(mRunning == false);
if (mSizeChoice == choice) return;
mSizeChoice = choice;
}
@@ -332,7 +334,7 @@ class GridViewSpecial extends View {
}
@Override
- public boolean onSingleTapUp(MotionEvent e) {
+ public boolean onSingleTapConfirmed(MotionEvent e) {
select(mCurrentSelection, false);
int index = computeSelectedIndex(e.getX(), e.getY());
if (index >= 0 && index < mCount) {
@@ -418,9 +420,9 @@ class GridViewSpecial extends View {
public void start() {
// These must be set before start().
- assert mLoader != null;
- assert mListener != null;
- assert mDrawAdapter != null;
+ Assert(mLoader != null);
+ Assert(mListener != null);
+ Assert(mDrawAdapter != null);
mRunning = true;
requestLayout();
}
@@ -706,8 +708,29 @@ class ImageBlockManager {
static final int REQUESTS_LOW = 3;
static final int REQUESTS_HIGH = 6;
- // Scan the cache and send requests to ImageLoader if needed.
+ // After clear requests currently in queue, start loading the thumbnails.
+ // We need to clear the queue first because the proper order of loading
+ // may have changed (because the visible region changed, or some images
+ // have been invalidated).
private void startLoading() {
+ clearLoaderQueue();
+ continueLoading();
+ }
+
+ private void clearLoaderQueue() {
+ int[] tags = mLoader.clearQueue();
+ for (int pos : tags) {
+ int row = pos / mColumns;
+ int col = pos - row * mColumns;
+ ImageBlock blk = mCache.get(row);
+ Assert(blk != null); // We won't reuse the block if it has pending
+ // requests. See getEmptyBlock().
+ blk.cancelRequest(col);
+ }
+ }
+
+ // Scan the cache and send requests to ImageLoader if needed.
+ private void continueLoading() {
// Check if we still have enough requests in the queue.
if (mPendingRequest >= REQUESTS_LOW) return;
@@ -722,10 +745,10 @@ class ImageBlockManager {
for (int d = 1; d <= range; d++) {
int after = mEndRow - 1 + d;
int before = mStartRow - d;
- if (after >= mCount && before < 0) {
+ if (after >= mRows && before < 0) {
break; // Nothing more the scan.
}
- if (after < mCount && scanOne(after)) return;
+ if (after < mRows && scanOne(after)) return;
if (before >= 0 && scanOne(before)) return;
}
}
@@ -738,7 +761,7 @@ class ImageBlockManager {
// Returns number of requests we issued for this row.
private int tryToLoad(int row) {
- assert row >= 0 && row < mRows;
+ Assert(row >= 0 && row < mRows);
ImageBlock blk = mCache.get(row);
if (blk == null) {
// Find an empty block
@@ -762,7 +785,7 @@ class ImageBlockManager {
for (int index : mCache.keySet()) {
// Make sure we don't reclaim a block which still has pending
// request.
- if (mCache.get(index).isBusy()) {
+ if (mCache.get(index).hasPendingRequests()) {
continue;
}
int dist = 0;
@@ -906,7 +929,7 @@ class ImageBlockManager {
}
public void invalidate() {
- // We do not change mRequestedMask or do cancelExistingRequests()
+ // We do not change mRequestedMask or do cancelAllRequests()
// because the data coming from pending requests are valid. (We only
// invalidate data which has been drawn to the bitmap).
mCompletedMask = 0;
@@ -914,7 +937,7 @@ class ImageBlockManager {
// After recycle, the ImageBlock instance should not be accessed.
public void recycle() {
- cancelExistingRequests();
+ cancelAllRequests();
mBitmap.recycle();
mBitmap = null;
}
@@ -925,7 +948,7 @@ class ImageBlockManager {
// Returns number of requests submitted to ImageLoader.
public int loadImages() {
- assert mRow != -1;
+ Assert(mRow != -1);
int columns = numColumns(mRow);
@@ -966,7 +989,7 @@ class ImageBlockManager {
}
};
// Load Image
- mLoader.getBitmap(image, cb, isVisible());
+ mLoader.getBitmap(image, cb, pos);
mRequestedMask |= (1 << col);
retVal += 1;
}
@@ -976,7 +999,7 @@ class ImageBlockManager {
}
// Whether this block has pending requests.
- public boolean isBusy() {
+ public boolean hasPendingRequests() {
return mRequestedMask != 0;
}
@@ -998,20 +1021,18 @@ class ImageBlockManager {
}
int mask = (1 << col);
- assert (mRequestedMask & mask) != 0;
- assert (mCompletedMask & mask) == 0;
+ Assert((mCompletedMask & mask) == 0);
+ Assert((mRequestedMask & mask) != 0);
mRequestedMask &= ~mask;
mCompletedMask |= mask;
mPendingRequest--;
- if (mRequestedMask == 0) {
- if (isVisible()) {
- mRedrawCallback.run();
- }
+ if (isVisible()) {
+ mRedrawCallback.run();
}
// Kick start next block loading.
- startLoading();
+ continueLoading();
}
// Draw the loaded bitmap to the block bitmap.
@@ -1059,11 +1080,20 @@ class ImageBlockManager {
}
}
- // Try to cancel pending requests. After this there could still be
- // requests not cancelled (because it is already in progress). We deal
- // with that situation by setting mBitmap to null in recycle() and check
- // this in loadImageDone().
- private void cancelExistingRequests() {
+ // Mark a request as cancelled. The request has already been removed
+ // from the queue of ImageLoader, so we only need to mark the fact.
+ public void cancelRequest(int col) {
+ int mask = (1 << col);
+ Assert((mRequestedMask & mask) != 0);
+ mRequestedMask &= ~mask;
+ mPendingRequest--;
+ }
+
+ // Try to cancel all pending requests for this block. After this
+ // completes there could still be requests not cancelled (because it is
+ // already in progress). We deal with that situation by setting mBitmap to
+ // null in recycle() and check this in loadImageDone().
+ private void cancelAllRequests() {
for (int i = 0; i < mColumns; i++) {
int mask = (1 << i);
if ((mRequestedMask & mask) != 0) {
diff --git a/src/com/android/camera/ImageLoader.java b/src/com/android/camera/ImageLoader.java
index a349ea8..e71f5c3 100644
--- a/src/com/android/camera/ImageLoader.java
+++ b/src/com/android/camera/ImageLoader.java
@@ -33,9 +33,8 @@ public class ImageLoader {
@SuppressWarnings("unused")
private static final String TAG = "ImageLoader";
- // queue of work to do in the worker thread
+ // Queue of work to do in the worker thread. The work is done in order.
private final ArrayList<WorkItem> mQueue = new ArrayList<WorkItem>();
- private final ArrayList<WorkItem> mInProgress = new ArrayList<WorkItem>();
// the worker thread and a done flag so we know when to exit
private boolean mDone;
@@ -58,66 +57,63 @@ public class ImageLoader {
public void run(Bitmap result);
}
- public boolean cancel(final IImage image) {
+ public void getBitmap(IImage image,
+ LoadedCallback imageLoadedRunnable,
+ int tag) {
+ if (mDecodeThread == null) {
+ start();
+ }
synchronized (mQueue) {
- WorkItem w = new WorkItem(image, null);
+ WorkItem w = new WorkItem(image, imageLoadedRunnable, tag);
+ mQueue.add(w);
+ mQueue.notifyAll();
+ }
+ }
- int existing = mQueue.indexOf(w);
- if (existing >= 0) {
- mQueue.remove(existing);
+ public boolean cancel(final IImage image) {
+ synchronized (mQueue) {
+ int index = findItem(image);
+ if (index >= 0) {
+ mQueue.remove(index);
return true;
+ } else {
+ return false;
}
- return false;
}
}
- public void getBitmap(IImage image,
- LoadedCallback imageLoadedRunnable,
- boolean postAtFront) {
- if (mDecodeThread == null) {
- start();
+ // The caller should hold mQueue lock.
+ private int findItem(IImage image) {
+ for (int i = 0; i < mQueue.size(); i++) {
+ if (mQueue.get(i).mImage == image) {
+ return i;
+ }
}
- synchronized (mQueue) {
- WorkItem w = new WorkItem(image, imageLoadedRunnable);
-
- if (mInProgress.contains(w)) return;
+ return -1;
+ }
- boolean contains = mQueue.contains(w);
- if (contains) {
- if (postAtFront) {
- // move this item to the front
- mQueue.remove(w);
- mQueue.add(0, w);
- }
- } else {
- if (postAtFront) {
- mQueue.add(0, w);
- } else {
- mQueue.add(w);
- }
- mQueue.notifyAll();
+ // Clear the queue. Returns an array of tags that were in the queue.
+ public int[] clearQueue() {
+ synchronized (mQueue) {
+ int n = mQueue.size();
+ int[] tags = new int[n];
+ for (int i = 0; i < n; i++) {
+ tags[i] = mQueue.get(i).mTag;
}
+ mQueue.clear();
+ return tags;
}
}
private class WorkItem {
IImage mImage;
LoadedCallback mOnLoadedRunnable;
+ int mTag;
- WorkItem(IImage image, LoadedCallback onLoadedRunnable) {
+ WorkItem(IImage image, LoadedCallback onLoadedRunnable, int tag) {
mImage = image;
mOnLoadedRunnable = onLoadedRunnable;
- }
-
- @Override
- public boolean equals(Object other) {
- WorkItem otherWorkItem = (WorkItem) other;
- return otherWorkItem.mImage == mImage;
- }
-
- @Override
- public int hashCode() {
- return mImage.fullSizeImageUri().hashCode();
+ mTag = tag;
}
}
@@ -128,16 +124,15 @@ public class ImageLoader {
}
private class WorkerThread implements Runnable {
- // pick off items on the queue, one by one, and compute their bitmap.
- // place the resulting bitmap in the cache. then callback by executing
+ // Pick off items on the queue, one by one, and compute their bitmap.
+ // Place the resulting bitmap in the cache, then call back by executing
// the given runnable so things can get updated appropriately.
public void run() {
while (!mDone) {
WorkItem workItem = null;
synchronized (mQueue) {
- if (mQueue.size() > 0) {
+ if (!mQueue.isEmpty()) {
workItem = mQueue.remove(0);
- mInProgress.add(workItem);
} else {
if (!mThumbnailChecker.hasMoreThumbnailsToCheck()) {
try {
@@ -160,14 +155,6 @@ public class ImageLoader {
final Bitmap b = workItem.mImage.miniThumbBitmap();
- synchronized (mQueue) {
- mInProgress.remove(workItem);
- }
-
- if (mDone) {
- break;
- }
-
if (workItem.mOnLoadedRunnable != null) {
workItem.mOnLoadedRunnable.run(b);
}
diff --git a/src/com/android/camera/Util.java b/src/com/android/camera/Util.java
index 4991d0e..991fe39 100644
--- a/src/com/android/camera/Util.java
+++ b/src/com/android/camera/Util.java
@@ -406,4 +406,10 @@ public class Util {
}
return sNullOnClickListener;
}
+
+ public static void Assert(boolean cond) {
+ if (!cond) {
+ throw new AssertionError();
+ }
+ }
}