1666ea1b28a76aeba74744148b15099254d918671Owen Lin/*
2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2009 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 Linimport com.android.camera.gallery.IImageList;
21666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.VideoObject;
22666ea1b28a76aeba74744148b15099254d918671Owen Lin
23666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver;
24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap;
25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Handler;
26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Message;
27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Process;
28666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore;
29666ea1b28a76aeba74744148b15099254d918671Owen Lin
30666ea1b28a76aeba74744148b15099254d918671Owen Lin/*
31666ea1b28a76aeba74744148b15099254d918671Owen Lin * Here's the loading strategy.  For any given image, load the thumbnail
32666ea1b28a76aeba74744148b15099254d918671Owen Lin * into memory and post a callback to display the resulting bitmap.
33666ea1b28a76aeba74744148b15099254d918671Owen Lin *
34666ea1b28a76aeba74744148b15099254d918671Owen Lin * Then proceed to load the full image bitmap.   Three things can
35666ea1b28a76aeba74744148b15099254d918671Owen Lin * happen at this point:
36666ea1b28a76aeba74744148b15099254d918671Owen Lin *
37666ea1b28a76aeba74744148b15099254d918671Owen Lin * 1.  the image fails to load because the UI thread decided
38666ea1b28a76aeba74744148b15099254d918671Owen Lin * to move on to a different image.  This "cancellation" happens
39666ea1b28a76aeba74744148b15099254d918671Owen Lin * by virtue of the UI thread closing the stream containing the
40666ea1b28a76aeba74744148b15099254d918671Owen Lin * image being decoded.  BitmapFactory.decodeStream returns null
41666ea1b28a76aeba74744148b15099254d918671Owen Lin * in this case.
42666ea1b28a76aeba74744148b15099254d918671Owen Lin *
43666ea1b28a76aeba74744148b15099254d918671Owen Lin * 2.  the image loaded successfully.  At that point we post
44666ea1b28a76aeba74744148b15099254d918671Owen Lin * a callback to the UI thread to actually show the bitmap.
45666ea1b28a76aeba74744148b15099254d918671Owen Lin *
46666ea1b28a76aeba74744148b15099254d918671Owen Lin * 3.  when the post runs it checks to see if the image that was
47666ea1b28a76aeba74744148b15099254d918671Owen Lin * loaded is still the one we want.  The UI may have moved on
48666ea1b28a76aeba74744148b15099254d918671Owen Lin * to some other image and if so we just drop the newly loaded
49666ea1b28a76aeba74744148b15099254d918671Owen Lin * bitmap on the floor.
50666ea1b28a76aeba74744148b15099254d918671Owen Lin */
51666ea1b28a76aeba74744148b15099254d918671Owen Lin
52666ea1b28a76aeba74744148b15099254d918671Owen Lininterface ImageGetterCallback {
53666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void imageLoaded(int pos, int offset, RotateBitmap bitmap,
54666ea1b28a76aeba74744148b15099254d918671Owen Lin                            boolean isThumb);
55666ea1b28a76aeba74744148b15099254d918671Owen Lin    public boolean wantsThumbnail(int pos, int offset);
56666ea1b28a76aeba74744148b15099254d918671Owen Lin    public boolean wantsFullImage(int pos, int offset);
57666ea1b28a76aeba74744148b15099254d918671Owen Lin    public int fullImageSizeToUse(int pos, int offset);
58666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void completed();
59666ea1b28a76aeba74744148b15099254d918671Owen Lin    public int [] loadOrder();
60666ea1b28a76aeba74744148b15099254d918671Owen Lin}
61666ea1b28a76aeba74744148b15099254d918671Owen Lin
62666ea1b28a76aeba74744148b15099254d918671Owen Linclass ImageGetter {
63666ea1b28a76aeba74744148b15099254d918671Owen Lin
64666ea1b28a76aeba74744148b15099254d918671Owen Lin    @SuppressWarnings("unused")
65666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final String TAG = "ImageGetter";
66666ea1b28a76aeba74744148b15099254d918671Owen Lin
67666ea1b28a76aeba74744148b15099254d918671Owen Lin    // The thread which does the work.
68666ea1b28a76aeba74744148b15099254d918671Owen Lin    private Thread mGetterThread;
69666ea1b28a76aeba74744148b15099254d918671Owen Lin
70666ea1b28a76aeba74744148b15099254d918671Owen Lin    // The current request serial number.
71666ea1b28a76aeba74744148b15099254d918671Owen Lin    // This is increased by one each time a new job is assigned.
72666ea1b28a76aeba74744148b15099254d918671Owen Lin    // It is only written in the main thread.
73666ea1b28a76aeba74744148b15099254d918671Owen Lin    private int mCurrentSerial;
74666ea1b28a76aeba74744148b15099254d918671Owen Lin
75666ea1b28a76aeba74744148b15099254d918671Owen Lin    // The base position that's being retrieved.  The actual images retrieved
76666ea1b28a76aeba74744148b15099254d918671Owen Lin    // are this base plus each of the offets. -1 means there is no current
77666ea1b28a76aeba74744148b15099254d918671Owen Lin    // request needs to be finished.
78666ea1b28a76aeba74744148b15099254d918671Owen Lin    private int mCurrentPosition = -1;
79666ea1b28a76aeba74744148b15099254d918671Owen Lin
80666ea1b28a76aeba74744148b15099254d918671Owen Lin    // The callback to invoke for each image.
81666ea1b28a76aeba74744148b15099254d918671Owen Lin    private ImageGetterCallback mCB;
82666ea1b28a76aeba74744148b15099254d918671Owen Lin
83666ea1b28a76aeba74744148b15099254d918671Owen Lin    // The image list for the images.
84666ea1b28a76aeba74744148b15099254d918671Owen Lin    private IImageList mImageList;
85666ea1b28a76aeba74744148b15099254d918671Owen Lin
86666ea1b28a76aeba74744148b15099254d918671Owen Lin    // The handler to do callback.
87666ea1b28a76aeba74744148b15099254d918671Owen Lin    private GetterHandler mHandler;
88666ea1b28a76aeba74744148b15099254d918671Owen Lin
89666ea1b28a76aeba74744148b15099254d918671Owen Lin    // True if we want to cancel the current loading.
90666ea1b28a76aeba74744148b15099254d918671Owen Lin    private volatile boolean mCancel = true;
91666ea1b28a76aeba74744148b15099254d918671Owen Lin
92666ea1b28a76aeba74744148b15099254d918671Owen Lin    // True if the getter thread is idle waiting.
93666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean mIdle = false;
94666ea1b28a76aeba74744148b15099254d918671Owen Lin
95666ea1b28a76aeba74744148b15099254d918671Owen Lin    // True when the getter thread should exit.
96666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean mDone = false;
97666ea1b28a76aeba74744148b15099254d918671Owen Lin
98666ea1b28a76aeba74744148b15099254d918671Owen Lin    private ContentResolver mCr;
99666ea1b28a76aeba74744148b15099254d918671Owen Lin
100666ea1b28a76aeba74744148b15099254d918671Owen Lin    private class ImageGetterRunnable implements Runnable {
101666ea1b28a76aeba74744148b15099254d918671Owen Lin
102666ea1b28a76aeba74744148b15099254d918671Owen Lin        private Runnable callback(final int position, final int offset,
103666ea1b28a76aeba74744148b15099254d918671Owen Lin                                  final boolean isThumb,
104666ea1b28a76aeba74744148b15099254d918671Owen Lin                                  final RotateBitmap bitmap,
105666ea1b28a76aeba74744148b15099254d918671Owen Lin                                  final int requestSerial) {
106666ea1b28a76aeba74744148b15099254d918671Owen Lin            return new Runnable() {
107666ea1b28a76aeba74744148b15099254d918671Owen Lin                public void run() {
108666ea1b28a76aeba74744148b15099254d918671Owen Lin                    // check for inflight callbacks that aren't applicable
109666ea1b28a76aeba74744148b15099254d918671Owen Lin                    // any longer before delivering them
110666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (requestSerial == mCurrentSerial) {
111666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mCB.imageLoaded(position, offset, bitmap, isThumb);
112666ea1b28a76aeba74744148b15099254d918671Owen Lin                    } else if (bitmap != null) {
113666ea1b28a76aeba74744148b15099254d918671Owen Lin                        bitmap.recycle();
114666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
115666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
116666ea1b28a76aeba74744148b15099254d918671Owen Lin            };
117666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
118666ea1b28a76aeba74744148b15099254d918671Owen Lin
119666ea1b28a76aeba74744148b15099254d918671Owen Lin        private Runnable completedCallback(final int requestSerial) {
120666ea1b28a76aeba74744148b15099254d918671Owen Lin            return new Runnable() {
121666ea1b28a76aeba74744148b15099254d918671Owen Lin                public void run() {
122666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (requestSerial == mCurrentSerial) {
123666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mCB.completed();
124666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
125666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
126666ea1b28a76aeba74744148b15099254d918671Owen Lin            };
127666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
128666ea1b28a76aeba74744148b15099254d918671Owen Lin
129666ea1b28a76aeba74744148b15099254d918671Owen Lin        public void run() {
130666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Lower the priority of this thread to avoid competing with
131666ea1b28a76aeba74744148b15099254d918671Owen Lin            // the UI thread.
132666ea1b28a76aeba74744148b15099254d918671Owen Lin            Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
133666ea1b28a76aeba74744148b15099254d918671Owen Lin
134666ea1b28a76aeba74744148b15099254d918671Owen Lin            while (true) {
135666ea1b28a76aeba74744148b15099254d918671Owen Lin                synchronized (ImageGetter.this) {
136666ea1b28a76aeba74744148b15099254d918671Owen Lin                    while (mCancel || mDone || mCurrentPosition == -1) {
137666ea1b28a76aeba74744148b15099254d918671Owen Lin                        if (mDone) return;
138666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mIdle = true;
139666ea1b28a76aeba74744148b15099254d918671Owen Lin                        ImageGetter.this.notify();
140666ea1b28a76aeba74744148b15099254d918671Owen Lin                        try {
141666ea1b28a76aeba74744148b15099254d918671Owen Lin                            ImageGetter.this.wait();
142666ea1b28a76aeba74744148b15099254d918671Owen Lin                        } catch (InterruptedException ex) {
143666ea1b28a76aeba74744148b15099254d918671Owen Lin                            // ignore
144666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
145666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mIdle = false;
146666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
147666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
148666ea1b28a76aeba74744148b15099254d918671Owen Lin
149666ea1b28a76aeba74744148b15099254d918671Owen Lin                executeRequest();
150666ea1b28a76aeba74744148b15099254d918671Owen Lin
151666ea1b28a76aeba74744148b15099254d918671Owen Lin                synchronized (ImageGetter.this) {
152666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mCurrentPosition = -1;
153666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
154666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
155666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
156666ea1b28a76aeba74744148b15099254d918671Owen Lin        private void executeRequest() {
157666ea1b28a76aeba74744148b15099254d918671Owen Lin            int imageCount = mImageList.getCount();
158666ea1b28a76aeba74744148b15099254d918671Owen Lin
159666ea1b28a76aeba74744148b15099254d918671Owen Lin            int [] order = mCB.loadOrder();
160666ea1b28a76aeba74744148b15099254d918671Owen Lin            for (int i = 0; i < order.length; i++) {
161666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (mCancel) return;
162666ea1b28a76aeba74744148b15099254d918671Owen Lin                int offset = order[i];
163666ea1b28a76aeba74744148b15099254d918671Owen Lin                int imageNumber = mCurrentPosition + offset;
164666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (imageNumber >= 0 && imageNumber < imageCount) {
165666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (!mCB.wantsThumbnail(mCurrentPosition, offset)) {
166666ea1b28a76aeba74744148b15099254d918671Owen Lin                        continue;
167666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
168666ea1b28a76aeba74744148b15099254d918671Owen Lin
169666ea1b28a76aeba74744148b15099254d918671Owen Lin                    IImage image = mImageList.getImageAt(imageNumber);
170666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (image == null) continue;
171666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (mCancel) return;
172666ea1b28a76aeba74744148b15099254d918671Owen Lin
173666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Bitmap b = image.thumbBitmap(IImage.NO_ROTATE);
174666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (b == null) continue;
175666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (mCancel) {
176666ea1b28a76aeba74744148b15099254d918671Owen Lin                        b.recycle();
177666ea1b28a76aeba74744148b15099254d918671Owen Lin                        return;
178666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
179666ea1b28a76aeba74744148b15099254d918671Owen Lin
180666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Runnable cb = callback(mCurrentPosition, offset,
181666ea1b28a76aeba74744148b15099254d918671Owen Lin                            true,
182666ea1b28a76aeba74744148b15099254d918671Owen Lin                            new RotateBitmap(b, image.getDegreesRotated()),
183666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mCurrentSerial);
184666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mHandler.postGetterCallback(cb);
185666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
186666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
187666ea1b28a76aeba74744148b15099254d918671Owen Lin
188666ea1b28a76aeba74744148b15099254d918671Owen Lin            for (int i = 0; i < order.length; i++) {
189666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (mCancel) return;
190666ea1b28a76aeba74744148b15099254d918671Owen Lin                int offset = order[i];
191666ea1b28a76aeba74744148b15099254d918671Owen Lin                int imageNumber = mCurrentPosition + offset;
192666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (imageNumber >= 0 && imageNumber < imageCount) {
193666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (!mCB.wantsFullImage(mCurrentPosition, offset)) {
194666ea1b28a76aeba74744148b15099254d918671Owen Lin                        continue;
195666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
196666ea1b28a76aeba74744148b15099254d918671Owen Lin
197666ea1b28a76aeba74744148b15099254d918671Owen Lin                    IImage image = mImageList.getImageAt(imageNumber);
198666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (image == null) continue;
199666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (image instanceof VideoObject) continue;
200666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (mCancel) return;
201666ea1b28a76aeba74744148b15099254d918671Owen Lin
202666ea1b28a76aeba74744148b15099254d918671Owen Lin                    int sizeToUse = mCB.fullImageSizeToUse(
203666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mCurrentPosition, offset);
204666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Bitmap b = image.fullSizeBitmap(sizeToUse, 3 * 1024 * 1024,
205666ea1b28a76aeba74744148b15099254d918671Owen Lin                            IImage.NO_ROTATE, IImage.USE_NATIVE);
206666ea1b28a76aeba74744148b15099254d918671Owen Lin
207666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (b == null) continue;
208666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (mCancel) {
209666ea1b28a76aeba74744148b15099254d918671Owen Lin                        b.recycle();
210666ea1b28a76aeba74744148b15099254d918671Owen Lin                        return;
211666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
212666ea1b28a76aeba74744148b15099254d918671Owen Lin
213666ea1b28a76aeba74744148b15099254d918671Owen Lin                    RotateBitmap rb = new RotateBitmap(b,
214666ea1b28a76aeba74744148b15099254d918671Owen Lin                            image.getDegreesRotated());
215666ea1b28a76aeba74744148b15099254d918671Owen Lin
216666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Runnable cb = callback(mCurrentPosition, offset,
217666ea1b28a76aeba74744148b15099254d918671Owen Lin                            false, rb, mCurrentSerial);
218666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mHandler.postGetterCallback(cb);
219666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
220666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
221666ea1b28a76aeba74744148b15099254d918671Owen Lin
222666ea1b28a76aeba74744148b15099254d918671Owen Lin            mHandler.postGetterCallback(completedCallback(mCurrentSerial));
223666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
224666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
225666ea1b28a76aeba74744148b15099254d918671Owen Lin
226666ea1b28a76aeba74744148b15099254d918671Owen Lin    public ImageGetter(ContentResolver cr) {
227666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCr = cr;
228666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGetterThread = new Thread(new ImageGetterRunnable());
229666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGetterThread.setName("ImageGettter");
230666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGetterThread.start();
231666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
232666ea1b28a76aeba74744148b15099254d918671Owen Lin
233666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Cancels current loading (without waiting).
234666ea1b28a76aeba74744148b15099254d918671Owen Lin    public synchronized void cancelCurrent() {
235666ea1b28a76aeba74744148b15099254d918671Owen Lin        Util.Assert(mGetterThread != null);
236666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCancel = true;
2378aa3fbcf9a5a0d11acd48861f5167073e3554980Owen Lin        BitmapManager.instance().cancelThreadDecoding(mGetterThread, mCr);
238666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
239666ea1b28a76aeba74744148b15099254d918671Owen Lin
240666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Cancels current loading (with waiting).
241666ea1b28a76aeba74744148b15099254d918671Owen Lin    private synchronized void cancelCurrentAndWait() {
242666ea1b28a76aeba74744148b15099254d918671Owen Lin        cancelCurrent();
243666ea1b28a76aeba74744148b15099254d918671Owen Lin        while (mIdle != true) {
244666ea1b28a76aeba74744148b15099254d918671Owen Lin            try {
245666ea1b28a76aeba74744148b15099254d918671Owen Lin                wait();
246666ea1b28a76aeba74744148b15099254d918671Owen Lin            } catch (InterruptedException ex) {
247666ea1b28a76aeba74744148b15099254d918671Owen Lin                // ignore.
248666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
249666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
250666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
251666ea1b28a76aeba74744148b15099254d918671Owen Lin
252666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Stops this image getter.
253666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void stop() {
254666ea1b28a76aeba74744148b15099254d918671Owen Lin        synchronized (this) {
255666ea1b28a76aeba74744148b15099254d918671Owen Lin            cancelCurrentAndWait();
256666ea1b28a76aeba74744148b15099254d918671Owen Lin            mDone = true;
257666ea1b28a76aeba74744148b15099254d918671Owen Lin            notify();
258666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
259666ea1b28a76aeba74744148b15099254d918671Owen Lin        try {
260666ea1b28a76aeba74744148b15099254d918671Owen Lin            mGetterThread.join();
261666ea1b28a76aeba74744148b15099254d918671Owen Lin        } catch (InterruptedException ex) {
262666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Ignore the exception
263666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
264666ea1b28a76aeba74744148b15099254d918671Owen Lin        mGetterThread = null;
265666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
266666ea1b28a76aeba74744148b15099254d918671Owen Lin
267666ea1b28a76aeba74744148b15099254d918671Owen Lin    public synchronized void setPosition(int position, ImageGetterCallback cb,
268666ea1b28a76aeba74744148b15099254d918671Owen Lin            IImageList imageList, GetterHandler handler) {
269666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Cancel the previous request.
270666ea1b28a76aeba74744148b15099254d918671Owen Lin        cancelCurrentAndWait();
271666ea1b28a76aeba74744148b15099254d918671Owen Lin
272666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Set new data.
273666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCurrentPosition = position;
274666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCB = cb;
275666ea1b28a76aeba74744148b15099254d918671Owen Lin        mImageList = imageList;
276666ea1b28a76aeba74744148b15099254d918671Owen Lin        mHandler = handler;
277666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCurrentSerial += 1;
278666ea1b28a76aeba74744148b15099254d918671Owen Lin
279666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Kick-start the current request.
280666ea1b28a76aeba74744148b15099254d918671Owen Lin        mCancel = false;
281666ea1b28a76aeba74744148b15099254d918671Owen Lin        BitmapManager.instance().allowThreadDecoding(mGetterThread);
282666ea1b28a76aeba74744148b15099254d918671Owen Lin        notify();
283666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
284666ea1b28a76aeba74744148b15099254d918671Owen Lin}
285666ea1b28a76aeba74744148b15099254d918671Owen Lin
286666ea1b28a76aeba74744148b15099254d918671Owen Linclass GetterHandler extends Handler {
287666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final int IMAGE_GETTER_CALLBACK = 1;
288666ea1b28a76aeba74744148b15099254d918671Owen Lin
289666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
290666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void handleMessage(Message message) {
291666ea1b28a76aeba74744148b15099254d918671Owen Lin        switch(message.what) {
292666ea1b28a76aeba74744148b15099254d918671Owen Lin            case IMAGE_GETTER_CALLBACK:
293666ea1b28a76aeba74744148b15099254d918671Owen Lin                ((Runnable) message.obj).run();
294666ea1b28a76aeba74744148b15099254d918671Owen Lin                break;
295666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
296666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
297666ea1b28a76aeba74744148b15099254d918671Owen Lin
298666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void postGetterCallback(Runnable callback) {
299666ea1b28a76aeba74744148b15099254d918671Owen Lin       postDelayedGetterCallback(callback, 0);
300666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
301666ea1b28a76aeba74744148b15099254d918671Owen Lin
302666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void postDelayedGetterCallback(Runnable callback, long delay) {
303666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (callback == null) {
304666ea1b28a76aeba74744148b15099254d918671Owen Lin            throw new NullPointerException();
305666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
306666ea1b28a76aeba74744148b15099254d918671Owen Lin        Message message = Message.obtain();
307666ea1b28a76aeba74744148b15099254d918671Owen Lin        message.what = IMAGE_GETTER_CALLBACK;
308666ea1b28a76aeba74744148b15099254d918671Owen Lin        message.obj = callback;
309666ea1b28a76aeba74744148b15099254d918671Owen Lin        sendMessageDelayed(message, delay);
310666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
311666ea1b28a76aeba74744148b15099254d918671Owen Lin
312666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void removeAllGetterCallbacks() {
313666ea1b28a76aeba74744148b15099254d918671Owen Lin        removeMessages(IMAGE_GETTER_CALLBACK);
314666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
315666ea1b28a76aeba74744148b15099254d918671Owen Lin}
316