AlbumSetDataLoader.java revision c3d8ac3b9504346dafc49e006b5f732dd1db21e8
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 19dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport android.os.Handler; 20dbf4ba12afba115888493caa34937643257e2bb1Ray Chenimport android.os.Message; 21d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Linimport android.os.Process; 22c3b30370ce9665d4371f61f0224b7f262dd2c7eeOwen Linimport android.os.SystemClock; 23dbf4ba12afba115888493caa34937643257e2bb1Ray Chen 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.ContentListener; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.DataManager; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaObject; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaSet; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.SynchronizedHandler; 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 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 37c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Linpublic class AlbumSetDataLoader { 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "AlbumSetDataAdapter"; 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int INDEX_NONE = -1; 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MIN_LOAD_COUNT = 4; 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_LOAD_START = 1; 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_LOAD_FINISH = 2; 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_RUN_OBJECT = 3; 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 49c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public static interface DataListener { 50c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void onContentChanged(int index); 51c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void onSizeChanged(int size); 52c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin } 53c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final MediaSet[] mData; 551a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin private final MediaItem[] mCoverItem; 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final long[] mItemVersion; 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final long[] mSetVersion; 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveStart = 0; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveEnd = 0; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentStart = 0; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentEnd = 0; 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final MediaSet mSource; 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private long mSourceVersion = MediaObject.INVALID_DATA_VERSION; 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSize; 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 69c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin private DataListener mDataListener; 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private LoadingListener mLoadingListener; 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ReloadTask mReloadTask; 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Handler mMainHandler; 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 75dbf4ba12afba115888493caa34937643257e2bb1Ray Chen private final MySourceListener mSourceListener = new MySourceListener(); 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 77c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public AlbumSetDataLoader(GalleryActivity activity, MediaSet albumSet, int cacheSize) { 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource = Utils.checkNotNull(albumSet); 791a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin mCoverItem = new MediaItem[cacheSize]; 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData = new MediaSet[cacheSize]; 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion = new long[cacheSize]; 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion = new long[cacheSize]; 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Arrays.fill(mItemVersion, MediaObject.INVALID_DATA_VERSION); 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Arrays.fill(mSetVersion, MediaObject.INVALID_DATA_VERSION); 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler = new SynchronizedHandler(activity.getGLRoot()) { 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void handleMessage(Message message) { 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (message.what) { 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_RUN_OBJECT: 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ((Runnable) message.obj).run(); 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_LOAD_START: 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLoadingListener != null) mLoadingListener.onLoadingStarted(); 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_LOAD_FINISH: 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLoadingListener != null) mLoadingListener.onLoadingFinished(); 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 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 void resume() { 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.addContentListener(mSourceListener); 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = new ReloadTask(); 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.start(); 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet getMediaSet(int index) { 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index < mActiveStart && index >= mActiveEnd) { 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(String.format( 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "%s not in (%s, %s)", index, mActiveStart, mActiveEnd)); 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mData[index % mData.length]; 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1241a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin public MediaItem getCoverItem(int index) { 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index < mActiveStart && index >= mActiveEnd) { 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(String.format( 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "%s not in (%s, %s)", index, mActiveStart, mActiveEnd)); 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1291a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin return mCoverItem[index % mCoverItem.length]; 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getActiveStart() { 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mActiveStart; 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isActive(int index) { 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return index >= mActiveStart && index < mActiveEnd; 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size() { 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mSize; 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void clearSlot(int slotIndex) { 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[slotIndex] = null; 1461a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin mCoverItem[slotIndex] = null; 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void setContentWindow(int contentStart, int contentEnd) { 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart == mContentStart && contentEnd == mContentEnd) return; 1531a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin int length = mCoverItem.length; 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = this.mContentStart; 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int end = this.mContentEnd; 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentStart = contentStart; 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentEnd = contentEnd; 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart >= end || start >= contentEnd) { 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start, n = end; i < n; ++i) { 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % length); 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start; i < contentStart; ++i) { 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % length); 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = contentEnd, n = end; i < n; ++i) { 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % length); 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.notifyDirty(); 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setActiveWindow(int start, int end) { 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == mActiveStart && end == mActiveEnd) return; 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.assertTrue(start <= end 1801a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin && end - start <= mCoverItem.length && end <= mSize); 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveStart = start; 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveEnd = end; 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1851a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin int length = mCoverItem.length; 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If no data is visible, keep the cache content 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == end) return; 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentStart = Utils.clamp((start + end) / 2 - length / 2, 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 0, Math.max(0, mSize - length)); 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentEnd = Math.min(contentStart + length, mSize); 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentStart > start || mContentEnd < end 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || Math.abs(contentStart - mContentStart) > MIN_LOAD_COUNT) { 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setContentWindow(contentStart, contentEnd); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class MySourceListener implements ContentListener { 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onContentDirty() { 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.notifyDirty(); 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 204c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void setModelListener(DataListener listener) { 205c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin mDataListener = listener; 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setLoadingListener(LoadingListener listener) { 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingListener = listener; 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static class UpdateInfo { 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public long version; 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int index; 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size; 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet item; 2181a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin public MediaItem cover; 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class GetUpdateInfo implements Callable<UpdateInfo> { 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final long mVersion; 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GetUpdateInfo(long version) { 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVersion = version; 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int getInvalidIndex(long version) { 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long setVersion[] = mSetVersion; 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int length = setVersion.length; 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentStart, n = mContentEnd; i < n; ++i) { 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = i % length; 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (setVersion[i % length] != version) return i; 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return INDEX_NONE; 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public UpdateInfo call() throws Exception { 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = getInvalidIndex(mVersion); 242dbf4ba12afba115888493caa34937643257e2bb1Ray Chen if (index == INDEX_NONE && mSourceVersion == mVersion) return null; 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = new UpdateInfo(); 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.version = mSourceVersion; 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.index = index; 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.size = mSize; 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return info; 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class UpdateContent implements Callable<Void> { 252dbf4ba12afba115888493caa34937643257e2bb1Ray Chen private final UpdateInfo mUpdateInfo; 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public UpdateContent(UpdateInfo info) { 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUpdateInfo = info; 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Void call() { 259dbf4ba12afba115888493caa34937643257e2bb1Ray Chen // Avoid notifying listeners of status change after pause 260dbf4ba12afba115888493caa34937643257e2bb1Ray Chen // Otherwise gallery will be in inconsistent state after resume. 261dbf4ba12afba115888493caa34937643257e2bb1Ray Chen if (mReloadTask == null) return null; 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = mUpdateInfo; 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSourceVersion = info.version; 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSize != info.size) { 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSize = info.size; 266c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin if (mDataListener != null) mDataListener.onSizeChanged(mSize); 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentEnd > mSize) mContentEnd = mSize; 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveEnd > mSize) mActiveEnd = mSize; 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Note: info.index could be INDEX_NONE, i.e., -1 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info.index >= mContentStart && info.index < mContentEnd) { 2721a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin int pos = info.index % mCoverItem.length; 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion[pos] = info.version; 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long itemVersion = info.item.getDataVersion(); 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mItemVersion[pos] == itemVersion) return null; 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion[pos] = itemVersion; 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[pos] = info.item; 2781a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin mCoverItem[pos] = info.cover; 279c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin if (mDataListener != null 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && info.index >= mActiveStart && info.index < mActiveEnd) { 281c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin mDataListener.onContentChanged(info.index); 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private <T> T executeAndWait(Callable<T> callable) { 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin FutureTask<T> task = new FutureTask<T>(callable); 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.sendMessage( 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.obtainMessage(MSG_RUN_OBJECT, task)); 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return task.get(); 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (InterruptedException e) { 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (ExecutionException e) { 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException(e); 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // TODO: load active range first 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class ReloadTask extends Thread { 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mActive = true; 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mDirty = true; 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mIsLoading = false; 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateLoading(boolean loading) { 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mIsLoading == loading) return; 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIsLoading = loading; 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.sendEmptyMessage(loading ? MSG_LOAD_START : MSG_LOAD_FINISH); 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void run() { 315d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 316d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean updateComplete = false; 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (mActive) { 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (this) { 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActive && !mDirty && updateComplete) { 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(false); 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.waitWithoutInterrupt(this); 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin continue; 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDirty = false; 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(true); 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long version; 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (DataManager.LOCK) { 331c3b30370ce9665d4371f61f0224b7f262dd2c7eeOwen Lin long start = SystemClock.uptimeMillis(); 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin version = mSource.reload(); 333c3b30370ce9665d4371f61f0224b7f262dd2c7eeOwen Lin long duration = SystemClock.uptimeMillis() - start; 334c3b30370ce9665d4371f61f0224b7f262dd2c7eeOwen Lin if (duration > 20) { 335c3b30370ce9665d4371f61f0224b7f262dd2c7eeOwen Lin Log.v("DebugLoadingTime", "finish reload - " + duration); 336c3b30370ce9665d4371f61f0224b7f262dd2c7eeOwen Lin } 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = executeAndWait(new GetUpdateInfo(version)); 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateComplete = info == null; 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (updateComplete) continue; 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (DataManager.LOCK) { 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info.version != version) { 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.version = version; 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.size = mSource.getSubMediaSetCount(); 3467cf4777f2d6691b5490b7e8df76d154ea5fd8bf7Chih-Chung Chang 3477cf4777f2d6691b5490b7e8df76d154ea5fd8bf7Chih-Chung Chang // If the size becomes smaller after reload(), we may 3487cf4777f2d6691b5490b7e8df76d154ea5fd8bf7Chih-Chung Chang // receive from GetUpdateInfo an index which is too 3497cf4777f2d6691b5490b7e8df76d154ea5fd8bf7Chih-Chung Chang // big. Because the main thread is not aware of the size 3507cf4777f2d6691b5490b7e8df76d154ea5fd8bf7Chih-Chung Chang // change until we call UpdateContent. 3517cf4777f2d6691b5490b7e8df76d154ea5fd8bf7Chih-Chung Chang if (info.index >= info.size) { 3527cf4777f2d6691b5490b7e8df76d154ea5fd8bf7Chih-Chung Chang info.index = INDEX_NONE; 3537cf4777f2d6691b5490b7e8df76d154ea5fd8bf7Chih-Chung Chang } 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info.index != INDEX_NONE) { 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.item = mSource.getSubMediaSet(info.index); 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info.item == null) continue; 3581a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin info.cover = info.item.getCoverMediaItem(); 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 360f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 361f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin executeAndWait(new UpdateContent(info)); 362f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(false); 364f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 365f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 366f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void notifyDirty() { 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDirty = true; 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void terminate() { 372f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActive = false; 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 379