AlbumSlidingWindow.java revision cd938f3f05975de73658dc2f2b6c632b7ee569a3
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
22c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Linimport com.android.gallery3d.app.AlbumDataLoader;
23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.app.GalleryActivity;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem;
26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.Path;
27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.Future;
28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.FutureListener;
29bc2154199aee16762e3758ad0cfed685323d9a9fChih-Chung Changimport com.android.gallery3d.util.GalleryUtils;
30113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linimport com.android.gallery3d.util.JobLimiter;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
32c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Linpublic class AlbumSlidingWindow implements AlbumDataLoader.DataListener {
33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @SuppressWarnings("unused")
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "AlbumSlidingWindow";
35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
361a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private static final int MSG_UPDATE_ENTRY = 0;
37113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin    private static final int JOB_LIMIT = 2;
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static interface Listener {
40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onSizeChanged(int size);
417260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin        public void onContentChanged();
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
441a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    public static class AlbumEntry {
451a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public MediaItem item;
461a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public Path path;
471a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public boolean isPanorama;
481a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public int rotation;
491a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public int mediaType;
501a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public boolean isWaitDisplayed;
511a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public Texture content;
521a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        private BitmapLoader contentLoader;
531a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
541a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
55c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin    private final AlbumDataLoader mSource;
56d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final AlbumEntry mData[];
57d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final SynchronizedHandler mHandler;
58d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final JobLimiter mThreadPool;
59d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final TextureUploader mTextureUploader;
60d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mSize;
62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mContentStart = 0;
64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mContentEnd = 0;
65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveStart = 0;
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveEnd = 0;
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private Listener mListener;
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveRequestCount = 0;
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean mIsActive = false;
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public AlbumSlidingWindow(GalleryActivity activity,
75c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            AlbumDataLoader source, int cacheSize) {
76c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin        source.setDataListener(this);
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSource = source;
781a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mData = new AlbumEntry[cacheSize];
79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSize = source.size();
80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mHandler = new SynchronizedHandler(activity.getGLRoot()) {
82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            @Override
83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            public void handleMessage(Message message) {
841a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                Utils.assertTrue(message.what == MSG_UPDATE_ENTRY);
851a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                ((ThumbnailLoader) message.obj).updateEntry();
86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        };
88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
89113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        mThreadPool = new JobLimiter(activity.getThreadPool(), JOB_LIMIT);
90d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        mTextureUploader = new TextureUploader(activity.getGLRoot());
91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setListener(Listener listener) {
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mListener = listener;
95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
971a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    public AlbumEntry get(int slotIndex) {
98cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        if (!isActiveSlot(slotIndex)) {
99cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang            Utils.fail("invalid slot: %s outsides (%s, %s)",
100cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang                    slotIndex, mActiveStart, mActiveEnd);
101cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        }
102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mData[slotIndex % mData.length];
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public boolean isActiveSlot(int slotIndex) {
106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return slotIndex >= mActiveStart && slotIndex < mActiveEnd;
107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void setContentWindow(int contentStart, int contentEnd) {
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (contentStart == mContentStart && contentEnd == mContentEnd) return;
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (!mIsActive) {
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mContentStart = contentStart;
114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mContentEnd = contentEnd;
115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSource.setActiveWindow(contentStart, contentEnd);
116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return;
117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (contentStart >= mContentEnd || mContentStart >= contentEnd) {
120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSource.setActiveWindow(contentStart, contentEnd);
124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentStart; i < contentEnd; ++i) {
125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentStart; i < contentStart; ++i) {
129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentEnd, n = mContentEnd; i < n; ++i) {
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSource.setActiveWindow(contentStart, contentEnd);
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentStart, n = mContentStart; i < n; ++i) {
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentEnd; i < contentEnd; ++i) {
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContentStart = contentStart;
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContentEnd = contentEnd;
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setActiveWindow(int start, int end) {
148cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        if (!(start <= end && end - start <= mData.length && end <= mSize)) {
149cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang            Utils.fail("%s, %s, %s, %s", start, end, mData.length, mSize);
150cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        }
1511a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry data[] = mData;
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveStart = start;
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveEnd = end;
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int contentStart = Utils.clamp((start + end) / 2 - data.length / 2,
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                0, Math.max(0, mSize - data.length));
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int contentEnd = Math.min(contentStart + data.length, mSize);
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setContentWindow(contentStart, contentEnd);
160cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        updateTextureUploadQueue();
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mIsActive) updateAllImageRequests();
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
164cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin    private void uploadBgTextureInSlot(int index) {
165cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        if (index < mContentEnd && index >= mContentStart) {
166cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            AlbumEntry entry = mData[index % mData.length];
167cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            if (entry.content instanceof BitmapTexture) {
168cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                mTextureUploader.addBgTexture((BitmapTexture) entry.content);
169cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            }
170d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        }
171d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    }
172d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
173cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin    private void updateTextureUploadQueue() {
174d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        if (!mIsActive) return;
175d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        mTextureUploader.clear();
176cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
177cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        // add foreground textures
178cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) {
179d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            AlbumEntry entry = mData[i % mData.length];
180cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            if (entry.content instanceof BitmapTexture) {
181cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                mTextureUploader.addFgTexture((BitmapTexture) entry.content);
182cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            }
183cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        }
184cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
185cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        // add background textures
186cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        int range = Math.max(
187cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                (mContentEnd - mActiveEnd), (mActiveStart - mContentStart));
188cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        for (int i = 0; i < range; ++i) {
189cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            uploadBgTextureInSlot(mActiveEnd + i);
190cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            uploadBgTextureInSlot(mActiveStart - i - 1);
191d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        }
192d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    }
193d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // We would like to request non active slots in the following order:
195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // Order:    8 6 4 2                   1 3 5 7
196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //         |---------|---------------|---------|
197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //                   |<-  active  ->|
198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //         |<-------- cached range ----------->|
199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void requestNonactiveImages() {
200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int range = Math.max(
201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                (mContentEnd - mActiveEnd), (mActiveStart - mContentStart));
202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0 ;i < range; ++i) {
2031a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            requestSlotImage(mActiveEnd + i);
2041a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            requestSlotImage(mActiveStart - 1 - i);
205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2081a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    // return whether the request is in progress or not
2091a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private boolean requestSlotImage(int slotIndex) {
2101a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        if (slotIndex < mContentStart || slotIndex >= mContentEnd) return false;
2111a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry entry = mData[slotIndex % mData.length];
2121a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        if (entry.content != null || entry.item == null) return false;
2131a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
2141a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.contentLoader.startLoad();
2151a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        return entry.contentLoader.isRequestInProgress();
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void cancelNonactiveImages() {
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int range = Math.max(
220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                (mContentEnd - mActiveEnd), (mActiveStart - mContentStart));
221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0 ;i < range; ++i) {
2221a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            cancelSlotImage(mActiveEnd + i);
2231a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            cancelSlotImage(mActiveStart - 1 - i);
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2271a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private void cancelSlotImage(int slotIndex) {
228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (slotIndex < mContentStart || slotIndex >= mContentEnd) return;
2291a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry item = mData[slotIndex % mData.length];
2301a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        if (item.contentLoader != null) item.contentLoader.cancelLoad();
231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void freeSlotContent(int slotIndex) {
2341a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry data[] = mData;
235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int index = slotIndex % data.length;
2361a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry entry = data[index];
2371a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        if (entry.contentLoader != null) {
2381a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            entry.contentLoader.recycle();
239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
2401a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        data[index] = null;
241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2431a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private void prepareSlotContent(int slotIndex) {
2441a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry entry = new AlbumEntry();
2451a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        MediaItem item = mSource.get(slotIndex); // item could be null;
2461a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.item = item;
2471a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.isPanorama = GalleryUtils.isPanorama(entry.item);
2481a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.mediaType = (item == null)
2491a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                ? MediaItem.MEDIA_TYPE_UNKNOWN
2501a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                : entry.item.getMediaType();
2511a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.path = (item == null) ? null : item.getPath();
2521a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.rotation = (item == null) ? 0 : item.getRotation();
2531a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.contentLoader = new ThumbnailLoader(slotIndex, entry.item);
2541a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mData[slotIndex % mData.length] = entry;
255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void updateAllImageRequests() {
258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveRequestCount = 0;
259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) {
2601a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            if (requestSlotImage(i)) ++mActiveRequestCount;
261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mActiveRequestCount == 0) {
263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestNonactiveImages();
264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            cancelNonactiveImages();
266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2691a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private class ThumbnailLoader extends BitmapLoader  {
270d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        private final int mSlotIndex;
271d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        private final MediaItem mItem;
2721a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
2731a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public ThumbnailLoader(int slotIndex, MediaItem item) {
274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSlotIndex = slotIndex;
2751a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            mItem = item;
276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
2794bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        protected void recycleBitmap(Bitmap bitmap) {
280d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            MediaItem.getMicroThumbPool().recycle(bitmap);
2814bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        }
2824bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin
2834bb5912e85f6d1bd8a6b78d6d52b4c4da7aeb740Owen Lin        @Override
2841a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) {
2851a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            return mThreadPool.submit(
2861a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                    mItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL), this);
287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
2901a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        protected void onLoadComplete(Bitmap bitmap) {
2911a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            mHandler.obtainMessage(MSG_UPDATE_ENTRY, this).sendToTarget();
292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2941a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public void updateEntry() {
295d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            Bitmap bitmap = getBitmap();
296d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            if (bitmap == null) return; // error or recycled
297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2981a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            AlbumEntry entry = mData[mSlotIndex % mData.length];
299d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            entry.content = new BitmapTexture(bitmap);
300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3011a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            if (isActiveSlot(mSlotIndex)) {
302d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin                mTextureUploader.addFgTexture((BitmapTexture) entry.content);
3031a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                --mActiveRequestCount;
3041a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                if (mActiveRequestCount == 0) requestNonactiveImages();
3051a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                if (mListener != null) mListener.onContentChanged();
306d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            } else {
307d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin                mTextureUploader.addBgTexture((BitmapTexture) entry.content);
3081a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            }
309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3121a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    @Override
313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onSizeChanged(int size) {
314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mSize != size) {
315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSize = size;
316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mListener != null) mListener.onSizeChanged(mSize);
317cd938f3f05975de73658dc2f2b6c632b7ee569a3Yuli Huang            if (mContentEnd > mSize) mContentEnd = mSize;
318cd938f3f05975de73658dc2f2b6c632b7ee569a3Yuli Huang            if (mActiveEnd > mSize) mActiveEnd = mSize;
319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3221a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    @Override
323c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin    public void onContentChanged(int index) {
324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (index >= mContentStart && index < mContentEnd && mIsActive) {
325c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            freeSlotContent(index);
326c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            prepareSlotContent(index);
327c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            updateAllImageRequests();
328c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            if (mListener != null && isActiveSlot(index)) {
329c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin                mListener.onContentChanged();
330c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            }
331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void resume() {
335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mIsActive = true;
336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            prepareSlotContent(i);
338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        updateAllImageRequests();
340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void pause() {
343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mIsActive = false;
344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            freeSlotContent(i);
346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
349