summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorChih-Chung Chang <chihchung@google.com>2009-04-27 19:43:36 +0800
committerChih-Chung Chang <chihchung@google.com>2009-04-28 10:26:38 +0800
commitff9922fb1a15f70ba34f35bc50c5b5ef52c174b2 (patch)
treea7ebc84bdd4040c8a25e41aa2a1868fd07b5e140 /src/com
parentebd325f9fd8fec33e7961a876c7f5d5934f36411 (diff)
downloadLegacyCamera-ff9922fb1a15f70ba34f35bc50c5b5ef52c174b2.zip
LegacyCamera-ff9922fb1a15f70ba34f35bc50c5b5ef52c174b2.tar.gz
LegacyCamera-ff9922fb1a15f70ba34f35bc50c5b5ef52c174b2.tar.bz2
In Gallery, make visible thumbnails appear faster.
Put checkThumbnails and getBitmap to the same thread in ImageLoader, and only do checkThumbnails when there are no getBitmap requests.
Diffstat (limited to 'src/com')
-rw-r--r--src/com/android/camera/GridViewSpecial.java12
-rw-r--r--src/com/android/camera/ImageGallery.java130
-rw-r--r--src/com/android/camera/ImageLoader.java125
-rwxr-xr-xsrc/com/android/camera/ImageManager.java3
-rw-r--r--src/com/android/camera/gallery/BaseImage.java4
-rw-r--r--src/com/android/camera/gallery/BaseImageList.java33
-rw-r--r--src/com/android/camera/gallery/DrmImageList.java9
-rw-r--r--src/com/android/camera/gallery/IImageList.java17
-rw-r--r--src/com/android/camera/gallery/Image.java3
-rw-r--r--src/com/android/camera/gallery/ImageListUber.java13
10 files changed, 200 insertions, 149 deletions
diff --git a/src/com/android/camera/GridViewSpecial.java b/src/com/android/camera/GridViewSpecial.java
index ce5c52e..5d9deff 100644
--- a/src/com/android/camera/GridViewSpecial.java
+++ b/src/com/android/camera/GridViewSpecial.java
@@ -30,6 +30,7 @@ class GridViewSpecial extends View {
ImageBlockManager mImageBlockManager;
private Handler mHandler;
+ private ImageLoader mLoader;
private LayoutSpec mCurrentSpec;
boolean mShowSelection = false;
@@ -91,7 +92,7 @@ class GridViewSpecial extends View {
public void invalidateAllImages() {
this.clearCache();
- mImageBlockManager = new ImageBlockManager();
+ mImageBlockManager = new ImageBlockManager(mLoader);
mImageBlockManager.moveDataWindow(true);
}
@@ -307,7 +308,7 @@ class GridViewSpecial extends View {
* (spec.mCellSpacing + spec.mCellHeight))
- (bottom - top) ;
if (mImageBlockManager == null) {
- mImageBlockManager = new ImageBlockManager();
+ mImageBlockManager = new ImageBlockManager(mLoader);
mImageBlockManager.moveDataWindow(true);
}
mLayoutComplete = true;
@@ -334,8 +335,8 @@ class GridViewSpecial extends View {
private Thread mWorkerThread;
- ImageBlockManager() {
- mLoader = new ImageLoader(mHandler);
+ ImageBlockManager(ImageLoader loader) {
+ mLoader = loader;
mBlockCache = new ImageBlock[sRowsPerPage
* (sPagesPreCache + sPagesPostCache + 1)];
@@ -887,8 +888,9 @@ class GridViewSpecial extends View {
}
}
- public void init(Handler handler) {
+ public void init(Handler handler, ImageLoader loader) {
mHandler = handler;
+ mLoader = loader;
}
@Override
diff --git a/src/com/android/camera/ImageGallery.java b/src/com/android/camera/ImageGallery.java
index 7dfdd80..a926f34 100644
--- a/src/com/android/camera/ImageGallery.java
+++ b/src/com/android/camera/ImageGallery.java
@@ -79,9 +79,8 @@ public class ImageGallery extends Activity implements
Handler mHandler = new Handler();
boolean mLayoutComplete;
boolean mPausing = false;
- boolean mStopThumbnailChecking = false;
+ ImageLoader mLoader;
- BitmapThread mThumbnailCheckThread;
GridViewSpecial mGvs;
// The index of the first picture in GridViewSpecial.
@@ -117,6 +116,8 @@ public class ImageGallery extends Activity implements
mGvs.setOnCreateContextMenuListener(
new CreateContextMenuListener());
}
+
+ mLoader = new ImageLoader(mHandler);
}
private MenuItem addSlideShowMenu(Menu menu, int position) {
@@ -347,7 +348,7 @@ public class ImageGallery extends Activity implements
mAllImages = allImages(!unmounted);
mGvs.setImageList(mAllImages);
mGvs.setDrawAdapter(this);
- mGvs.init(mHandler);
+ mGvs.init(mHandler, mLoader);
mGvs.start();
mGvs.requestLayout();
checkThumbnails();
@@ -427,51 +428,14 @@ public class ImageGallery extends Activity implements
}
private void stopCheckingThumbnails() {
- mStopThumbnailChecking = true;
- if (mThumbnailCheckThread != null) {
- mThumbnailCheckThread.join();
- }
- mStopThumbnailChecking = false;
+ mLoader.stopCheckingThumbnails();
}
private void checkThumbnails() {
- final long startTime = System.currentTimeMillis();
- mThumbnailCheckThread = new BitmapThread(new Runnable() {
- public void run() {
- Resources resources = getResources();
- TextView progressTextView =
- (TextView) findViewById(R.id.loading_text);
- String progressTextFormatString =
- resources.getString(
- R.string.loading_progress_format_string);
-
- PowerManager pm = (PowerManager)
- getSystemService(Context.POWER_SERVICE);
- PowerManager.WakeLock mWakeLock = pm.newWakeLock(
- PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
- "ImageGallery.checkThumbnails");
- mWakeLock.acquire();
- IImageList.ThumbCheckCallback r = new MyThumbCheckCallback(
- progressTextView, startTime, progressTextFormatString);
- IImageList imageList = allImages(true);
- imageList.checkThumbnails(r, imageList.getCount());
- mWakeLock.release();
- mThumbnailCheckThread = null;
- mHandler.post(new Runnable() {
- public void run() {
- findViewById(R.id.loading_indicator).setVisibility(
- View.GONE);
- }
- });
- }
- });
-
- mThumbnailCheckThread.setName("check_thumbnails");
- mThumbnailCheckThread.start();
- mThumbnailCheckThread.toBackground();
-
- IImageList list = allImages(true);
- mNoImagesView.setVisibility(list.getCount() > 0
+ ImageLoader.ThumbCheckCallback cb = new MyThumbCheckCallback();
+ IImageList imageList = allImages(true);
+ mLoader.startCheckingThumbnails(imageList, cb);
+ mNoImagesView.setVisibility(imageList.getCount() > 0
? View.GONE
: View.VISIBLE);
}
@@ -667,25 +631,27 @@ public class ImageGallery extends Activity implements
}
}
- private final class MyThumbCheckCallback implements IImageList.ThumbCheckCallback {
- private final TextView progressTextView;
- private final long startTime;
- private final String progressTextFormatString;
+ private final class MyThumbCheckCallback implements
+ ImageLoader.ThumbCheckCallback {
+ private final TextView mProgressTextView;
+ private final String mProgressTextFormatString;
boolean mDidSetProgress = false;
-
- private MyThumbCheckCallback(TextView progressTextView, long startTime,
- String progressTextFormatString) {
- this.progressTextView = progressTextView;
- this.startTime = startTime;
- this.progressTextFormatString = progressTextFormatString;
+ private PowerManager.WakeLock mWakeLock;
+
+ private MyThumbCheckCallback() {
+ Resources resources = getResources();
+ mProgressTextView = (TextView) findViewById(R.id.loading_text);
+ mProgressTextFormatString = resources.getString(
+ R.string.loading_progress_format_string);
+ PowerManager pm = (PowerManager)
+ getSystemService(Context.POWER_SERVICE);
+ mWakeLock = pm.newWakeLock(
+ PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
+ "ImageGallery.checkThumbnails");
+ mWakeLock.acquire();
}
- public boolean checking(final int count,
- final int maxCount) {
- if (mStopThumbnailChecking) {
- return false;
- }
-
+ public boolean checking(final int count, final int maxCount) {
if (!mLayoutComplete) {
return true;
}
@@ -693,31 +659,38 @@ public class ImageGallery extends Activity implements
if (!mDidSetProgress) {
mHandler.post(new Runnable() {
public void run() {
- findViewById(
- R.id.loading_indicator)
- .setVisibility(View.VISIBLE);
+ View v = findViewById(R.id.loading_indicator);
+ v.setVisibility(View.VISIBLE);
}
});
mDidSetProgress = true;
}
mGvs.postInvalidate();
- // If there is a new image done and it has been
- // one second, update the progress text.
- if (System.currentTimeMillis()
- - startTime > 1000) {
- mHandler.post(new Runnable() {
- public void run() {
- String s = String.format(
- progressTextFormatString,
- maxCount - count);
- progressTextView.setText(s);
- }
- });
- }
+ // Update the progress text.
+ mHandler.post(new Runnable() {
+ public void run() {
+ String s = String.format(mProgressTextFormatString,
+ maxCount - count);
+ mProgressTextView.setText(s);
+ }
+ });
return !mPausing;
}
+
+ public void done() {
+ // done() should only be called once. Use mWakeLock to verify this.
+ assert mWakeLock.isHeld();
+
+ mWakeLock.release();
+ mHandler.post(new Runnable() {
+ public void run() {
+ findViewById(R.id.loading_indicator).setVisibility(
+ View.GONE);
+ }
+ });
+ }
}
private class CreateContextMenuListener implements
@@ -902,7 +875,4 @@ public class ImageGallery extends Activity implements
return mMissingVideoThumbnailBitmap;
}
}
-
}
-
-
diff --git a/src/com/android/camera/ImageLoader.java b/src/com/android/camera/ImageLoader.java
index ad67b14..667bd5b 100644
--- a/src/com/android/camera/ImageLoader.java
+++ b/src/com/android/camera/ImageLoader.java
@@ -17,11 +17,14 @@
package com.android.camera;
import com.android.camera.gallery.IImage;
+import com.android.camera.gallery.IImageList;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.Handler;
+import android.util.Log;
+import java.io.IOException;
import java.util.ArrayList;
/**
@@ -36,11 +39,22 @@ public class ImageLoader {
private final ArrayList<WorkItem> mInProgress = new ArrayList<WorkItem>();
// the worker thread and a done flag so we know when to exit
- // currently we only exit from finalize
private boolean mDone;
private Thread mDecodeThread;
private final Handler mHandler;
+ // Thumbnail checking will be done when there is no getBitmap requests
+ // need to be processed.
+ private ThumbnailChecker mThumbnailChecker;
+
+ /**
+ * Notify interface of how many thumbnails are processed.
+ */
+ public interface ThumbCheckCallback {
+ public boolean checking(int current, int count);
+ public void done();
+ }
+
public interface LoadedCallback {
public void run(Bitmap result);
}
@@ -118,6 +132,7 @@ public class ImageLoader {
public ImageLoader(Handler handler) {
mHandler = handler;
+ mThumbnailChecker = new ThumbnailChecker();
start();
}
@@ -134,15 +149,25 @@ public class ImageLoader {
workItem = mQueue.remove(0);
mInProgress.add(workItem);
} else {
- try {
- mQueue.wait();
- } catch (InterruptedException ex) {
- // ignore the exception
+ if (!mThumbnailChecker.hasMoreThumbnailsToCheck()) {
+ try {
+ mQueue.wait();
+ } catch (InterruptedException ex) {
+ // ignore the exception
+ }
+ continue;
}
- continue;
}
}
+ // This holds if and only if the above
+ // hasMoreThumbnailsToCheck() returns true. (We put the call
+ // here because we want to release the lock on mQueue.
+ if (workItem == null) {
+ mThumbnailChecker.checkNextThumbnail();
+ continue;
+ }
+
final Bitmap b = workItem.mImage.miniThumbBitmap();
synchronized (mQueue) {
@@ -197,5 +222,93 @@ public class ImageLoader {
// so now what?
}
}
+ stopCheckingThumbnails();
+ }
+
+ // Passthrough to ThumbnailChecker.
+ public void startCheckingThumbnails(IImageList imageList,
+ ThumbCheckCallback cb) {
+ mThumbnailChecker.startCheckingThumbnails(imageList, cb);
+ // Kick WorkerThread to start working.
+ synchronized (mQueue) {
+ mQueue.notifyAll();
+ }
+ }
+
+ public void stopCheckingThumbnails() {
+ mThumbnailChecker.stopCheckingThumbnails();
+ }
+}
+
+// This is part of ImageLoader which is responsible for checking thumbnails.
+//
+// The methods of ThumbnailChecker need to be synchronized because the data
+// will also be accessed by the WorkerThread. The methods of ThumbnailChecker
+// is only called by ImageLoader.
+class ThumbnailChecker {
+ private static final String TAG = "ThumbnailChecker";
+
+ private IImageList mImageListToCheck; // The image list we will check.
+ private int mTotalToCheck; // total number of thumbnails to check.
+ private int mNextToCheck; // next thumbnail to check,
+ // -1 if no further checking is needed.
+ private ImageLoader.ThumbCheckCallback mThumbCheckCallback;
+
+ ThumbnailChecker() {
+ mNextToCheck = -1;
+ }
+
+ // Both imageList and cb must be non-null.
+ synchronized void startCheckingThumbnails(IImageList imageList,
+ ImageLoader.ThumbCheckCallback cb) {
+ assert imageList != null;
+ assert cb != null;
+ mImageListToCheck = imageList;
+ mTotalToCheck = imageList.getCount();
+ mNextToCheck = 0;
+ mThumbCheckCallback = cb;
+
+ if (!ImageManager.hasStorage()) {
+ Log.v(TAG, "bailing from the image checker -- no storage");
+ stopCheckingThumbnails();
+ }
+ }
+
+ synchronized void stopCheckingThumbnails() {
+ if (mThumbCheckCallback == null) return; // alreay stopped.
+ mThumbCheckCallback.done();
+ mImageListToCheck = null;
+ mTotalToCheck = 0;
+ mNextToCheck = -1;
+ mThumbCheckCallback = null;
+ }
+
+ synchronized boolean hasMoreThumbnailsToCheck() {
+ return mNextToCheck != -1;
+ }
+
+ synchronized void checkNextThumbnail() {
+ if (mNextToCheck == -1) {
+ return;
+ }
+
+ if (mNextToCheck >= mTotalToCheck) {
+ stopCheckingThumbnails();
+ return;
+ }
+
+ try {
+ mImageListToCheck.checkThumbnail(mNextToCheck);
+ } catch (IOException ex) {
+ Log.e(TAG, "Failed to check thumbnail..."
+ + " was the sd card removed? - " + ex.getMessage());
+ stopCheckingThumbnails();
+ }
+
+ if (!mThumbCheckCallback.checking(mNextToCheck, mTotalToCheck)) {
+ stopCheckingThumbnails();
+ }
+
+ mNextToCheck++;
}
}
diff --git a/src/com/android/camera/ImageManager.java b/src/com/android/camera/ImageManager.java
index 8a4b055..acd11aa 100755
--- a/src/com/android/camera/ImageManager.java
+++ b/src/com/android/camera/ImageManager.java
@@ -314,8 +314,7 @@ public class ImageManager {
}
private static class EmptyImageList implements IImageList {
- public void checkThumbnails(IImageList.ThumbCheckCallback cb,
- int totalThumbnails) {
+ public void checkThumbnail(int index) {
}
public void deactivate() {
diff --git a/src/com/android/camera/gallery/BaseImage.java b/src/com/android/camera/gallery/BaseImage.java
index 66d9289..33554ce 100644
--- a/src/com/android/camera/gallery/BaseImage.java
+++ b/src/com/android/camera/gallery/BaseImage.java
@@ -342,7 +342,7 @@ public abstract class BaseImage implements IImage {
long dbMagic = mMiniThumbMagic;
if (dbMagic == 0 || dbMagic == id) {
dbMagic = ((BaseImageList) getContainer())
- .checkThumbnail(this, getCursor(), getRow());
+ .checkThumbnail(this, getRow(), null);
}
synchronized (sMiniThumbData) {
@@ -353,7 +353,7 @@ public abstract class BaseImage implements IImage {
byte[][] createdThumbData = new byte[1][];
try {
dbMagic = ((BaseImageList) getContainer())
- .checkThumbnail(this, getCursor(), getRow(),
+ .checkThumbnail(this, getRow(),
createdThumbData);
} catch (IOException ex) {
// Typically IOException because the sd card is full.
diff --git a/src/com/android/camera/gallery/BaseImageList.java b/src/com/android/camera/gallery/BaseImageList.java
index e26f972..dba6398 100644
--- a/src/com/android/camera/gallery/BaseImageList.java
+++ b/src/com/android/camera/gallery/BaseImageList.java
@@ -207,17 +207,14 @@ public abstract class BaseImageList implements IImageList {
return bitmap;
}
- // returns id
- public long checkThumbnail(BaseImage existingImage, Cursor c, int i)
- throws IOException {
- return checkThumbnail(existingImage, c, i, null);
+ public void checkThumbnail(int index) throws IOException {
+ checkThumbnail(null, index, null);
}
/**
* Checks to see if a mini thumbnail exists in the cache. If not, tries to
* create it and add it to the cache.
* @param existingImage
- * @param c
* @param i
* @param createdThumbnailData if this parameter is non-null, and a new
* mini-thumbnail bitmap is created, the new bitmap's data will be
@@ -228,13 +225,14 @@ public abstract class BaseImageList implements IImageList {
* thumbnail even if the sdcard is full.
* @throws IOException
*/
- public long checkThumbnail(BaseImage existingImage, Cursor c, int i,
+ public long checkThumbnail(BaseImage existingImage, int i,
byte[][] createdThumbnailData) throws IOException {
long magic, id;
if (BitmapManager.instance().acquireResourceLock() == false) {
return -1;
}
+ Cursor c = getCursor();
try {
if (existingImage == null) {
// if we don't have an Image object then get the id and magic
@@ -321,29 +319,6 @@ public abstract class BaseImageList implements IImageList {
}
}
- public void checkThumbnails(ThumbCheckCallback cb, int totalThumbnails) {
- if (!ImageManager.hasStorage()) {
- Log.v(TAG, "bailing from the image checker thread -- no storage");
- return;
- }
-
- Cursor c = getCursor();
- for (int i = 0; i < c.getCount(); i++) {
- try {
- checkThumbnail(null, c, i);
- } catch (IOException ex) {
- Log.e(TAG, "!!!!! failed to check thumbnail..."
- + " was the sd card removed? - " + ex.getMessage());
- break;
- }
- if (cb != null) {
- if (!cb.checking(i, totalThumbnails)) {
- break;
- }
- }
- }
- }
-
protected Uri contentUri(long id) {
try {
// does our uri already have an id (single image query)?
diff --git a/src/com/android/camera/gallery/DrmImageList.java b/src/com/android/camera/gallery/DrmImageList.java
index ee976b9..68e9c07 100644
--- a/src/com/android/camera/gallery/DrmImageList.java
+++ b/src/com/android/camera/gallery/DrmImageList.java
@@ -48,14 +48,7 @@ public class DrmImageList extends ImageList implements IImageList {
}
@Override
- public void checkThumbnails(
- IImageList.ThumbCheckCallback cb, int totalCount) {
- // do nothing
- }
-
- @Override
- public long checkThumbnail(BaseImage existingImage, Cursor c, int i) {
- return 0;
+ public void checkThumbnail(int index) {
}
private class DrmImage extends Image {
diff --git a/src/com/android/camera/gallery/IImageList.java b/src/com/android/camera/gallery/IImageList.java
index 8be69ce..6820a35 100644
--- a/src/com/android/camera/gallery/IImageList.java
+++ b/src/com/android/camera/gallery/IImageList.java
@@ -18,6 +18,7 @@ package com.android.camera.gallery;
import android.net.Uri;
+import java.io.IOException;
import java.util.HashMap;
//
@@ -46,16 +47,6 @@ import java.util.HashMap;
public interface IImageList {
public HashMap<String, String> getBucketIds();
- /**
- * Notify interface of how many thumbnails are processed.
- */
- public interface ThumbCheckCallback {
- public boolean checking(int current, int count);
- }
-
- public abstract void checkThumbnails(
- IImageList.ThumbCheckCallback cb, int totalThumbnails);
-
public abstract void deactivate();
/**
@@ -99,4 +90,10 @@ public interface IImageList {
* @param i the position
*/
public abstract void removeImageAt(int i);
+
+ /**
+ * Generate thumbnail for the image (if it has not been generated.)
+ * @param index the position of the image
+ */
+ public abstract void checkThumbnail(int index) throws IOException;
}
diff --git a/src/com/android/camera/gallery/Image.java b/src/com/android/camera/gallery/Image.java
index 04ae09f..a8a6796 100644
--- a/src/com/android/camera/gallery/Image.java
+++ b/src/com/android/camera/gallery/Image.java
@@ -328,8 +328,7 @@ public class Image extends BaseImage implements IImage {
// fresh thumbs
mMiniThumbMagic = 0;
try {
- mContainer.checkThumbnail(
- this, mContainer.getCursor(), this.getRow());
+ mContainer.checkThumbnail(this, this.getRow(), null);
} catch (IOException e) {
// Ignore inability to store mini thumbnail.
}
diff --git a/src/com/android/camera/gallery/ImageListUber.java b/src/com/android/camera/gallery/ImageListUber.java
index 7cbc88b..4cd1ba1 100644
--- a/src/com/android/camera/gallery/ImageListUber.java
+++ b/src/com/android/camera/gallery/ImageListUber.java
@@ -20,6 +20,7 @@ import com.android.camera.ImageManager;
import android.net.Uri;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
@@ -54,11 +55,13 @@ public class ImageListUber implements IImageList {
mSort = sort;
}
- public void checkThumbnails(ThumbCheckCallback cb, int totalThumbnails) {
- for (IImageList i : mSubList) {
- int count = i.getCount();
- i.checkThumbnails(cb, totalThumbnails);
- totalThumbnails -= count;
+ public void checkThumbnail(int index) throws IOException {
+ for (IImageList list : mSubList) {
+ int count = list.getCount();
+ if (count > index) {
+ list.checkThumbnail(index);
+ }
+ index -= count;
}
}