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; 21d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Linimport android.os.Process; 22fe49be45412f8d0f68343662318e73822da486c8Owen Lin 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.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 37c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Linpublic class AlbumDataLoader { 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 53c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public static interface DataListener { 54c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void onContentChanged(int index); 55c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void onSizeChanged(int size); 56c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin } 57c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveStart = 0; 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveEnd = 0; 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentStart = 0; 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mContentEnd = 0; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final MediaSet mSource; 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private long mSourceVersion = MediaObject.INVALID_DATA_VERSION; 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Handler mMainHandler; 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mSize = 0; 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 70c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin private DataListener mDataListener; 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private MySourceListener mSourceListener = new MySourceListener(); 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private LoadingListener mLoadingListener; 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private ReloadTask mReloadTask; 7505da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan // the data version on which last loading failed 7605da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan private long mFailedVersion = MediaObject.INVALID_DATA_VERSION; 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 78b21b8e58a604f6c701245d84b141b5b87663192bOwen Lin public AlbumDataLoader(AbstractGalleryActivity context, MediaSet mediaSet) { 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource = mediaSet; 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData = new MediaItem[DATA_CACHE_SIZE]; 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion = new long[DATA_CACHE_SIZE]; 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion = new long[DATA_CACHE_SIZE]; 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(context.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) { 9905da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan boolean loadingFailed = 10005da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan (mFailedVersion != MediaObject.INVALID_DATA_VERSION); 10105da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan mLoadingListener.onLoadingFinished(loadingFailed); 10205da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan } 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return; 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void resume() { 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.addContentListener(mSourceListener); 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = new ReloadTask(); 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.start(); 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void pause() { 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask.terminate(); 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mReloadTask = null; 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSource.removeContentListener(mSourceListener); 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaItem get(int index) { 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!isActive(index)) { 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(String.format( 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "%s not in (%s, %s)", index, mActiveStart, mActiveEnd)); 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mData[index % mData.length]; 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getActiveStart() { 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mActiveStart; 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isActive(int index) { 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return index >= mActiveStart && index < mActiveEnd; 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size() { 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mSize; 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 141995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb // Returns the index of the MediaItem with the given path or 142995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb // -1 if the path is not cached 143995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb public int findItem(Path id) { 144995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb for (int i = mContentStart; i < mContentEnd; i++) { 145995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb MediaItem item = mData[i % DATA_CACHE_SIZE]; 146995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb if (item != null && id == item.getPath()) { 147995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb return i; 148995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb } 149995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb } 150995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb return -1; 151995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb } 152995c4566bed7df1aa48ba7e1351f964efa73880bMichael Kolb 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void clearSlot(int slotIndex) { 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[slotIndex] = null; 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion[slotIndex] = MediaObject.INVALID_DATA_VERSION; 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void setContentWindow(int contentStart, int contentEnd) { 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart == mContentStart && contentEnd == mContentEnd) return; 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int end = mContentEnd; 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = mContentStart; 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // We need change the content window before calling reloadData(...) 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (this) { 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentStart = contentStart; 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mContentEnd = contentEnd; 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long[] itemVersion = mItemVersion; 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long[] setVersion = mSetVersion; 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (contentStart >= end || start >= contentEnd) { 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start, n = end; i < n; ++i) { 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % DATA_CACHE_SIZE); 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } else { 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start; i < contentStart; ++i) { 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % DATA_CACHE_SIZE); 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = contentEnd, n = end; i < n; ++i) { 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin clearSlot(i % DATA_CACHE_SIZE); 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mReloadTask != null) mReloadTask.notifyDirty(); 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setActiveWindow(int start, int end) { 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == mActiveStart && end == mActiveEnd) return; 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.assertTrue(start <= end 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin && end - start <= mData.length && end <= mSize); 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int length = mData.length; 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveStart = start; 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActiveEnd = end; 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // If no data is visible, keep the cache content 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (start == end) return; 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentStart = Utils.clamp((start + end) / 2 - length / 2, 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 0, Math.max(0, mSize - length)); 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int contentEnd = Math.min(contentStart + length, mSize); 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentStart > start || mContentEnd < end 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin || Math.abs(contentStart - mContentStart) > MIN_LOAD_COUNT) { 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin setContentWindow(contentStart, contentEnd); 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class MySourceListener implements ContentListener { 2097817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void onContentDirty() { 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mReloadTask != null) mReloadTask.notifyDirty(); 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 215c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin public void setDataListener(DataListener listener) { 216c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin mDataListener = listener; 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void setLoadingListener(LoadingListener listener) { 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mLoadingListener = listener; 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private <T> T executeAndWait(Callable<T> callable) { 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin FutureTask<T> task = new FutureTask<T>(callable); 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.sendMessage( 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.obtainMessage(MSG_RUN_OBJECT, task)); 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin try { 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return task.get(); 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (InterruptedException e) { 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } catch (ExecutionException e) { 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new RuntimeException(e); 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static class UpdateInfo { 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public long version; 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int reloadStart; 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int reloadCount; 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int size; 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public ArrayList<MediaItem> items; 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class GetUpdateInfo implements Callable<UpdateInfo> { 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final long mVersion; 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public GetUpdateInfo(long version) { 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mVersion = version; 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2527817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public UpdateInfo call() throws Exception { 25405da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan if (mFailedVersion == mVersion) { 25505da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan // previous loading failed, return null to pause loading 25605da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan return null; 25705da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan } 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = new UpdateInfo(); 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long version = mVersion; 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.version = mSourceVersion; 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.size = mSize; 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long setVersion[] = mSetVersion; 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = mContentStart, n = mContentEnd; i < n; ++i) { 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = i % DATA_CACHE_SIZE; 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (setVersion[index] != version) { 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.reloadStart = i; 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin info.reloadCount = Math.min(MAX_LOAD_COUNT, n - i); 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return info; 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return mSourceVersion == mVersion ? null : info; 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class UpdateContent implements Callable<Void> { 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private UpdateInfo mUpdateInfo; 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public UpdateContent(UpdateInfo info) { 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mUpdateInfo = info; 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Void call() throws Exception { 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = mUpdateInfo; 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSourceVersion = info.version; 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mSize != info.size) { 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSize = info.size; 289c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin if (mDataListener != null) mDataListener.onSizeChanged(mSize); 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mContentEnd > mSize) mContentEnd = mSize; 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveEnd > mSize) mActiveEnd = mSize; 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<MediaItem> items = info.items; 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 29605da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan mFailedVersion = MediaObject.INVALID_DATA_VERSION; 29705da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan if ((items == null) || items.isEmpty()) { 29805da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan if (info.reloadCount > 0) { 29905da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan mFailedVersion = info.version; 30005da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan Log.d(TAG, "loading failed: " + mFailedVersion); 30105da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan } 30205da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan return null; 30305da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan } 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = Math.max(info.reloadStart, mContentStart); 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int end = Math.min(info.reloadStart + items.size(), mContentEnd); 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = start; i < end; ++i) { 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = i % DATA_CACHE_SIZE; 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSetVersion[index] = info.version; 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaItem updateItem = items.get(i - info.reloadStart); 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long itemVersion = updateItem.getDataVersion(); 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mItemVersion[index] != itemVersion) { 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mItemVersion[index] = itemVersion; 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mData[index] = updateItem; 315c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin if (mDataListener != null && i >= mActiveStart && i < mActiveEnd) { 316c3d8ac3b9504346dafc49e006b5f732dd1db21e8Owen Lin mDataListener.onContentChanged(i); 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin /* 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * The thread model of ReloadTask 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * * 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * [Reload Task] [Main Thread] 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * getUpdateInfo() --> | (synchronous call) 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (wait) <---- getUpdateInfo() 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * Load Data | 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * updateContent() --> | (synchronous call) 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * (wait) updateContent() 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin * | | 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin */ 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private class ReloadTask extends Thread { 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mActive = true; 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private volatile boolean mDirty = true; 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private boolean mIsLoading = false; 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private void updateLoading(boolean loading) { 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mIsLoading == loading) return; 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mIsLoading = loading; 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mMainHandler.sendEmptyMessage(loading ? MSG_LOAD_START : MSG_LOAD_FINISH); 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 352f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void run() { 353d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); 354d8fb81f601830385a2343d08ad5dd171e4c7bfe0Owen Lin 355f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin boolean updateComplete = false; 356f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (mActive) { 357f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (this) { 358f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActive && !mDirty && updateComplete) { 359f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(false); 36005da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan if (mFailedVersion != MediaObject.INVALID_DATA_VERSION) { 36105da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan Log.d(TAG, "reload pause"); 36205da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan } 363f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Utils.waitWithoutInterrupt(this); 36405da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan if (mActive && (mFailedVersion != MediaObject.INVALID_DATA_VERSION)) { 36505da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan Log.d(TAG, "reload resume"); 36605da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan } 367f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin continue; 368f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 36905da3f520eacb9219964b6ed57ef37846d889fd7Hung-ying Tyan mDirty = false; 370f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 371f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(true); 372676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin long version = mSource.reload(); 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin UpdateInfo info = executeAndWait(new GetUpdateInfo(version)); 374f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateComplete = info == null; 375f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (updateComplete) continue; 376676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (info.version != version) { 377676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.size = mSource.getMediaItemCount(); 378676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.version = version; 379676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin } 380676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (info.reloadCount > 0) { 381676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin info.items = mSource.getMediaItem(info.reloadStart, info.reloadCount); 382f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 383f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin executeAndWait(new UpdateContent(info)); 384f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 385f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin updateLoading(false); 386f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 387f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 388f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void notifyDirty() { 389f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDirty = true; 390f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 391f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 392f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 393f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void terminate() { 394f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mActive = false; 395f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifyAll(); 396f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 397f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 398f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 399