AlbumSetSlidingWindow.java revision dbf4ba12afba115888493caa34937643257e2bb1
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
19dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport android.graphics.Bitmap;
20dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport android.graphics.Color;
21dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport android.os.Message;
22dbf4ba12afba115888493caa34937643257e2bb1Ray Chen
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.R;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.app.GalleryActivity;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem;
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaSet;
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.Path;
29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.AlbumSetView.AlbumSetItem;
30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.Future;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.FutureListener;
32bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Changimport com.android.gallery3d.util.GalleryUtils;
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.MediaSetUtils;
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.ThreadPool;
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class AlbumSetSlidingWindow implements AlbumSetView.ModelListener {
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "GallerySlidingWindow";
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final int MSG_LOAD_BITMAP_DONE = 0;
39da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang    private static final int PLACEHOLDER_COLOR = 0xFF222222;
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static interface Listener {
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onSizeChanged(int size);
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onContentInvalidated();
44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onWindowContentChanged(
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                int slot, AlbumSetItem old, AlbumSetItem update);
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final AlbumSetView.Model mSource;
49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mSize;
50dbf4ba12afba115888493caa34937643257e2bb1Ray Chen    private final AlbumSetView.LabelSpec mLabelSpec;
51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mContentStart = 0;
53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mContentEnd = 0;
54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveStart = 0;
56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveEnd = 0;
57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private Listener mListener;
59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final MyAlbumSetItem mData[];
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private SelectionDrawer mSelectionDrawer;
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private final ColorTexture mWaitLoadingTexture;
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
64dbf4ba12afba115888493caa34937643257e2bb1Ray Chen    private final SynchronizedHandler mHandler;
65dbf4ba12afba115888493caa34937643257e2bb1Ray Chen    private final ThreadPool mThreadPool;
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveRequestCount = 0;
68dbf4ba12afba115888493caa34937643257e2bb1Ray Chen    private final String mLoadingLabel;
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean mIsActive = false;
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static class MyAlbumSetItem extends AlbumSetItem {
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public Path setPath;
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public int sourceType;
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public int cacheFlag;
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public int cacheStatus;
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
789201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang    public AlbumSetSlidingWindow(GalleryActivity activity,
799201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            AlbumSetView.LabelSpec labelSpec, SelectionDrawer drawer,
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            AlbumSetView.Model source, int cacheSize) {
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        source.setModelListener(this);
829201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang        mLabelSpec = labelSpec;
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mLoadingLabel = activity.getAndroidContext().getString(R.string.loading);
84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSource = source;
85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSelectionDrawer = drawer;
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mData = new MyAlbumSetItem[cacheSize];
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSize = source.size();
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
89da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang        mWaitLoadingTexture = new ColorTexture(PLACEHOLDER_COLOR);
90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mWaitLoadingTexture.setSize(1, 1);
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mHandler = new SynchronizedHandler(activity.getGLRoot()) {
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            @Override
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            public void handleMessage(Message message) {
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                Utils.assertTrue(message.what == MSG_LOAD_BITMAP_DONE);
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ((GalleryDisplayItem) message.obj).onLoadBitmapDone();
97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        };
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mThreadPool = activity.getThreadPool();
101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setSelectionDrawer(SelectionDrawer drawer) {
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSelectionDrawer = drawer;
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setListener(Listener listener) {
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mListener = listener;
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public AlbumSetItem get(int slotIndex) {
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Utils.assertTrue(isActiveSlot(slotIndex),
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                "invalid slot: %s outsides (%s, %s)",
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                slotIndex, mActiveStart, mActiveEnd);
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mData[slotIndex % mData.length];
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public int size() {
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mSize;
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public boolean isActiveSlot(int slotIndex) {
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return slotIndex >= mActiveStart && slotIndex < mActiveEnd;
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void setContentWindow(int contentStart, int contentEnd) {
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (contentStart == mContentStart && contentEnd == mContentEnd) return;
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (contentStart >= mContentEnd || mContentStart >= contentEnd) {
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSource.setActiveWindow(contentStart, contentEnd);
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentStart; i < contentEnd; ++i) {
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentStart; i < contentStart; ++i) {
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentEnd, n = mContentEnd; i < n; ++i) {
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSource.setActiveWindow(contentStart, contentEnd);
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentStart, n = mContentStart; i < n; ++i) {
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentEnd; i < contentEnd; ++i) {
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContentStart = contentStart;
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContentEnd = contentEnd;
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setActiveWindow(int start, int end) {
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Utils.assertTrue(
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                start <= end && end - start <= mData.length && end <= mSize,
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                "start = %s, end = %s, length = %s, size = %s",
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                start, end, mData.length, mSize);
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        AlbumSetItem data[] = mData;
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveStart = start;
166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveEnd = end;
167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // If no data is visible, keep the cache content
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (start == end) return;
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int contentStart = Utils.clamp((start + end) / 2 - data.length / 2,
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                0, Math.max(0, mSize - data.length));
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int contentEnd = Math.min(contentStart + data.length, mSize);
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setContentWindow(contentStart, contentEnd);
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mIsActive) updateAllImageRequests();
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // We would like to request non active slots in the following order:
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // Order:    8 6 4 2                   1 3 5 7
180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //         |---------|---------------|---------|
181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //                   |<-  active  ->|
182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //         |<-------- cached range ----------->|
183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void requestNonactiveImages() {
184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int range = Math.max(
185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mContentEnd - mActiveEnd, mActiveStart - mContentStart);
186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0 ;i < range; ++i) {
187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestImagesInSlot(mActiveEnd + i);
188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestImagesInSlot(mActiveStart - 1 - i);
189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void cancelNonactiveImages() {
193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int range = Math.max(
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                mContentEnd - mActiveEnd, mActiveStart - mContentStart);
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0 ;i < range; ++i) {
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            cancelImagesInSlot(mActiveEnd + i);
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            cancelImagesInSlot(mActiveStart - 1 - i);
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void requestImagesInSlot(int slotIndex) {
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (slotIndex < mContentStart || slotIndex >= mContentEnd) return;
203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        AlbumSetItem items = mData[slotIndex % mData.length];
204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (DisplayItem item : items.covers) {
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            ((GalleryDisplayItem) item).requestImage();
206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void cancelImagesInSlot(int slotIndex) {
210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (slotIndex < mContentStart || slotIndex >= mContentEnd) return;
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        AlbumSetItem items = mData[slotIndex % mData.length];
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (DisplayItem item : items.covers) {
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            ((GalleryDisplayItem) item).cancelImageRequest();
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void freeSlotContent(int slotIndex) {
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        AlbumSetItem data[] = mData;
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int index = slotIndex % data.length;
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        AlbumSetItem original = data[index];
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (original != null) {
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            data[index] = null;
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (DisplayItem item : original.covers) {
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ((GalleryDisplayItem) item).recycle();
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private long getMediaSetDataVersion(MediaSet set) {
230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return set == null
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ? MediaSet.INVALID_DATA_VERSION
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                : set.getDataVersion();
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void prepareSlotContent(int slotIndex) {
236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        MediaSet set = mSource.getMediaSet(slotIndex);
237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        MyAlbumSetItem item = new MyAlbumSetItem();
239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        MediaItem[] coverItems = mSource.getCoverItems(slotIndex);
240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        item.covers = new GalleryDisplayItem[coverItems.length];
241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        item.sourceType = identifySourceType(set);
242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        item.cacheFlag = identifyCacheFlag(set);
243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        item.cacheStatus = identifyCacheStatus(set);
244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        item.setPath = set == null ? null : set.getPath();
245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0; i < coverItems.length; ++i) {
247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            item.covers[i] = new GalleryDisplayItem(slotIndex, i, coverItems[i]);
248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        item.labelItem = new LabelDisplayItem(slotIndex);
250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        item.setDataVersion = getMediaSetDataVersion(set);
251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mData[slotIndex % mData.length] = item;
252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean isCoverItemsChanged(int slotIndex) {
255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        AlbumSetItem original = mData[slotIndex % mData.length];
256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (original == null) return true;
257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        MediaItem[] coverItems = mSource.getCoverItems(slotIndex);
258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (original.covers.length != coverItems.length) return true;
260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0, n = coverItems.length; i < n; ++i) {
261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            GalleryDisplayItem g = (GalleryDisplayItem) original.covers[i];
262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (g.mDataVersion != coverItems[i].getDataVersion()) return true;
263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return false;
265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void updateSlotContent(final int slotIndex) {
268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        MyAlbumSetItem data[] = mData;
270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int pos = slotIndex % data.length;
271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        MyAlbumSetItem original = data[pos];
272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!isCoverItemsChanged(slotIndex)) {
274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            MediaSet set = mSource.getMediaSet(slotIndex);
275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            original.sourceType = identifySourceType(set);
276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            original.cacheFlag = identifyCacheFlag(set);
277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            original.cacheStatus = identifyCacheStatus(set);
278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            original.setPath = set == null ? null : set.getPath();
279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            ((LabelDisplayItem) original.labelItem).updateContent();
280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mListener != null) mListener.onContentInvalidated();
281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return;
282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        prepareSlotContent(slotIndex);
285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        AlbumSetItem update = data[pos];
286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mListener != null && isActiveSlot(slotIndex)) {
288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mListener.onWindowContentChanged(slotIndex, original, update);
289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (original != null) {
291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (DisplayItem item : original.covers) {
292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                ((GalleryDisplayItem) item).recycle();
293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void notifySlotChanged(int slotIndex) {
298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        // If the updated content is not cached, ignore it
299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (slotIndex < mContentStart || slotIndex >= mContentEnd) {
300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Log.w(TAG, String.format(
301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    "invalid update: %s is outside (%s, %s)",
302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    slotIndex, mContentStart, mContentEnd) );
303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return;
304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        updateSlotContent(slotIndex);
306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        boolean isActiveSlot = isActiveSlot(slotIndex);
307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mActiveRequestCount == 0 || isActiveSlot) {
308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (DisplayItem item : mData[slotIndex % mData.length].covers) {
309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                GalleryDisplayItem galleryItem = (GalleryDisplayItem) item;
310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                galleryItem.requestImage();
311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (isActiveSlot && galleryItem.isRequestInProgress()) {
312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    ++mActiveRequestCount;
313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                }
314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void updateAllImageRequests() {
319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveRequestCount = 0;
320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) {
321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (DisplayItem item : mData[i % mData.length].covers) {
322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                GalleryDisplayItem coverItem = (GalleryDisplayItem) item;
323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                coverItem.requestImage();
324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (coverItem.isRequestInProgress()) ++mActiveRequestCount;
325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mActiveRequestCount == 0) {
328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestNonactiveImages();
329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            cancelNonactiveImages();
331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private class GalleryDisplayItem extends AbstractDisplayItem
335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            implements FutureListener<Bitmap> {
336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private Future<Bitmap> mFuture;
337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private final int mSlotIndex;
338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private final int mCoverIndex;
339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private final int mMediaType;
340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private Texture mContent;
341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private final long mDataVersion;
342dbf4ba12afba115888493caa34937643257e2bb1Ray Chen        private final boolean mIsPanorama;
3436c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang        private boolean mWaitLoadingDisplayed;
344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public GalleryDisplayItem(int slotIndex, int coverIndex, MediaItem item) {
346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            super(item);
347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSlotIndex = slotIndex;
348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mCoverIndex = coverIndex;
349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mMediaType = item.getMediaType();
350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mDataVersion = item.getDataVersion();
351bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            mIsPanorama = GalleryUtils.isPanorama(item);
352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            updateContent(mWaitLoadingTexture);
353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        protected void onBitmapAvailable(Bitmap bitmap) {
357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (isActiveSlot(mSlotIndex)) {
358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                --mActiveRequestCount;
359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (mActiveRequestCount == 0) requestNonactiveImages();
360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (bitmap != null) {
3621a088db165c138f57d9445ca0b7e50fe90d3ad1dChih-Chung Chang                BitmapTexture texture = new BitmapTexture(bitmap, true);
363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                texture.setThrottled(true);
3646c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang                if (mWaitLoadingDisplayed) {
3656c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang                    updateContent(new FadeInTexture(PLACEHOLDER_COLOR, texture));
3666c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang                } else {
3676c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang                    updateContent(texture);
3686c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang                }
369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                if (mListener != null) mListener.onContentInvalidated();
370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private void updateContent(Texture content) {
374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mContent = content;
3759201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang        }
376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3779201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang        @Override
378da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang        public int render(GLCanvas canvas, int pass) {
3799201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            // Fit the content into the box
3809201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            int width = mContent.getWidth();
3819201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            int height = mContent.getHeight();
382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3839201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            float scalex = mBoxWidth / (float) width;
3849201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            float scaley = mBoxHeight / (float) height;
3859201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            float scale = Math.min(scalex, scaley);
386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            width = (int) Math.floor(width * scale);
388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            height = (int) Math.floor(height * scale);
389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3909201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            // Now draw it
391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int sourceType = SelectionDrawer.DATASOURCE_TYPE_NOT_CATEGORIZED;
392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int cacheFlag = MediaSet.CACHE_FLAG_NO;
393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            int cacheStatus = MediaSet.CACHE_STATUS_NOT_CACHED;
394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            MyAlbumSetItem set = mData[mSlotIndex % mData.length];
395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Path path = set.setPath;
396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mCoverIndex == 0) {
397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                sourceType = set.sourceType;
398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                cacheFlag = set.cacheFlag;
399f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                cacheStatus = set.cacheStatus;
400f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
401f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
4029201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            mSelectionDrawer.draw(canvas, mContent, width, height,
403da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang                    getRotation(), path, sourceType, mMediaType,
404bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang                    mIsPanorama, mLabelSpec.labelBackgroundHeight,
405f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    cacheFlag == MediaSet.CACHE_FLAG_FULL,
406f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    (cacheFlag == MediaSet.CACHE_FLAG_FULL)
407f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    && (cacheStatus != MediaSet.CACHE_STATUS_CACHED_FULL));
408da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang
4096c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang            if (mContent == mWaitLoadingTexture) {
4106c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang                mWaitLoadingDisplayed = true;
4116c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang            }
4126c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang
4136c1f01e21406a05dc7d3258001aa901bd8628a79Chih-Chung Chang            if ((mContent instanceof FadeInTexture) &&
414da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang                    ((FadeInTexture) mContent).isAnimating()) {
415da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang                return RENDER_MORE_FRAME;
416da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang            } else {
417da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang                return 0;
418da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang            }
419f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
420f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
421f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
422f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void startLoadBitmap() {
423f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFuture = mThreadPool.submit(mMediaItem.requestImage(
424f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                    MediaItem.TYPE_MICROTHUMBNAIL), this);
425f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
426f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
427f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
428f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void cancelLoadBitmap() {
429f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFuture.cancel();
430f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
431f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
432f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
433f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onFutureDone(Future<Bitmap> future) {
434f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mHandler.sendMessage(mHandler.obtainMessage(MSG_LOAD_BITMAP_DONE, this));
435f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
436f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
437f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private void onLoadBitmapDone() {
438f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            Future<Bitmap> future = mFuture;
439f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mFuture = null;
440f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            updateImage(future.get(), future.isCancelled());
441f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
442f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
443f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
444f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public String toString() {
445f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return String.format("GalleryDisplayItem(%s, %s)", mSlotIndex, mCoverIndex);
446f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
447f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
448f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
449f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static int identifySourceType(MediaSet set) {
450f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (set == null) {
451f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return SelectionDrawer.DATASOURCE_TYPE_NOT_CATEGORIZED;
452f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
453f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
454f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        Path path = set.getPath();
455f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (MediaSetUtils.isCameraSource(path)) {
456f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return SelectionDrawer.DATASOURCE_TYPE_CAMERA;
457f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
458f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
459f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int type = SelectionDrawer.DATASOURCE_TYPE_NOT_CATEGORIZED;
460f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        String prefix = path.getPrefix();
461f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
462f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (prefix.equals("picasa")) {
463f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            type = SelectionDrawer.DATASOURCE_TYPE_PICASA;
464f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else if (prefix.equals("local") || prefix.equals("merge")) {
465f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            type = SelectionDrawer.DATASOURCE_TYPE_LOCAL;
466f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else if (prefix.equals("mtp")) {
467f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            type = SelectionDrawer.DATASOURCE_TYPE_MTP;
468f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
469f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
470f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return type;
471f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
472f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
473f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static int identifyCacheFlag(MediaSet set) {
474f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (set == null || (set.getSupportedOperations()
475f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                & MediaSet.SUPPORT_CACHE) == 0) {
476f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return MediaSet.CACHE_FLAG_NO;
477f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
478f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
479f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return set.getCacheFlag();
480f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
481f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
482f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static int identifyCacheStatus(MediaSet set) {
483f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (set == null || (set.getSupportedOperations()
484f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                & MediaSet.SUPPORT_CACHE) == 0) {
485f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return MediaSet.CACHE_STATUS_NOT_CACHED;
486f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
487f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
488f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return set.getCacheStatus();
489f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
490f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
491f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private class LabelDisplayItem extends DisplayItem {
4929201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang        private static final int FONT_COLOR_TITLE = Color.WHITE;
493bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang        private static final int FONT_COLOR_COUNT = 0x80FFFFFF;  // 50% white
4949201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang
4959201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang        private StringTexture mTextureTitle;
496bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang        private StringTexture mTextureCount;
4979201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang        private String mTitle;
498bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang        private String mCount;
4999201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang        private int mLastWidth;
500f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        private final int mSlotIndex;
501bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang        private boolean mHasIcon;
502f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
503f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public LabelDisplayItem(int slotIndex) {
504f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSlotIndex = slotIndex;
505f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
506f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
507f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public boolean updateContent() {
5089201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            String title = mLoadingLabel;
509bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            String count = "";
510f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            MediaSet set = mSource.getMediaSet(mSlotIndex);
511f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (set != null) {
5129201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang                title = Utils.ensureNotNull(set.getName());
513bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang                count = "" + set.getTotalMediaItemCount();
5149201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            }
5159201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            if (Utils.equals(title, mTitle)
516bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang                    && Utils.equals(count, mCount)
5179201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang                    && Utils.equals(mBoxWidth, mLastWidth)) {
5189201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang                    return false;
519f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
5209201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            mTitle = title;
521bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            mCount = count;
5229201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            mLastWidth = mBoxWidth;
523bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            mHasIcon = (identifySourceType(set) !=
524bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang                    SelectionDrawer.DATASOURCE_TYPE_NOT_CATEGORIZED);
5259201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang
5269201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            AlbumSetView.LabelSpec s = mLabelSpec;
5279201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            mTextureTitle = StringTexture.newInstance(
5289201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang                    title, s.titleFontSize, FONT_COLOR_TITLE,
5299201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang                    mBoxWidth - s.leftMargin, false);
530bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            mTextureCount = StringTexture.newInstance(
531bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang                    count, s.countFontSize, FONT_COLOR_COUNT,
5329201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang                    mBoxWidth - s.leftMargin, true);
5339201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang
534f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return true;
535f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
536f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
537f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
538da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang        public int render(GLCanvas canvas, int pass) {
5399201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            if (mBoxWidth != mLastWidth) {
5409201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang                updateContent();
5419201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            }
5429201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang
5439201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            AlbumSetView.LabelSpec s = mLabelSpec;
5449201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            int x = -mBoxWidth / 2;
545bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            int y = (mBoxHeight + 1) / 2 - s.labelBackgroundHeight;
5469201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            y += s.titleOffset;
5479201679ed1c485767f2e334aa618bd733024af03Chih-Chung Chang            mTextureTitle.draw(canvas, x + s.leftMargin, y);
548bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            y += s.titleFontSize + s.countOffset;
549bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            x += mHasIcon ? s.iconSize : s.leftMargin;
550bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Chang            mTextureCount.draw(canvas, x, y);
551da071d27a1435cce080b5c609d0d833555e5a175Chih-Chung Chang            return 0;
552f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
553f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
554f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
555f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public long getIdentity() {
556f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return System.identityHashCode(this);
557f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
558f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
559f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
560f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onSizeChanged(int size) {
561dbf4ba12afba115888493caa34937643257e2bb1Ray Chen        if (mIsActive && mSize != size) {
562f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSize = size;
563dbf4ba12afba115888493caa34937643257e2bb1Ray Chen            if (mListener != null) mListener.onSizeChanged(mSize);
564f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
565f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
566f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
567f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onWindowContentChanged(int index) {
568f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!mIsActive) {
569f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            // paused, ignore slot changed event
570f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return;
571f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
572f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        notifySlotChanged(index);
573f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
574f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
575f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void pause() {
576f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mIsActive = false;
577f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
578f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            freeSlotContent(i);
579f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
580f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
581f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
582f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void resume() {
583f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mIsActive = true;
584f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
585f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            prepareSlotContent(i);
586f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
587f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        updateAllImageRequests();
588f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
589f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
590