1f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin/* 2f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Copyright (C) 2010 The Android Open Source Project 3f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 4f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Licensed under the Apache License, Version 2.0 (the "License"); 5f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * you may not use this file except in compliance with the License. 6f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * You may obtain a copy of the License at 7f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 8f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * http://www.apache.org/licenses/LICENSE-2.0 9f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * 10f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Unless required by applicable law or agreed to in writing, software 11f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * distributed under the License is distributed on an "AS IS" BASIS, 12f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * See the License for the specific language governing permissions and 14f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * limitations under the License. 15f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 16f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 17f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpackage com.android.gallery3d.app; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chenimport android.graphics.Bitmap; 20604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.app.SlideshowPage.Slide; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.ContentListener; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaObject; 25604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chenimport com.android.gallery3d.data.Path; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.Future; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.FutureListener; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.ThreadPool; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.ThreadPool.Job; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.ThreadPool.JobContext; 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.LinkedList; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.atomic.AtomicBoolean; 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class SlideshowDataAdapter implements SlideshowPage.Model { 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "SlideshowDataAdapter"; 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int IMAGE_QUEUE_CAPACITY = 3; 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public interface SlideshowSource { 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void addContentListener(ContentListener listener); 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void removeContentListener(ContentListener listener); 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public long reload(); 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaItem getMediaItem(int index); 46604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen public int findItemIndex(Path path, int hint); 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final SlideshowSource mSource; 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mLoadIndex = 0; 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mNextOutput = 0; 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mIsActive = false; 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mNeedReset; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mDataReady; 56604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen private Path mInitialPath; 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final LinkedList<Slide> mImageQueue = new LinkedList<Slide>(); 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Future<Void> mReloadTask; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ThreadPool mThreadPool; 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private long mDataVersion = MediaObject.INVALID_DATA_VERSION; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final AtomicBoolean mNeedReload = new AtomicBoolean(false); 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final SourceListener mSourceListener = new SourceListener(); 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 67604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen // The index is just a hint if initialPath is set 68604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen public SlideshowDataAdapter(GalleryContext context, SlideshowSource source, int index, 69604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen Path initialPath) { 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource = source; 71604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen mInitialPath = initialPath; 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadIndex = index; 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNextOutput = index; 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mThreadPool = context.getThreadPool(); 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 7778979fc21d1e1111a504cc07ae6b0e0bc4d61447Chih-Chung Chang private MediaItem loadItem() { 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mNeedReload.compareAndSet(true, false)) { 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long v = mSource.reload(); 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (v != mDataVersion) { 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDataVersion = v; 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNeedReset = true; 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 86604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen int index = mLoadIndex; 87604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen if (mInitialPath != null) { 88604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen index = mSource.findItemIndex(mInitialPath, index); 89604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen mInitialPath = null; 90604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen } 91604f053d040782159b61d3b74ee533bc2c0ccdd0Ray Chen return mSource.getMediaItem(index); 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class ReloadTask implements Job<Void> { 957817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Void run(JobContext jc) { 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (true) { 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (SlideshowDataAdapter.this) { 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (mIsActive && (!mDataReady 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || mImageQueue.size() >= IMAGE_QUEUE_CAPACITY)) { 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin SlideshowDataAdapter.this.wait(); 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (InterruptedException ex) { 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // ignored. 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin continue; 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mIsActive) return null; 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNeedReset = false; 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaItem item = loadItem(); 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mNeedReset) { 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (SlideshowDataAdapter.this) { 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageQueue.clear(); 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadIndex = mNextOutput; 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin continue; 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (item == null) { 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (SlideshowDataAdapter.this) { 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mNeedReload.get()) mDataReady = false; 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin SlideshowDataAdapter.this.notifyAll(); 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin continue; 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Bitmap bitmap = item 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .requestImage(MediaItem.TYPE_THUMBNAIL) 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .run(jc); 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (bitmap != null) { 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (SlideshowDataAdapter.this) { 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageQueue.addLast( 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new Slide(item, mLoadIndex, bitmap)); 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mImageQueue.size() == 1) { 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin SlideshowDataAdapter.this.notifyAll(); 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ++mLoadIndex; 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class SourceListener implements ContentListener { 1497817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onContentDirty() { 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (SlideshowDataAdapter.this) { 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNeedReload.set(true); 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDataReady = true; 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin SlideshowDataAdapter.this.notifyAll(); 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private synchronized Slide innerNextBitmap() { 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (mIsActive && mDataReady && mImageQueue.isEmpty()) { 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin wait(); 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (InterruptedException t) { 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new AssertionError(); 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mImageQueue.isEmpty()) return null; 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNextOutput++; 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin this.notifyAll(); 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mImageQueue.removeFirst(); 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1737817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Future<Slide> nextSlide(FutureListener<Slide> listener) { 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mThreadPool.submit(new Job<Slide>() { 1767817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Slide run(JobContext jc) { 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin jc.setMode(ThreadPool.MODE_NONE); 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return innerNextBitmap(); 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }, listener); 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1847817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void pause() { 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (this) { 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIsActive = false; 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.removeContentListener(mSourceListener); 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.cancel(); 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.waitDone(); 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = null; 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1967817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void resume() { 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIsActive = true; 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.addContentListener(mSourceListener); 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNeedReload.set(true); 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDataReady = true; 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = mThreadPool.submit(new ReloadTask()); 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 205