1666ea1b28a76aeba74744148b15099254d918671Owen Lin/* 2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2007 The Android Open Source Project 3666ea1b28a76aeba74744148b15099254d918671Owen Lin * 4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License. 6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at 7666ea1b28a76aeba74744148b15099254d918671Owen Lin * 8666ea1b28a76aeba74744148b15099254d918671Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9666ea1b28a76aeba74744148b15099254d918671Owen Lin * 10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software 11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and 14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License. 15666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 16666ea1b28a76aeba74744148b15099254d918671Owen Lin 17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera; 18666ea1b28a76aeba74744148b15099254d918671Owen Lin 19666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImage; 20666ea1b28a76aeba74744148b15099254d918671Owen Lin 21666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver; 22666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap; 23666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Handler; 24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore; 25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.Log; 26666ea1b28a76aeba74744148b15099254d918671Owen Lin 27666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.ArrayList; 28666ea1b28a76aeba74744148b15099254d918671Owen Lin 29666ea1b28a76aeba74744148b15099254d918671Owen Lin/** 30666ea1b28a76aeba74744148b15099254d918671Owen Lin * A dedicated decoding thread used by ImageGallery. 31666ea1b28a76aeba74744148b15099254d918671Owen Lin */ 32666ea1b28a76aeba74744148b15099254d918671Owen Linpublic class ImageLoader { 33666ea1b28a76aeba74744148b15099254d918671Owen Lin @SuppressWarnings("unused") 34666ea1b28a76aeba74744148b15099254d918671Owen Lin private static final String TAG = "ImageLoader"; 35666ea1b28a76aeba74744148b15099254d918671Owen Lin 36666ea1b28a76aeba74744148b15099254d918671Owen Lin // Queue of work to do in the worker thread. The work is done in order. 37666ea1b28a76aeba74744148b15099254d918671Owen Lin private final ArrayList<WorkItem> mQueue = new ArrayList<WorkItem>(); 38666ea1b28a76aeba74744148b15099254d918671Owen Lin 39666ea1b28a76aeba74744148b15099254d918671Owen Lin // the worker thread and a done flag so we know when to exit 40666ea1b28a76aeba74744148b15099254d918671Owen Lin private boolean mDone; 41666ea1b28a76aeba74744148b15099254d918671Owen Lin private Thread mDecodeThread; 42666ea1b28a76aeba74744148b15099254d918671Owen Lin private ContentResolver mCr; 43666ea1b28a76aeba74744148b15099254d918671Owen Lin 44666ea1b28a76aeba74744148b15099254d918671Owen Lin public interface LoadedCallback { 45666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run(Bitmap result); 46666ea1b28a76aeba74744148b15099254d918671Owen Lin } 47666ea1b28a76aeba74744148b15099254d918671Owen Lin 48666ea1b28a76aeba74744148b15099254d918671Owen Lin public void getBitmap(IImage image, 49666ea1b28a76aeba74744148b15099254d918671Owen Lin LoadedCallback imageLoadedRunnable, 50666ea1b28a76aeba74744148b15099254d918671Owen Lin int tag) { 51666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mDecodeThread == null) { 52666ea1b28a76aeba74744148b15099254d918671Owen Lin start(); 53666ea1b28a76aeba74744148b15099254d918671Owen Lin } 54666ea1b28a76aeba74744148b15099254d918671Owen Lin synchronized (mQueue) { 55666ea1b28a76aeba74744148b15099254d918671Owen Lin WorkItem w = new WorkItem(image, imageLoadedRunnable, tag); 56666ea1b28a76aeba74744148b15099254d918671Owen Lin mQueue.add(w); 57666ea1b28a76aeba74744148b15099254d918671Owen Lin mQueue.notifyAll(); 58666ea1b28a76aeba74744148b15099254d918671Owen Lin } 59666ea1b28a76aeba74744148b15099254d918671Owen Lin } 60666ea1b28a76aeba74744148b15099254d918671Owen Lin 61666ea1b28a76aeba74744148b15099254d918671Owen Lin public boolean cancel(final IImage image) { 62666ea1b28a76aeba74744148b15099254d918671Owen Lin synchronized (mQueue) { 63666ea1b28a76aeba74744148b15099254d918671Owen Lin int index = findItem(image); 64666ea1b28a76aeba74744148b15099254d918671Owen Lin if (index >= 0) { 65666ea1b28a76aeba74744148b15099254d918671Owen Lin mQueue.remove(index); 66666ea1b28a76aeba74744148b15099254d918671Owen Lin return true; 67666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 68666ea1b28a76aeba74744148b15099254d918671Owen Lin return false; 69666ea1b28a76aeba74744148b15099254d918671Owen Lin } 70666ea1b28a76aeba74744148b15099254d918671Owen Lin } 71666ea1b28a76aeba74744148b15099254d918671Owen Lin } 72666ea1b28a76aeba74744148b15099254d918671Owen Lin 73666ea1b28a76aeba74744148b15099254d918671Owen Lin // The caller should hold mQueue lock. 74666ea1b28a76aeba74744148b15099254d918671Owen Lin private int findItem(IImage image) { 75666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < mQueue.size(); i++) { 76666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mQueue.get(i).mImage == image) { 77666ea1b28a76aeba74744148b15099254d918671Owen Lin return i; 78666ea1b28a76aeba74744148b15099254d918671Owen Lin } 79666ea1b28a76aeba74744148b15099254d918671Owen Lin } 80666ea1b28a76aeba74744148b15099254d918671Owen Lin return -1; 81666ea1b28a76aeba74744148b15099254d918671Owen Lin } 82666ea1b28a76aeba74744148b15099254d918671Owen Lin 83666ea1b28a76aeba74744148b15099254d918671Owen Lin // Clear the queue. Returns an array of tags that were in the queue. 84666ea1b28a76aeba74744148b15099254d918671Owen Lin public int[] clearQueue() { 85666ea1b28a76aeba74744148b15099254d918671Owen Lin synchronized (mQueue) { 86666ea1b28a76aeba74744148b15099254d918671Owen Lin int n = mQueue.size(); 87666ea1b28a76aeba74744148b15099254d918671Owen Lin int[] tags = new int[n]; 88666ea1b28a76aeba74744148b15099254d918671Owen Lin for (int i = 0; i < n; i++) { 89666ea1b28a76aeba74744148b15099254d918671Owen Lin tags[i] = mQueue.get(i).mTag; 90666ea1b28a76aeba74744148b15099254d918671Owen Lin } 91666ea1b28a76aeba74744148b15099254d918671Owen Lin mQueue.clear(); 92666ea1b28a76aeba74744148b15099254d918671Owen Lin return tags; 93666ea1b28a76aeba74744148b15099254d918671Owen Lin } 94666ea1b28a76aeba74744148b15099254d918671Owen Lin } 95666ea1b28a76aeba74744148b15099254d918671Owen Lin 96666ea1b28a76aeba74744148b15099254d918671Owen Lin private static class WorkItem { 97666ea1b28a76aeba74744148b15099254d918671Owen Lin IImage mImage; 98666ea1b28a76aeba74744148b15099254d918671Owen Lin LoadedCallback mOnLoadedRunnable; 99666ea1b28a76aeba74744148b15099254d918671Owen Lin int mTag; 100666ea1b28a76aeba74744148b15099254d918671Owen Lin 101666ea1b28a76aeba74744148b15099254d918671Owen Lin WorkItem(IImage image, LoadedCallback onLoadedRunnable, int tag) { 102666ea1b28a76aeba74744148b15099254d918671Owen Lin mImage = image; 103666ea1b28a76aeba74744148b15099254d918671Owen Lin mOnLoadedRunnable = onLoadedRunnable; 104666ea1b28a76aeba74744148b15099254d918671Owen Lin mTag = tag; 105666ea1b28a76aeba74744148b15099254d918671Owen Lin } 106666ea1b28a76aeba74744148b15099254d918671Owen Lin } 107666ea1b28a76aeba74744148b15099254d918671Owen Lin 108666ea1b28a76aeba74744148b15099254d918671Owen Lin public ImageLoader(ContentResolver cr, Handler handler) { 109666ea1b28a76aeba74744148b15099254d918671Owen Lin mCr = cr; 110666ea1b28a76aeba74744148b15099254d918671Owen Lin start(); 111666ea1b28a76aeba74744148b15099254d918671Owen Lin } 112666ea1b28a76aeba74744148b15099254d918671Owen Lin 113666ea1b28a76aeba74744148b15099254d918671Owen Lin private class WorkerThread implements Runnable { 114666ea1b28a76aeba74744148b15099254d918671Owen Lin 115666ea1b28a76aeba74744148b15099254d918671Owen Lin // Pick off items on the queue, one by one, and compute their bitmap. 116666ea1b28a76aeba74744148b15099254d918671Owen Lin // Place the resulting bitmap in the cache, then call back by executing 117666ea1b28a76aeba74744148b15099254d918671Owen Lin // the given runnable so things can get updated appropriately. 118666ea1b28a76aeba74744148b15099254d918671Owen Lin public void run() { 119666ea1b28a76aeba74744148b15099254d918671Owen Lin while (true) { 120666ea1b28a76aeba74744148b15099254d918671Owen Lin WorkItem workItem = null; 121666ea1b28a76aeba74744148b15099254d918671Owen Lin synchronized (mQueue) { 122666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mDone) { 123666ea1b28a76aeba74744148b15099254d918671Owen Lin break; 124666ea1b28a76aeba74744148b15099254d918671Owen Lin } 125666ea1b28a76aeba74744148b15099254d918671Owen Lin if (!mQueue.isEmpty()) { 126666ea1b28a76aeba74744148b15099254d918671Owen Lin workItem = mQueue.remove(0); 127666ea1b28a76aeba74744148b15099254d918671Owen Lin } else { 128666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 129666ea1b28a76aeba74744148b15099254d918671Owen Lin mQueue.wait(); 130666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (InterruptedException ex) { 131666ea1b28a76aeba74744148b15099254d918671Owen Lin // ignore the exception 132666ea1b28a76aeba74744148b15099254d918671Owen Lin } 133666ea1b28a76aeba74744148b15099254d918671Owen Lin continue; 134666ea1b28a76aeba74744148b15099254d918671Owen Lin } 135666ea1b28a76aeba74744148b15099254d918671Owen Lin } 136666ea1b28a76aeba74744148b15099254d918671Owen Lin 137666ea1b28a76aeba74744148b15099254d918671Owen Lin final Bitmap b = workItem.mImage.miniThumbBitmap(); 138666ea1b28a76aeba74744148b15099254d918671Owen Lin 139666ea1b28a76aeba74744148b15099254d918671Owen Lin if (workItem.mOnLoadedRunnable != null) { 140666ea1b28a76aeba74744148b15099254d918671Owen Lin workItem.mOnLoadedRunnable.run(b); 141666ea1b28a76aeba74744148b15099254d918671Owen Lin } 142666ea1b28a76aeba74744148b15099254d918671Owen Lin } 143666ea1b28a76aeba74744148b15099254d918671Owen Lin } 144666ea1b28a76aeba74744148b15099254d918671Owen Lin } 145666ea1b28a76aeba74744148b15099254d918671Owen Lin 146666ea1b28a76aeba74744148b15099254d918671Owen Lin private void start() { 147666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mDecodeThread != null) { 148666ea1b28a76aeba74744148b15099254d918671Owen Lin return; 149666ea1b28a76aeba74744148b15099254d918671Owen Lin } 150666ea1b28a76aeba74744148b15099254d918671Owen Lin 151666ea1b28a76aeba74744148b15099254d918671Owen Lin mDone = false; 152666ea1b28a76aeba74744148b15099254d918671Owen Lin Thread t = new Thread(new WorkerThread()); 153666ea1b28a76aeba74744148b15099254d918671Owen Lin t.setName("image-loader"); 154666ea1b28a76aeba74744148b15099254d918671Owen Lin mDecodeThread = t; 155666ea1b28a76aeba74744148b15099254d918671Owen Lin t.start(); 156666ea1b28a76aeba74744148b15099254d918671Owen Lin } 157666ea1b28a76aeba74744148b15099254d918671Owen Lin 158666ea1b28a76aeba74744148b15099254d918671Owen Lin public void stop() { 159666ea1b28a76aeba74744148b15099254d918671Owen Lin synchronized (mQueue) { 160666ea1b28a76aeba74744148b15099254d918671Owen Lin mDone = true; 161666ea1b28a76aeba74744148b15099254d918671Owen Lin mQueue.notifyAll(); 162666ea1b28a76aeba74744148b15099254d918671Owen Lin } 163666ea1b28a76aeba74744148b15099254d918671Owen Lin if (mDecodeThread != null) { 164666ea1b28a76aeba74744148b15099254d918671Owen Lin try { 165666ea1b28a76aeba74744148b15099254d918671Owen Lin Thread t = mDecodeThread; 1668aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin BitmapManager.instance().cancelThreadDecoding(t, mCr); 167666ea1b28a76aeba74744148b15099254d918671Owen Lin t.join(); 168666ea1b28a76aeba74744148b15099254d918671Owen Lin mDecodeThread = null; 169666ea1b28a76aeba74744148b15099254d918671Owen Lin } catch (InterruptedException ex) { 170666ea1b28a76aeba74744148b15099254d918671Owen Lin // so now what? 171666ea1b28a76aeba74744148b15099254d918671Owen Lin } 172666ea1b28a76aeba74744148b15099254d918671Owen Lin } 173666ea1b28a76aeba74744148b15099254d918671Owen Lin } 174666ea1b28a76aeba74744148b15099254d918671Owen Lin} 175