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.data; 18f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 1957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyanimport com.android.gallery3d.common.Utils; 20f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.util.Future; 21f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 22f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList; 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.WeakHashMap; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// MediaSet is a directory-like data structure. 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// It contains MediaItems and sub-MediaSets. 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// The primary interface are: 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getMediaItemCount(), getMediaItem() and 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getSubMediaSetCount(), getSubMediaSet(). 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getTotalMediaItemCount() returns the number of all MediaItems, including 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// those in sub-MediaSets. 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic abstract class MediaSet extends MediaObject { 357817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @SuppressWarnings("unused") 36fe49be45412f8d0f68343662318e73822da486c8Owen Lin private static final String TAG = "MediaSet"; 37fe49be45412f8d0f68343662318e73822da486c8Owen Lin 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int MEDIAITEM_BATCH_FETCH_COUNT = 500; 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INDEX_NOT_FOUND = -1; 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 4157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public static final int SYNC_RESULT_SUCCESS = 0; 4257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public static final int SYNC_RESULT_CANCELLED = 1; 4357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public static final int SYNC_RESULT_ERROR = 2; 4457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 4557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan /** Listener to be used with requestSync(SyncListener). */ 4657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public static interface SyncListener { 4757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan /** 4857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * Called when the sync task completed. Completion may be due to normal termination, 4957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * an exception, or cancellation. 5057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * 5157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * @param mediaSet the MediaSet that's done with sync 5257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * @param resultCode one of the SYNC_RESULT_* constants 5357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan */ 5457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan void onSyncDone(MediaSet mediaSet, int resultCode); 5557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 5657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet(Path path, long version) { 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super(path, version); 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getMediaItemCount() { 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return 0; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Returns the media items in the range [start, start + count). 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The number of media items returned may be less than the specified count 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // if there are not enough media items available. The number of 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // media items available may not be consistent with the return value of 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // getMediaItemCount() because the contents of database may have already 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // changed. 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public ArrayList<MediaItem> getMediaItem(int start, int count) { 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return new ArrayList<MediaItem>(); 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 769ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin public MediaItem getCoverMediaItem() { 779ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin ArrayList<MediaItem> items = getMediaItem(0, 1); 789ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin if (items.size() > 0) return items.get(0); 799ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin for (int i = 0, n = getSubMediaSetCount(); i < n; i++) { 809ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin MediaItem cover = getSubMediaSet(i).getCoverMediaItem(); 819ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin if (cover != null) return cover; 829ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin } 839ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin return null; 849ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin } 859ce0381a975f65ec7794a2d3436b0424d0030f39Owen Lin 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getSubMediaSetCount() { 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return 0; 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet getSubMediaSet(int index) { 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IndexOutOfBoundsException(); 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isLeafAlbum() { 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 987eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu public boolean isCameraRoll() { 997eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu return false; 1007eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu } 1017eea4d3ac59aa88d327fc0d58f5e4052f43c54c9Bobby Georgescu 102e8c1e69f85efb8673d0606f3aca729a366038753Ray Chen /** 103e8c1e69f85efb8673d0606f3aca729a366038753Ray Chen * Method {@link #reload()} may process the loading task in background, this method tells 104e8c1e69f85efb8673d0606f3aca729a366038753Ray Chen * its client whether the loading is still in process or not. 105e8c1e69f85efb8673d0606f3aca729a366038753Ray Chen */ 106e8c1e69f85efb8673d0606f3aca729a366038753Ray Chen public boolean isLoading() { 107e8c1e69f85efb8673d0606f3aca729a366038753Ray Chen return false; 108e8c1e69f85efb8673d0606f3aca729a366038753Ray Chen } 109e8c1e69f85efb8673d0606f3aca729a366038753Ray Chen 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getTotalMediaItemCount() { 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int total = getMediaItemCount(); 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = getSubMediaSetCount(); i < n; i++) { 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin total += getSubMediaSet(i).getTotalMediaItemCount(); 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return total; 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // TODO: we should have better implementation of sub classes 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getIndexOfItem(Path path, int hint) { 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // hint < 0 is handled below 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // first, try to find it around the hint 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = Math.max(0, 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin hint - MEDIAITEM_BATCH_FETCH_COUNT / 2); 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<MediaItem> list = getMediaItem( 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start, MEDIAITEM_BATCH_FETCH_COUNT); 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = getIndexOf(path, list); 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index != INDEX_NOT_FOUND) return start + index; 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // try to find it globally 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start = start == 0 ? MEDIAITEM_BATCH_FETCH_COUNT : 0; 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin list = getMediaItem(start, MEDIAITEM_BATCH_FETCH_COUNT); 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (true) { 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index = getIndexOf(path, list); 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index != INDEX_NOT_FOUND) return start + index; 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (list.size() < MEDIAITEM_BATCH_FETCH_COUNT) return INDEX_NOT_FOUND; 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start += MEDIAITEM_BATCH_FETCH_COUNT; 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin list = getMediaItem(start, MEDIAITEM_BATCH_FETCH_COUNT); 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int getIndexOf(Path path, ArrayList<MediaItem> list) { 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = list.size(); i < n; ++i) { 143b9e41109f413768d6f8bb5ec7c14ca31fbc0c098Owen Lin // item could be null only in ClusterAlbum 144b9e41109f413768d6f8bb5ec7c14ca31fbc0c098Owen Lin MediaObject item = list.get(i); 145b9e41109f413768d6f8bb5ec7c14ca31fbc0c098Owen Lin if (item != null && item.mPath == path) return i; 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return INDEX_NOT_FOUND; 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public abstract String getName(); 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private WeakHashMap<ContentListener, Object> mListeners = 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new WeakHashMap<ContentListener, Object>(); 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // NOTE: The MediaSet only keeps a weak reference to the listener. The 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // listener is automatically removed when there is no other reference to 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // the listener. 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void addContentListener(ContentListener listener) { 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mListeners.containsKey(listener)) { 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(); 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListeners.put(listener, null); 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void removeContentListener(ContentListener listener) { 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mListeners.containsKey(listener)) { 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(); 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListeners.remove(listener); 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // This should be called by subclasses when the content is changed. 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void notifyContentChanged() { 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (ContentListener listener : mListeners.keySet()) { 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin listener.onContentDirty(); 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Reload the content. Return the current data version. reload() should be called 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // in the same thread as getMediaItem(int, int) and getSubMediaSet(int). 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public abstract long reload(); 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaDetails getDetails() { 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaDetails details = super.getDetails(); 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin details.addDetail(MediaDetails.INDEX_TITLE, getName()); 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return details; 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Enumerate all media items in this media set (including the ones in sub 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // media sets), in an efficient order. ItemConsumer.consumer() will be 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // called for each media item with its index. 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void enumerateMediaItems(ItemConsumer consumer) { 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin enumerateMediaItems(consumer, 0); 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void enumerateTotalMediaItems(ItemConsumer consumer) { 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin enumerateTotalMediaItems(consumer, 0); 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static interface ItemConsumer { 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin void consume(int index, MediaItem item); 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The default implementation uses getMediaItem() for enumerateMediaItems(). 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Subclasses may override this and use more efficient implementations. 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Returns the number of items enumerated. 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int enumerateMediaItems(ItemConsumer consumer, int startIndex) { 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int total = getMediaItemCount(); 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = 0; 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (start < total) { 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int count = Math.min(MEDIAITEM_BATCH_FETCH_COUNT, total - start); 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<MediaItem> items = getMediaItem(start, count); 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = items.size(); i < n; i++) { 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaItem item = items.get(i); 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin consumer.consume(startIndex + start + i, item); 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start += count; 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return total; 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Recursively enumerate all media items under this set. 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Returns the number of items enumerated. 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int enumerateTotalMediaItems( 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ItemConsumer consumer, int startIndex) { 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = 0; 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start += enumerateMediaItems(consumer, startIndex); 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int m = getSubMediaSetCount(); 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < m; i++) { 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start += getSubMediaSet(i).enumerateTotalMediaItems( 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin consumer, startIndex + start); 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return start; 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 23757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan /** 23857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * Requests sync on this MediaSet. It returns a Future object that can be used by the caller 23957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * to query the status of the sync. The sync result code is one of the SYNC_RESULT_* constants 24057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * defined in this class and can be obtained by Future.get(). 24157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * 24257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * Subclasses should perform sync on a different thread. 24357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * 24457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * The default implementation here returns a Future stub that does nothing and returns 24557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * SYNC_RESULT_SUCCESS by get(). 24657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan */ 24757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public Future<Integer> requestSync(SyncListener listener) { 248fe49be45412f8d0f68343662318e73822da486c8Owen Lin listener.onSyncDone(this, SYNC_RESULT_SUCCESS); 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return FUTURE_STUB; 250f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 251f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 25257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private static final Future<Integer> FUTURE_STUB = new Future<Integer>() { 253f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void cancel() {} 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isCancelled() { 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isDone() { 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 26757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public Integer get() { 26857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan return SYNC_RESULT_SUCCESS; 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 270f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void waitDone() {} 273f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 27457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 275fe49be45412f8d0f68343662318e73822da486c8Owen Lin protected Future<Integer> requestSyncOnMultipleSets(MediaSet[] sets, SyncListener listener) { 276fe49be45412f8d0f68343662318e73822da486c8Owen Lin return new MultiSetSyncFuture(sets, listener); 27757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 27857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 27957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private class MultiSetSyncFuture implements Future<Integer>, SyncListener { 2807817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @SuppressWarnings("hiding") 28157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private static final String TAG = "Gallery.MultiSetSync"; 28257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 28357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private final SyncListener mListener; 284fe49be45412f8d0f68343662318e73822da486c8Owen Lin private final Future<Integer> mFutures[]; 28557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 28657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private boolean mIsCancelled = false; 28757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private int mResult = -1; 288fe49be45412f8d0f68343662318e73822da486c8Owen Lin private int mPendingCount; 28957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 290fe49be45412f8d0f68343662318e73822da486c8Owen Lin @SuppressWarnings("unchecked") 291fe49be45412f8d0f68343662318e73822da486c8Owen Lin MultiSetSyncFuture(MediaSet[] sets, SyncListener listener) { 29257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan mListener = listener; 293fe49be45412f8d0f68343662318e73822da486c8Owen Lin mPendingCount = sets.length; 294fe49be45412f8d0f68343662318e73822da486c8Owen Lin mFutures = new Future[sets.length]; 29557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 296fe49be45412f8d0f68343662318e73822da486c8Owen Lin synchronized (this) { 297fe49be45412f8d0f68343662318e73822da486c8Owen Lin for (int i = 0, n = sets.length; i < n; ++i) { 298fe49be45412f8d0f68343662318e73822da486c8Owen Lin mFutures[i] = sets[i].requestSync(this); 299fe49be45412f8d0f68343662318e73822da486c8Owen Lin Log.d(TAG, " request sync: " + Utils.maskDebugInfo(sets[i].getName())); 30057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 30157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 30257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 30357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 30457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 30557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized void cancel() { 30657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (mIsCancelled) return; 30757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan mIsCancelled = true; 308fe49be45412f8d0f68343662318e73822da486c8Owen Lin for (Future<Integer> future : mFutures) future.cancel(); 30957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (mResult < 0) mResult = SYNC_RESULT_CANCELLED; 31057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 31157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 31257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 31357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized boolean isCancelled() { 31457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan return mIsCancelled; 31557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 31657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 31757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 31857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized boolean isDone() { 319fe49be45412f8d0f68343662318e73822da486c8Owen Lin return mPendingCount == 0; 32057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 32157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 32257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 32357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized Integer get() { 32457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan waitDone(); 32557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan return mResult; 32657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 32757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 32857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 32957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized void waitDone() { 33057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan try { 33157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan while (!isDone()) wait(); 33257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } catch (InterruptedException e) { 33357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan Log.d(TAG, "waitDone() interrupted"); 33457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 33557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 33657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 33757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan // SyncListener callback 33857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 33957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public void onSyncDone(MediaSet mediaSet, int resultCode) { 34057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan SyncListener listener = null; 34157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan synchronized (this) { 342fe49be45412f8d0f68343662318e73822da486c8Owen Lin if (resultCode == SYNC_RESULT_ERROR) mResult = SYNC_RESULT_ERROR; 343fe49be45412f8d0f68343662318e73822da486c8Owen Lin --mPendingCount; 344fe49be45412f8d0f68343662318e73822da486c8Owen Lin if (mPendingCount == 0) { 345fe49be45412f8d0f68343662318e73822da486c8Owen Lin listener = mListener; 346fe49be45412f8d0f68343662318e73822da486c8Owen Lin notifyAll(); 34757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 348fe49be45412f8d0f68343662318e73822da486c8Owen Lin Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) 349fe49be45412f8d0f68343662318e73822da486c8Owen Lin + " #pending=" + mPendingCount); 35057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 35157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (listener != null) listener.onSyncDone(MediaSet.this, mResult); 35257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 35357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 354f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 355