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
22b21b8e58a604f6c701245d84b141b5b87663192bOwen Linimport com.android.gallery3d.app.AbstractGalleryActivity;
23c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Linimport com.android.gallery3d.app.AlbumDataLoader;
24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils;
25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem;
262f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liuimport com.android.gallery3d.data.MediaObject;
272f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liuimport com.android.gallery3d.data.MediaObject.PanoramaSupportCallback;
28f52ceba89962829aa12f5caba131580e8da85880Bobby Georgescuimport com.android.gallery3d.data.Path;
29a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.Texture;
30a4eae1abb4f2547dfbda84301ee764ce35464881John Reckimport com.android.gallery3d.glrenderer.TiledTexture;
31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.Future;
32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.FutureListener;
33113bfc77c4468411da9ae1290553c3be89f8df9aOwen Linimport com.android.gallery3d.util.JobLimiter;
34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
35c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Linpublic class AlbumSlidingWindow implements AlbumDataLoader.DataListener {
36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    @SuppressWarnings("unused")
37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private static final String TAG = "AlbumSlidingWindow";
38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
391a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private static final int MSG_UPDATE_ENTRY = 0;
40113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin    private static final int JOB_LIMIT = 2;
41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public static interface Listener {
43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        public void onSizeChanged(int size);
447260f6f74d465520e4497b23fe56f98abb0c15a2Owen Lin        public void onContentChanged();
45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
471a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    public static class AlbumEntry {
481a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public MediaItem item;
491a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public Path path;
501a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public boolean isPanorama;
511a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public int rotation;
521a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public int mediaType;
531a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public boolean isWaitDisplayed;
54adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin        public TiledTexture bitmapTexture;
551a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public Texture content;
561a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        private BitmapLoader contentLoader;
572f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        private PanoSupportListener mPanoSupportListener;
581a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    }
591a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
60c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin    private final AlbumDataLoader mSource;
61d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final AlbumEntry mData[];
62d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final SynchronizedHandler mHandler;
63d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    private final JobLimiter mThreadPool;
64adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin    private final TiledTexture.Uploader mTileUploader;
65d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mSize;
67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mContentStart = 0;
69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mContentEnd = 0;
70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveStart = 0;
72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveEnd = 0;
73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private Listener mListener;
75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private int mActiveRequestCount = 0;
77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private boolean mIsActive = false;
78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
792f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu    private class PanoSupportListener implements PanoramaSupportCallback {
802f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        public final AlbumEntry mEntry;
812f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        public PanoSupportListener (AlbumEntry entry) {
822f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu            mEntry = entry;
832f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        }
842f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        @Override
852f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama,
862f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu                boolean isPanorama360) {
872f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu            if (mEntry != null) mEntry.isPanorama = isPanorama;
882f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        }
892f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu    }
902f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu
91b21b8e58a604f6c701245d84b141b5b87663192bOwen Lin    public AlbumSlidingWindow(AbstractGalleryActivity activity,
92c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            AlbumDataLoader source, int cacheSize) {
93c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin        source.setDataListener(this);
94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSource = source;
951a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mData = new AlbumEntry[cacheSize];
96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mSize = source.size();
97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mHandler = new SynchronizedHandler(activity.getGLRoot()) {
99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            @Override
100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            public void handleMessage(Message message) {
1011a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                Utils.assertTrue(message.what == MSG_UPDATE_ENTRY);
1021a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                ((ThumbnailLoader) message.obj).updateEntry();
103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        };
105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
106113bfc77c4468411da9ae1290553c3be89f8df9aOwen Lin        mThreadPool = new JobLimiter(activity.getThreadPool(), JOB_LIMIT);
107adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin        mTileUploader = new TiledTexture.Uploader(activity.getGLRoot());
108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setListener(Listener listener) {
111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mListener = listener;
112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
1141a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    public AlbumEntry get(int slotIndex) {
115cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        if (!isActiveSlot(slotIndex)) {
116cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang            Utils.fail("invalid slot: %s outsides (%s, %s)",
117cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang                    slotIndex, mActiveStart, mActiveEnd);
118cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        }
119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        return mData[slotIndex % mData.length];
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 (!mIsActive) {
130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mContentStart = contentStart;
131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mContentEnd = contentEnd;
132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSource.setActiveWindow(contentStart, contentEnd);
133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            return;
134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (contentStart >= mContentEnd || mContentStart >= contentEnd) {
137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSource.setActiveWindow(contentStart, contentEnd);
141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentStart; i < contentEnd; ++i) {
142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentStart; i < contentStart; ++i) {
146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentEnd, n = mContentEnd; i < n; ++i) {
149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                freeSlotContent(i);
150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSource.setActiveWindow(contentStart, contentEnd);
152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = contentStart, n = mContentStart; i < n; ++i) {
153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            for (int i = mContentEnd; i < contentEnd; ++i) {
156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                prepareSlotContent(i);
157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            }
158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContentStart = contentStart;
161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mContentEnd = contentEnd;
162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void setActiveWindow(int start, int end) {
165cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        if (!(start <= end && end - start <= mData.length && end <= mSize)) {
166cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang            Utils.fail("%s, %s, %s, %s", start, end, mData.length, mSize);
167cfa105d3934c4dfa14f02b693bfa97c8d17d56a9Chih-Chung Chang        }
1681a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry data[] = mData;
169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveStart = start;
171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveEnd = end;
172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int contentStart = Utils.clamp((start + end) / 2 - data.length / 2,
174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                0, Math.max(0, mSize - data.length));
175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int contentEnd = Math.min(contentStart + data.length, mSize);
176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        setContentWindow(contentStart, contentEnd);
177cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        updateTextureUploadQueue();
178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mIsActive) updateAllImageRequests();
179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
181cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin    private void uploadBgTextureInSlot(int index) {
182cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        if (index < mContentEnd && index >= mContentStart) {
183cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            AlbumEntry entry = mData[index % mData.length];
1843535d67239b1b1e4ee038f39dece64545b78f2edOwen Lin            if (entry.bitmapTexture != null) {
185adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin                mTileUploader.addTexture(entry.bitmapTexture);
186cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            }
187d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        }
188d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    }
189d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
190cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin    private void updateTextureUploadQueue() {
191d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        if (!mIsActive) return;
192adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin        mTileUploader.clear();
193cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
194cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        // add foreground textures
195cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) {
196d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            AlbumEntry entry = mData[i % mData.length];
1973535d67239b1b1e4ee038f39dece64545b78f2edOwen Lin            if (entry.bitmapTexture != null) {
198adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin                mTileUploader.addTexture(entry.bitmapTexture);
199cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            }
200cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        }
201cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin
202cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        // add background textures
203cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        int range = Math.max(
204cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin                (mContentEnd - mActiveEnd), (mActiveStart - mContentStart));
205cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin        for (int i = 0; i < range; ++i) {
206cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            uploadBgTextureInSlot(mActiveEnd + i);
207cd36bfc52cc4e7f4b667ba3c5e8eb950647ae9d1Owen Lin            uploadBgTextureInSlot(mActiveStart - i - 1);
208d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        }
209d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin    }
210d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin
211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // We would like to request non active slots in the following order:
212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    // Order:    8 6 4 2                   1 3 5 7
213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //         |---------|---------------|---------|
214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //                   |<-  active  ->|
215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    //         |<-------- cached range ----------->|
216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void requestNonactiveImages() {
217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int range = Math.max(
218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                (mContentEnd - mActiveEnd), (mActiveStart - mContentStart));
219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0 ;i < range; ++i) {
2201a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            requestSlotImage(mActiveEnd + i);
2211a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            requestSlotImage(mActiveStart - 1 - i);
222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2251a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    // return whether the request is in progress or not
2261a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private boolean requestSlotImage(int slotIndex) {
2271a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        if (slotIndex < mContentStart || slotIndex >= mContentEnd) return false;
2281a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry entry = mData[slotIndex % mData.length];
2291a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        if (entry.content != null || entry.item == null) return false;
2301a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
2312f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        // Set up the panorama callback
2322f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        entry.mPanoSupportListener = new PanoSupportListener(entry);
2332f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu        entry.item.getPanoramaSupport(entry.mPanoSupportListener);
2342f060cc74ab6be5e5dd39e53dc99941b368ffb60Doris Liu
2351a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.contentLoader.startLoad();
2361a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        return entry.contentLoader.isRequestInProgress();
237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void cancelNonactiveImages() {
240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int range = Math.max(
241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin                (mContentEnd - mActiveEnd), (mActiveStart - mContentStart));
242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = 0 ;i < range; ++i) {
2431a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            cancelSlotImage(mActiveEnd + i);
2441a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            cancelSlotImage(mActiveStart - 1 - i);
245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2481a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private void cancelSlotImage(int slotIndex) {
249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (slotIndex < mContentStart || slotIndex >= mContentEnd) return;
2501a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry item = mData[slotIndex % mData.length];
2511a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        if (item.contentLoader != null) item.contentLoader.cancelLoad();
252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void freeSlotContent(int slotIndex) {
2551a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry data[] = mData;
256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        int index = slotIndex % data.length;
2571a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry entry = data[index];
2583535d67239b1b1e4ee038f39dece64545b78f2edOwen Lin        if (entry.contentLoader != null) entry.contentLoader.recycle();
2593535d67239b1b1e4ee038f39dece64545b78f2edOwen Lin        if (entry.bitmapTexture != null) entry.bitmapTexture.recycle();
2601a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        data[index] = null;
261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2631a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private void prepareSlotContent(int slotIndex) {
2641a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        AlbumEntry entry = new AlbumEntry();
2651a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        MediaItem item = mSource.get(slotIndex); // item could be null;
2661a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.item = item;
2671a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.mediaType = (item == null)
2681a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                ? MediaItem.MEDIA_TYPE_UNKNOWN
2691a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                : entry.item.getMediaType();
2701a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.path = (item == null) ? null : item.getPath();
2711a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.rotation = (item == null) ? 0 : item.getRotation();
2721a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        entry.contentLoader = new ThumbnailLoader(slotIndex, entry.item);
2731a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        mData[slotIndex % mData.length] = entry;
274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    private void updateAllImageRequests() {
277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mActiveRequestCount = 0;
278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) {
2791a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            if (requestSlotImage(i)) ++mActiveRequestCount;
280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mActiveRequestCount == 0) {
282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            requestNonactiveImages();
283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        } else {
284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            cancelNonactiveImages();
285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
2881a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    private class ThumbnailLoader extends BitmapLoader  {
289d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        private final int mSlotIndex;
290d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin        private final MediaItem mItem;
2911a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin
2921a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public ThumbnailLoader(int slotIndex, MediaItem item) {
293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSlotIndex = slotIndex;
2941a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            mItem = item;
295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
2981a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) {
2991a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            return mThreadPool.submit(
3001a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                    mItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL), this);
301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        @Override
3041a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        protected void onLoadComplete(Bitmap bitmap) {
3051a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            mHandler.obtainMessage(MSG_UPDATE_ENTRY, this).sendToTarget();
306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3081a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin        public void updateEntry() {
309d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            Bitmap bitmap = getBitmap();
310d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            if (bitmap == null) return; // error or recycled
3111a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            AlbumEntry entry = mData[mSlotIndex % mData.length];
312adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin            entry.bitmapTexture = new TiledTexture(bitmap);
3133535d67239b1b1e4ee038f39dece64545b78f2edOwen Lin            entry.content = entry.bitmapTexture;
314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3151a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            if (isActiveSlot(mSlotIndex)) {
316adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin                mTileUploader.addTexture(entry.bitmapTexture);
3171a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                --mActiveRequestCount;
3181a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                if (mActiveRequestCount == 0) requestNonactiveImages();
3191a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin                if (mListener != null) mListener.onContentChanged();
320d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin            } else {
321adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin                mTileUploader.addTexture(entry.bitmapTexture);
3221a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin            }
323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3261a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    @Override
327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void onSizeChanged(int size) {
328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (mSize != size) {
329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            mSize = size;
330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            if (mListener != null) mListener.onSizeChanged(mSize);
331cd938f3f05975de73658dc2f2b6c632b7ee569a3Yuli Huang            if (mContentEnd > mSize) mContentEnd = mSize;
332cd938f3f05975de73658dc2f2b6c632b7ee569a3Yuli Huang            if (mActiveEnd > mSize) mActiveEnd = mSize;
333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
3361a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin    @Override
337c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin    public void onContentChanged(int index) {
338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        if (index >= mContentStart && index < mContentEnd && mIsActive) {
339c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            freeSlotContent(index);
340c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            prepareSlotContent(index);
341c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            updateAllImageRequests();
342c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            if (mListener != null && isActiveSlot(index)) {
343c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin                mListener.onContentChanged();
344c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin            }
345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void resume() {
349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mIsActive = true;
350adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin        TiledTexture.prepareResources();
351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            prepareSlotContent(i);
353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        updateAllImageRequests();
355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin
357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    public void pause() {
358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        mIsActive = false;
359adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin        mTileUploader.clear();
360adee31f028d839e7baa8f9e052dc4e4d60b137daOwen Lin        TiledTexture.freeResources();
361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin            freeSlotContent(i);
363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin        }
364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin    }
365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin}
366