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