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