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; 22dbf4ba12afba115888493caa34937643257e2bb1Ray Chen 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.ContentListener; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaItem; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaObject; 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaSet; 28995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolbimport com.android.gallery3d.data.Path; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.ui.SynchronizedHandler; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.Arrays; 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.Callable; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.ExecutionException; 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.concurrent.FutureTask; 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 36c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Linpublic class AlbumSetDataLoader { 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @SuppressWarnings("unused") 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "AlbumSetDataAdapter"; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int INDEX_NONE = -1; 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MIN_LOAD_COUNT = 4; 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_LOAD_START = 1; 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_LOAD_FINISH = 2; 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final int MSG_RUN_OBJECT = 3; 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 48c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public static interface DataListener { 49c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void onContentChanged(int index); 50c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void onSizeChanged(int size); 51c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin } 52c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final MediaSet[] mData; 541a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin private final MediaItem[] mCoverItem; 558ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin private final int[] mTotalCount; 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 77b21b8e58a604f6c701245d84b141b5b87663192bOwen Lin public AlbumSetDataLoader(AbstractGalleryActivity activity, MediaSet albumSet, int cacheSize) { 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource = Utils.checkNotNull(albumSet); 791a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin mCoverItem = new MediaItem[cacheSize]; 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData = new MediaSet[cacheSize]; 818ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin mTotalCount = new int[cacheSize]; 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion = new long[cacheSize]; 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion = new long[cacheSize]; 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Arrays.fill(mItemVersion, MediaObject.INVALID_DATA_VERSION); 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Arrays.fill(mSetVersion, MediaObject.INVALID_DATA_VERSION); 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler = new SynchronizedHandler(activity.getGLRoot()) { 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void handleMessage(Message message) { 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (message.what) { 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_RUN_OBJECT: 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ((Runnable) message.obj).run(); 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_LOAD_START: 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mLoadingListener != null) mLoadingListener.onLoadingStarted(); 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case MSG_LOAD_FINISH: 9805da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan if (mLoadingListener != null) mLoadingListener.onLoadingFinished(false); 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void pause() { 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.terminate(); 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = null; 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.removeContentListener(mSourceListener); 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void resume() { 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.addContentListener(mSourceListener); 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = new ReloadTask(); 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.start(); 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1178ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin private void assertIsActive(int index) { 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index < mActiveStart && index >= mActiveEnd) { 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(String.format( 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "%s not in (%s, %s)", index, mActiveStart, mActiveEnd)); 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 1228ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin } 1238ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin 1248ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin public MediaSet getMediaSet(int index) { 1258ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin assertIsActive(index); 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mData[index % mData.length]; 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1291a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin public MediaItem getCoverItem(int index) { 1308ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin assertIsActive(index); 1311a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin return mCoverItem[index % mCoverItem.length]; 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1348ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin public int getTotalCount(int index) { 1358ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin assertIsActive(index); 1368ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin return mTotalCount[index % mTotalCount.length]; 1378ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin } 1388ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getActiveStart() { 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mActiveStart; 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isActive(int index) { 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return index >= mActiveStart && index < mActiveEnd; 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size() { 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mSize; 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 151995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb // Returns the index of the MediaSet with the given path or 152995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb // -1 if the path is not cached 153995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb public int findSet(Path id) { 154995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb int length = mData.length; 155995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb for (int i = mContentStart; i < mContentEnd; i++) { 156995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb MediaSet set = mData[i % length]; 157995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb if (set != null && id == set.getPath()) { 158995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb return i; 159995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb } 160995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb } 161995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb return -1; 162995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb } 163995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void clearSlot(int slotIndex) { 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[slotIndex] = null; 1661a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin mCoverItem[slotIndex] = null; 1678ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin mTotalCount[slotIndex] = 0; 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void setContentWindow(int contentStart, int contentEnd) { 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart == mContentStart && contentEnd == mContentEnd) return; 1741a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin int length = mCoverItem.length; 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = this.mContentStart; 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int end = this.mContentEnd; 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentStart = contentStart; 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentEnd = contentEnd; 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart >= end || start >= contentEnd) { 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start, n = end; i < n; ++i) { 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % length); 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start; i < contentStart; ++i) { 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % length); 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = contentEnd, n = end; i < n; ++i) { 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % length); 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.notifyDirty(); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setActiveWindow(int start, int end) { 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == mActiveStart && end == mActiveEnd) return; 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.assertTrue(start <= end 2011a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin && end - start <= mCoverItem.length && end <= mSize); 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveStart = start; 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveEnd = end; 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2061a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin int length = mCoverItem.length; 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If no data is visible, keep the cache content 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == end) return; 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentStart = Utils.clamp((start + end) / 2 - length / 2, 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 0, Math.max(0, mSize - length)); 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentEnd = Math.min(contentStart + length, mSize); 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentStart > start || mContentEnd < end 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || Math.abs(contentStart - mContentStart) > MIN_LOAD_COUNT) { 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setContentWindow(contentStart, contentEnd); 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class MySourceListener implements ContentListener { 2207817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onContentDirty() { 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.notifyDirty(); 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 226c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void setModelListener(DataListener listener) { 227c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin mDataListener = listener; 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setLoadingListener(LoadingListener listener) { 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingListener = listener; 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static class UpdateInfo { 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public long version; 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int index; 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size; 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet item; 2401a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin public MediaItem cover; 2418ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin public int totalCount; 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class GetUpdateInfo implements Callable<UpdateInfo> { 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final long mVersion; 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GetUpdateInfo(long version) { 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVersion = version; 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 252f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int getInvalidIndex(long version) { 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long setVersion[] = mSetVersion; 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int length = setVersion.length; 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentStart, n = mContentEnd; i < n; ++i) { 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = i % length; 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (setVersion[i % length] != version) return i; 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return INDEX_NONE; 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public UpdateInfo call() throws Exception { 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = getInvalidIndex(mVersion); 265dbf4ba12afba115888493caa34937643257e2bb1Ray Chen if (index == INDEX_NONE && mSourceVersion == mVersion) return null; 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = new UpdateInfo(); 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.version = mSourceVersion; 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.index = index; 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.size = mSize; 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return info; 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class UpdateContent implements Callable<Void> { 275dbf4ba12afba115888493caa34937643257e2bb1Ray Chen private final UpdateInfo mUpdateInfo; 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public UpdateContent(UpdateInfo info) { 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUpdateInfo = info; 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2817817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Void call() { 283dbf4ba12afba115888493caa34937643257e2bb1Ray Chen // Avoid notifying listeners of status change after pause 284dbf4ba12afba115888493caa34937643257e2bb1Ray Chen // Otherwise gallery will be in inconsistent state after resume. 285dbf4ba12afba115888493caa34937643257e2bb1Ray Chen if (mReloadTask == null) return null; 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = mUpdateInfo; 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSourceVersion = info.version; 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSize != info.size) { 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSize = info.size; 290c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin if (mDataListener != null) mDataListener.onSizeChanged(mSize); 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentEnd > mSize) mContentEnd = mSize; 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveEnd > mSize) mActiveEnd = mSize; 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Note: info.index could be INDEX_NONE, i.e., -1 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (info.index >= mContentStart && info.index < mContentEnd) { 2961a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin int pos = info.index % mCoverItem.length; 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion[pos] = info.version; 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long itemVersion = info.item.getDataVersion(); 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mItemVersion[pos] == itemVersion) return null; 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion[pos] = itemVersion; 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[pos] = info.item; 3021a4bd273afe5dd11592f7625c2f19853b6f174e9Owen Lin mCoverItem[pos] = info.cover; 3038ef6c55bdad9a3e835ce56bdc98681434b4ac5b3Owen Lin mTotalCount[pos] = info.totalCount; 304c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin if (mDataListener != null 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && info.index >= mActiveStart && info.index < mActiveEnd) { 306c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin mDataListener.onContentChanged(info.index); 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private <T> T executeAndWait(Callable<T> callable) { 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin FutureTask<T> task = new FutureTask<T>(callable); 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.sendMessage( 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.obtainMessage(MSG_RUN_OBJECT, task)); 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return task.get(); 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (InterruptedException e) { 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (ExecutionException e) { 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException(e); 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // TODO: load active range first 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class ReloadTask extends Thread { 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mActive = true; 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mDirty = true; 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mIsLoading = false; 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateLoading(boolean loading) { 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mIsLoading == loading) return; 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIsLoading = loading; 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.sendEmptyMessage(loading ? MSG_LOAD_START : MSG_LOAD_FINISH); 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void run() { 340d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 341d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean updateComplete = false; 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (mActive) { 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (this) { 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActive && !mDirty && updateComplete) { 346705dc819661cb8c8e839a04577b0641bd6caad53John Reck if (!mSource.isLoading()) updateLoading(false); 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.waitWithoutInterrupt(this); 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin continue; 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDirty = false; 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(true); 353f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 354705dc819661cb8c8e839a04577b0641bd6caad53John Reck long version = mSource.reload(); 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = executeAndWait(new GetUpdateInfo(version)); 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateComplete = info == null; 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (updateComplete) continue; 358676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (info.version != version) { 359676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.version = version; 360676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.size = mSource.getSubMediaSetCount(); 361676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin 362676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // If the size becomes smaller after reload(), we may 363676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // receive from GetUpdateInfo an index which is too 364676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // big. Because the main thread is not aware of the size 365676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // change until we call UpdateContent. 366676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (info.index >= info.size) { 367676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.index = INDEX_NONE; 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 369f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 370676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (info.index != INDEX_NONE) { 371676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.item = mSource.getSubMediaSet(info.index); 372676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (info.item == null) continue; 373676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.cover = info.item.getCoverMediaItem(); 374676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.totalCount = info.item.getTotalMediaItemCount(); 375676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin } 376f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin executeAndWait(new UpdateContent(info)); 377f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 378f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(false); 379f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 380f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 381f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void notifyDirty() { 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDirty = true; 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void terminate() { 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActive = false; 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 394