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