AlbumSlidingWindow.java revision da071d27a1435cce080b5c609d0d833555e5a175
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.ui; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.app.GalleryActivity; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.BitmapUtils; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.LruCache; 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.Path; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.Future; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.FutureListener; 27bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Changimport com.android.gallery3d.util.GalleryUtils; 28113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linimport com.android.gallery3d.util.JobLimiter; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.ThreadPool.Job; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.ThreadPool.JobContext; 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Bitmap; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.graphics.Color; 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport android.os.Message; 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class AlbumSlidingWindow implements AlbumView.ModelListener { 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "AlbumSlidingWindow"; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_LOAD_BITMAP_DONE = 0; 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_UPDATE_SLOT = 1; 42113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private static final int JOB_LIMIT = 2; 43da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang private static final int PLACEHOLDER_COLOR = 0xFF222222; 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static interface Listener { 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSizeChanged(int size); 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onContentInvalidated(); 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onWindowContentChanged( 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int slot, DisplayItem old, DisplayItem update); 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final AlbumView.Model mSource; 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSize; 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentStart = 0; 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentEnd = 0; 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveStart = 0; 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveEnd = 0; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Listener mListener; 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mFocusIndex = -1; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final AlbumDisplayItem mData[]; 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final ColorTexture mWaitLoadingTexture; 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private SelectionDrawer mSelectionDrawer; 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private SynchronizedHandler mHandler; 69113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin private JobLimiter mThreadPool; 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveRequestCount = 0; 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mIsActive = false; 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 749201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang private int mCacheThumbSize; // 0: Don't cache the thumbnails 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private LruCache<Path, Bitmap> mImageCache = new LruCache<Path, Bitmap>(1000); 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public AlbumSlidingWindow(GalleryActivity activity, 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumView.Model source, int cacheSize, 799201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang int cacheThumbSize) { 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin source.setModelListener(this); 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource = source; 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData = new AlbumDisplayItem[cacheSize]; 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSize = source.size(); 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 85da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang mWaitLoadingTexture = new ColorTexture(PLACEHOLDER_COLOR); 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mWaitLoadingTexture.setSize(1, 1); 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler = new SynchronizedHandler(activity.getGLRoot()) { 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void handleMessage(Message message) { 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (message.what) { 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_LOAD_BITMAP_DONE: { 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ((AlbumDisplayItem) message.obj).onLoadBitmapDone(); 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_UPDATE_SLOT: { 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateSlotContent(message.arg1); 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin break; 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 104113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin mThreadPool = new JobLimiter(activity.getThreadPool(), JOB_LIMIT); 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setSelectionDrawer(SelectionDrawer drawer) { 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSelectionDrawer = drawer; 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setListener(Listener listener) { 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener = listener; 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setFocusIndex(int slotIndex) { 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFocusIndex = slotIndex; 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public DisplayItem get(int slotIndex) { 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.assertTrue(isActiveSlot(slotIndex), 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "invalid slot: %s outsides (%s, %s)", 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin slotIndex, mActiveStart, mActiveEnd); 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mData[slotIndex % mData.length]; 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size() { 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mSize; 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isActiveSlot(int slotIndex) { 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return slotIndex >= mActiveStart && slotIndex < mActiveEnd; 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void setContentWindow(int contentStart, int contentEnd) { 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart == mContentStart && contentEnd == mContentEnd) return; 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mIsActive) { 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentStart = contentStart; 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentEnd = contentEnd; 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.setActiveWindow(contentStart, contentEnd); 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart >= mContentEnd || mContentStart >= contentEnd) { 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentStart, n = mContentEnd; i < n; ++i) { 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin freeSlotContent(i); 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.setActiveWindow(contentStart, contentEnd); 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = contentStart; i < contentEnd; ++i) { 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prepareSlotContent(i); 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentStart; i < contentStart; ++i) { 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin freeSlotContent(i); 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = contentEnd, n = mContentEnd; i < n; ++i) { 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin freeSlotContent(i); 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.setActiveWindow(contentStart, contentEnd); 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = contentStart, n = mContentStart; i < n; ++i) { 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prepareSlotContent(i); 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentEnd; i < contentEnd; ++i) { 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prepareSlotContent(i); 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentStart = contentStart; 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentEnd = contentEnd; 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setActiveWindow(int start, int end) { 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.assertTrue(start <= end 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && end - start <= mData.length && end <= mSize, 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "%s, %s, %s, %s", start, end, mData.length, mSize); 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin DisplayItem data[] = mData; 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveStart = start; 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveEnd = end; 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If no data is visible, keep the cache content 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == end) return; 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentStart = Utils.clamp((start + end) / 2 - data.length / 2, 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 0, Math.max(0, mSize - data.length)); 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentEnd = Math.min(contentStart + data.length, mSize); 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setContentWindow(contentStart, contentEnd); 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mIsActive) updateAllImageRequests(); 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We would like to request non active slots in the following order: 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Order: 8 6 4 2 1 3 5 7 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // |---------|---------------|---------| 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // |<- active ->| 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // |<-------- cached range ----------->| 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void requestNonactiveImages() { 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int range = Math.max( 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (mContentEnd - mActiveEnd), (mActiveStart - mContentStart)); 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0 ;i < range; ++i) { 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin requestSlotImage(mActiveEnd + i, false); 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin requestSlotImage(mActiveStart - 1 - i, false); 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void requestSlotImage(int slotIndex, boolean isActive) { 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (slotIndex < mContentStart || slotIndex >= mContentEnd) return; 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem item = mData[slotIndex % mData.length]; 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin item.requestImage(); 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void cancelNonactiveImages() { 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int range = Math.max( 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin (mContentEnd - mActiveEnd), (mActiveStart - mContentStart)); 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0 ;i < range; ++i) { 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin cancelSlotImage(mActiveEnd + i, false); 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin cancelSlotImage(mActiveStart - 1 - i, false); 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void cancelSlotImage(int slotIndex, boolean isActive) { 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (slotIndex < mContentStart || slotIndex >= mContentEnd) return; 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem item = mData[slotIndex % mData.length]; 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin item.cancelImageRequest(); 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void freeSlotContent(int slotIndex) { 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem data[] = mData; 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = slotIndex % data.length; 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem original = data[index]; 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (original != null) { 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin original.recycle(); 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin data[index] = null; 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void prepareSlotContent(final int slotIndex) { 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[slotIndex % mData.length] = new AlbumDisplayItem( 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin slotIndex, mSource.get(slotIndex)); 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateSlotContent(final int slotIndex) { 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaItem item = mSource.get(slotIndex); 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem data[] = mData; 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = slotIndex % data.length; 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem original = data[index]; 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem update = new AlbumDisplayItem(slotIndex, item); 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin data[index] = update; 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean isActive = isActiveSlot(slotIndex); 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mListener != null && isActive) { 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onWindowContentChanged(slotIndex, original, update); 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (original != null) { 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (isActive && original.isRequestInProgress()) { 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin --mActiveRequestCount; 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin original.recycle(); 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (isActive) { 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveRequestCount == 0) cancelNonactiveImages(); 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ++mActiveRequestCount; 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin update.requestImage(); 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveRequestCount == 0) update.requestImage(); 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateAllImageRequests() { 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveRequestCount = 0; 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem data[] = mData; 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) { 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin AlbumDisplayItem item = data[i % data.length]; 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin item.requestImage(); 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (item.isRequestInProgress()) ++mActiveRequestCount; 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveRequestCount == 0) { 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin requestNonactiveImages(); 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin cancelNonactiveImages(); 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class AlbumDisplayItem extends AbstractDisplayItem 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin implements FutureListener<Bitmap>, Job<Bitmap> { 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Future<Bitmap> mFuture; 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final int mSlotIndex; 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final int mMediaType; 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private Texture mContent; 288bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang private boolean mIsPanorama; 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public AlbumDisplayItem(int slotIndex, MediaItem item) { 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super(item); 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMediaType = (item == null) 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ? MediaItem.MEDIA_TYPE_UNKNOWN 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin : item.getMediaType(); 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSlotIndex = slotIndex; 296bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang mIsPanorama = GalleryUtils.isPanorama(item); 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateContent(mWaitLoadingTexture); 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected void onBitmapAvailable(Bitmap bitmap) { 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean isActiveSlot = isActiveSlot(mSlotIndex); 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (isActiveSlot) { 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin --mActiveRequestCount; 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveRequestCount == 0) requestNonactiveImages(); 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (bitmap != null) { 3081a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang BitmapTexture texture = new BitmapTexture(bitmap, true); 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin texture.setThrottled(true); 310da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang updateContent(new FadeInTexture(PLACEHOLDER_COLOR, texture)); 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mListener != null && isActiveSlot) { 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListener.onContentInvalidated(); 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateContent(Texture content) { 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContent = content; 3199201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang } 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 3219201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang @Override 322da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang public int render(GLCanvas canvas, int pass) { 3239201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // Fit the content into the box 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int width = mContent.getWidth(); 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int height = mContent.getHeight(); 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 3279201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang float scalex = mBoxWidth / (float) width; 3289201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang float scaley = mBoxHeight / (float) height; 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin float scale = Math.min(scalex, scaley); 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin width = (int) Math.floor(width * scale); 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin height = (int) Math.floor(height * scale); 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 3349201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang // Now draw it 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (pass == 0) { 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Path path = null; 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mMediaItem != null) path = mMediaItem.getPath(); 3389201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSelectionDrawer.draw(canvas, mContent, width, height, 339bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang getRotation(), path, mMediaType, mIsPanorama); 340da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang int result = 0; 341da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang if (mFocusIndex == mSlotIndex) { 342da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang result |= RENDER_MORE_PASS; 343da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang } 344da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang if (mContent != mWaitLoadingTexture && 345da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang ((FadeInTexture) mContent).isAnimating()) { 346da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang result |= RENDER_MORE_FRAME; 347da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang } 348da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang return result; 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else if (pass == 1) { 3509201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang mSelectionDrawer.drawFocus(canvas, width, height); 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 352da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang return 0; 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void startLoadBitmap() { 3579201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang if (mCacheThumbSize > 0) { 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Path path = mMediaItem.getPath(); 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mImageCache.containsKey(path)) { 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Bitmap bitmap = mImageCache.get(path); 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateImage(bitmap, false); 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFuture = mThreadPool.submit(this, this); 365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFuture = mThreadPool.submit(mMediaItem.requestImage( 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaItem.TYPE_MICROTHUMBNAIL), this); 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // This gets the bitmap and scale it down. 372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Bitmap run(JobContext jc) { 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Job<Bitmap> job = mMediaItem.requestImage( 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaItem.TYPE_MICROTHUMBNAIL); 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Bitmap bitmap = job.run(jc); 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (bitmap != null) { 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin bitmap = BitmapUtils.resizeDownBySideLength( 3789201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang bitmap, mCacheThumbSize, true); 379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return bitmap; 381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void cancelLoadBitmap() { 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mFuture != null) { 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFuture.cancel(); 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onFutureDone(Future<Bitmap> bitmap) { 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mHandler.sendMessage(mHandler.obtainMessage(MSG_LOAD_BITMAP_DONE, this)); 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void onLoadBitmapDone() { 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Future<Bitmap> future = mFuture; 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mFuture = null; 398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Bitmap bitmap = future.get(); 399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean isCancelled = future.isCancelled(); 4009201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang if (mCacheThumbSize > 0 && (bitmap != null || !isCancelled)) { 401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Path path = mMediaItem.getPath(); 402f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageCache.put(path, bitmap); 403f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 404f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateImage(bitmap, isCancelled); 405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 408f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public String toString() { 409f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return String.format("AlbumDisplayItem[%s]", mSlotIndex); 410f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 411f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 412f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 413f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onSizeChanged(int size) { 414f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSize != size) { 415f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSize = size; 416f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mListener != null) mListener.onSizeChanged(mSize); 417f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 418f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 419f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 420f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onWindowContentChanged(int index) { 421f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index >= mContentStart && index < mContentEnd && mIsActive) { 422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateSlotContent(index); 423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 424f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 425f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 426f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void resume() { 427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIsActive = true; 428f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentStart, n = mContentEnd; i < n; ++i) { 429f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin prepareSlotContent(i); 430f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 431f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateAllImageRequests(); 432f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void pause() { 435f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIsActive = false; 436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentStart, n = mContentEnd; i < n; ++i) { 437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin freeSlotContent(i); 438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mImageCache.clear(); 440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 442