blob: a394508a79aeaf9b31e7b7e69c172f525bae1f74 [file] [log] [blame]
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.camera;
import com.android.camera.gallery.IImage;
import android.content.ContentResolver;
import android.graphics.Bitmap;
import android.os.Handler;
import android.provider.MediaStore;
import android.util.Log;
import java.util.ArrayList;
/**
* A dedicated decoding thread used by ImageGallery.
*/
public class ImageLoader {
@SuppressWarnings("unused")
private static final String TAG = "ImageLoader";
// Queue of work to do in the worker thread. The work is done in order.
private final ArrayList<WorkItem> mQueue = new ArrayList<WorkItem>();
// the worker thread and a done flag so we know when to exit
private boolean mDone;
private Thread mDecodeThread;
private ContentResolver mCr;
public interface LoadedCallback {
public void run(Bitmap result);
}
public void getBitmap(IImage image,
LoadedCallback imageLoadedRunnable,
int tag) {
if (mDecodeThread == null) {
start();
}
synchronized (mQueue) {
WorkItem w = new WorkItem(image, imageLoadedRunnable, tag);
mQueue.add(w);
mQueue.notifyAll();
}
}
public boolean cancel(final IImage image) {
synchronized (mQueue) {
int index = findItem(image);
if (index >= 0) {
mQueue.remove(index);
return true;
} else {
return false;
}
}
}
// 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;
}
}
return -1;
}
// 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 static class WorkItem {
IImage mImage;
LoadedCallback mOnLoadedRunnable;
int mTag;
WorkItem(IImage image, LoadedCallback onLoadedRunnable, int tag) {
mImage = image;
mOnLoadedRunnable = onLoadedRunnable;
mTag = tag;
}
}
public ImageLoader(ContentResolver cr, Handler handler) {
mCr = cr;
start();
}
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 call back by executing
// the given runnable so things can get updated appropriately.
public void run() {
while (true) {
WorkItem workItem = null;
synchronized (mQueue) {
if (mDone) {
break;
}
if (!mQueue.isEmpty()) {
workItem = mQueue.remove(0);
} else {
try {
mQueue.wait();
} catch (InterruptedException ex) {
// ignore the exception
}
continue;
}
}
final Bitmap b = workItem.mImage.miniThumbBitmap();
if (workItem.mOnLoadedRunnable != null) {
workItem.mOnLoadedRunnable.run(b);
}
}
}
}
private void start() {
if (mDecodeThread != null) {
return;
}
mDone = false;
Thread t = new Thread(new WorkerThread());
t.setName("image-loader");
mDecodeThread = t;
t.start();
}
public void stop() {
synchronized (mQueue) {
mDone = true;
mQueue.notifyAll();
}
if (mDecodeThread != null) {
try {
Thread t = mDecodeThread;
BitmapManager.instance().cancelThreadDecoding(t, mCr);
t.join();
mDecodeThread = null;
} catch (InterruptedException ex) {
// so now what?
}
}
}
}