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.app; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 19fe49be45412f8d0f68343662318e73822da486c8Owen Linimport android.os.Handler; 20fe49be45412f8d0f68343662318e73822da486c8Owen Linimport android.os.Message; 21fe49be45412f8d0f68343662318e73822da486c8Owen Lin 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.ContentListener; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.DataManager; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaObject; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaSet; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.AlbumView; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.SynchronizedHandler; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList; 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.Arrays; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.Callable; 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.ExecutionException; 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.FutureTask; 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic class AlbumDataAdapter implements AlbumView.Model { 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "AlbumDataAdapter"; 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int DATA_CACHE_SIZE = 1000; 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_LOAD_START = 1; 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_LOAD_FINISH = 2; 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_RUN_OBJECT = 3; 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MIN_LOAD_COUNT = 32; 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MAX_LOAD_COUNT = 64; 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final MediaItem[] mData; 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final long[] mItemVersion; 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final long[] mSetVersion; 52f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveStart = 0; 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveEnd = 0; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentStart = 0; 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentEnd = 0; 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final MediaSet mSource; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private long mSourceVersion = MediaObject.INVALID_DATA_VERSION; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Handler mMainHandler; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSize = 0; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private AlbumView.ModelListener mModelListener; 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private MySourceListener mSourceListener = new MySourceListener(); 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private LoadingListener mLoadingListener; 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ReloadTask mReloadTask; 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public AlbumDataAdapter(GalleryActivity context, MediaSet mediaSet) { 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource = mediaSet; 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData = new MediaItem[DATA_CACHE_SIZE]; 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion = new long[DATA_CACHE_SIZE]; 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion = new long[DATA_CACHE_SIZE]; 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Arrays.fill(mItemVersion, MediaObject.INVALID_DATA_VERSION); 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Arrays.fill(mSetVersion, MediaObject.INVALID_DATA_VERSION); 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler = new SynchronizedHandler(context.getGLRoot()) { 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void handleMessage(Message message) { 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (message.what) { 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_RUN_OBJECT: 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ((Runnable) message.obj).run(); 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_LOAD_START: 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLoadingListener != null) mLoadingListener.onLoadingStarted(); 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_LOAD_FINISH: 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLoadingListener != null) mLoadingListener.onLoadingFinished(); 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void resume() { 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.addContentListener(mSourceListener); 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = new ReloadTask(); 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.start(); 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void pause() { 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.terminate(); 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = null; 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.removeContentListener(mSourceListener); 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaItem get(int index) { 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!isActive(index)) { 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(String.format( 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "%s not in (%s, %s)", index, mActiveStart, mActiveEnd)); 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mData[index % mData.length]; 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getActiveStart() { 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mActiveStart; 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getActiveEnd() { 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mActiveEnd; 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isActive(int index) { 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return index >= mActiveStart && index < mActiveEnd; 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size() { 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mSize; 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void clearSlot(int slotIndex) { 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[slotIndex] = null; 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void setContentWindow(int contentStart, int contentEnd) { 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart == mContentStart && contentEnd == mContentEnd) return; 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int end = mContentEnd; 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = mContentStart; 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We need change the content window before calling reloadData(...) 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (this) { 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentStart = contentStart; 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentEnd = contentEnd; 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long[] itemVersion = mItemVersion; 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long[] setVersion = mSetVersion; 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart >= end || start >= contentEnd) { 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start, n = end; i < n; ++i) { 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % DATA_CACHE_SIZE); 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start; i < contentStart; ++i) { 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % DATA_CACHE_SIZE); 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = contentEnd, n = end; i < n; ++i) { 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % DATA_CACHE_SIZE); 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mReloadTask != null) mReloadTask.notifyDirty(); 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setActiveWindow(int start, int end) { 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == mActiveStart && end == mActiveEnd) return; 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.assertTrue(start <= end 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && end - start <= mData.length && end <= mSize); 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int length = mData.length; 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveStart = start; 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveEnd = end; 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If no data is visible, keep the cache content 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == end) return; 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentStart = Utils.clamp((start + end) / 2 - length / 2, 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 0, Math.max(0, mSize - length)); 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentEnd = Math.min(contentStart + length, mSize); 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentStart > start || mContentEnd < end 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || Math.abs(contentStart - mContentStart) > MIN_LOAD_COUNT) { 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setContentWindow(contentStart, contentEnd); 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class MySourceListener implements ContentListener { 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onContentDirty() { 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mReloadTask != null) mReloadTask.notifyDirty(); 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setModelListener(AlbumView.ModelListener listener) { 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mModelListener = listener; 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setLoadingListener(LoadingListener listener) { 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingListener = listener; 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private <T> T executeAndWait(Callable<T> callable) { 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin FutureTask<T> task = new FutureTask<T>(callable); 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.sendMessage( 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.obtainMessage(MSG_RUN_OBJECT, task)); 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return task.get(); 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (InterruptedException e) { 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (ExecutionException e) { 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException(e); 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static class UpdateInfo { 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public long version; 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int reloadStart; 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int reloadCount; 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size; 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public ArrayList<MediaItem> items; 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class GetUpdateInfo implements Callable<UpdateInfo> { 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final long mVersion; 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GetUpdateInfo(long version) { 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVersion = version; 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public UpdateInfo call() throws Exception { 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = new UpdateInfo(); 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long version = mVersion; 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.version = mSourceVersion; 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.size = mSize; 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long setVersion[] = mSetVersion; 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentStart, n = mContentEnd; i < n; ++i) { 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = i % DATA_CACHE_SIZE; 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (setVersion[index] != version) { 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.reloadStart = i; 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.reloadCount = Math.min(MAX_LOAD_COUNT, n - i); 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return info; 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mSourceVersion == mVersion ? null : info; 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class UpdateContent implements Callable<Void> { 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private UpdateInfo mUpdateInfo; 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public UpdateContent(UpdateInfo info) { 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUpdateInfo = info; 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Void call() throws Exception { 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = mUpdateInfo; 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSourceVersion = info.version; 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSize != info.size) { 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSize = info.size; 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mModelListener != null) mModelListener.onSizeChanged(mSize); 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentEnd > mSize) mContentEnd = mSize; 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveEnd > mSize) mActiveEnd = mSize; 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<MediaItem> items = info.items; 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (items == null) return null; 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = Math.max(info.reloadStart, mContentStart); 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int end = Math.min(info.reloadStart + items.size(), mContentEnd); 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start; i < end; ++i) { 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = i % DATA_CACHE_SIZE; 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion[index] = info.version; 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaItem updateItem = items.get(i - info.reloadStart); 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long itemVersion = updateItem.getDataVersion(); 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mItemVersion[index] != itemVersion) { 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion[index] = itemVersion; 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[index] = updateItem; 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mModelListener != null && i >= mActiveStart && i < mActiveEnd) { 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mModelListener.onWindowContentChanged(i); 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /* 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * The thread model of ReloadTask 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * * 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * [Reload Task] [Main Thread] 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * getUpdateInfo() --> | (synchronous call) 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (wait) <---- getUpdateInfo() 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Load Data | 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * updateContent() --> | (synchronous call) 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (wait) updateContent() 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class ReloadTask extends Thread { 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mActive = true; 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mDirty = true; 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mIsLoading = false; 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateLoading(boolean loading) { 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mIsLoading == loading) return; 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIsLoading = loading; 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.sendEmptyMessage(loading ? MSG_LOAD_START : MSG_LOAD_FINISH); 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void run() { 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean updateComplete = false; 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (mActive) { 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (this) { 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActive && !mDirty && updateComplete) { 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(false); 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.waitWithoutInterrupt(this); 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin continue; 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDirty = false; 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(true); 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long version; 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (DataManager.LOCK) { 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin version = mSource.reload(); 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = executeAndWait(new GetUpdateInfo(version)); 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateComplete = info == null; 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (updateComplete) continue; 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (DataManager.LOCK) { 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info.version != version) { 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.size = mSource.getMediaItemCount(); 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.version = version; 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info.reloadCount > 0) { 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.items = mSource.getMediaItem(info.reloadStart, info.reloadCount); 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin executeAndWait(new UpdateContent(info)); 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(false); 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void notifyDirty() { 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDirty = true; 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void terminate() { 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActive = false; 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 364