MediaSet.java revision 57cbaa1ef40d2215c6400f5ae4af3a09e67abb2d
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; 2357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyanimport java.util.HashMap; 24f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.WeakHashMap; 25f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// MediaSet is a directory-like data structure. 27f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// It contains MediaItems and sub-MediaSets. 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// The primary interface are: 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getMediaItemCount(), getMediaItem() and 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getSubMediaSetCount(), getSubMediaSet(). 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// getTotalMediaItemCount() returns the number of all MediaItems, including 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// those in sub-MediaSets. 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linpublic abstract class MediaSet extends MediaObject { 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int MEDIAITEM_BATCH_FETCH_COUNT = 500; 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INDEX_NOT_FOUND = -1; 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 3957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public static final int SYNC_RESULT_SUCCESS = 0; 4057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public static final int SYNC_RESULT_CANCELLED = 1; 4157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public static final int SYNC_RESULT_ERROR = 2; 4257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 4357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan /** Listener to be used with requestSync(SyncListener). */ 4457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public static interface SyncListener { 4557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan /** 4657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * Called when the sync task completed. Completion may be due to normal termination, 4757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * an exception, or cancellation. 4857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * 4957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * @param mediaSet the MediaSet that's done with sync 5057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * @param resultCode one of the SYNC_RESULT_* constants 5157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan */ 5257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan void onSyncDone(MediaSet mediaSet, int resultCode); 5357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 5457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet(Path path, long version) { 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super(path, version); 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getMediaItemCount() { 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return 0; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Returns the media items in the range [start, start + count). 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The number of media items returned may be less than the specified count 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // if there are not enough media items available. The number of 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // media items available may not be consistent with the return value of 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // getMediaItemCount() because the contents of database may have already 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // changed. 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public ArrayList<MediaItem> getMediaItem(int start, int count) { 71f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return new ArrayList<MediaItem>(); 72f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 73f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 74f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getSubMediaSetCount() { 75f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return 0; 76f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 77f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 78f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet getSubMediaSet(int index) { 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IndexOutOfBoundsException(); 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 81f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 82f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isLeafAlbum() { 83f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 84f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 85f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 86f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getTotalMediaItemCount() { 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int total = getMediaItemCount(); 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = getSubMediaSetCount(); i < n; i++) { 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin total += getSubMediaSet(i).getTotalMediaItemCount(); 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return total; 92f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // TODO: we should have better implementation of sub classes 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getIndexOfItem(Path path, int hint) { 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // hint < 0 is handled below 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // first, try to find it around the hint 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = Math.max(0, 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin hint - MEDIAITEM_BATCH_FETCH_COUNT / 2); 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<MediaItem> list = getMediaItem( 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start, MEDIAITEM_BATCH_FETCH_COUNT); 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int index = getIndexOf(path, list); 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index != INDEX_NOT_FOUND) return start + index; 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // try to find it globally 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start = start == 0 ? MEDIAITEM_BATCH_FETCH_COUNT : 0; 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin list = getMediaItem(start, MEDIAITEM_BATCH_FETCH_COUNT); 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (true) { 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin index = getIndexOf(path, list); 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (index != INDEX_NOT_FOUND) return start + index; 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (list.size() < MEDIAITEM_BATCH_FETCH_COUNT) return INDEX_NOT_FOUND; 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start += MEDIAITEM_BATCH_FETCH_COUNT; 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin list = getMediaItem(start, MEDIAITEM_BATCH_FETCH_COUNT); 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int getIndexOf(Path path, ArrayList<MediaItem> list) { 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = list.size(); i < n; ++i) { 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (list.get(i).mPath == path) return i; 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 121f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return INDEX_NOT_FOUND; 122f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 123f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public abstract String getName(); 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private WeakHashMap<ContentListener, Object> mListeners = 127f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new WeakHashMap<ContentListener, Object>(); 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 129f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // NOTE: The MediaSet only keeps a weak reference to the listener. The 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // listener is automatically removed when there is no other reference to 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // the listener. 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void addContentListener(ContentListener listener) { 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mListeners.containsKey(listener)) { 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(); 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListeners.put(listener, null); 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void removeContentListener(ContentListener listener) { 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mListeners.containsKey(listener)) { 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin throw new IllegalArgumentException(); 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mListeners.remove(listener); 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // This should be called by subclasses when the content is changed. 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void notifyContentChanged() { 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (ContentListener listener : mListeners.keySet()) { 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin listener.onContentDirty(); 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 153f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Reload the content. Return the current data version. reload() should be called 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // in the same thread as getMediaItem(int, int) and getSubMediaSet(int). 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public abstract long reload(); 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 157f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 158f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaDetails getDetails() { 159f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaDetails details = super.getDetails(); 160f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin details.addDetail(MediaDetails.INDEX_TITLE, getName()); 161f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return details; 162f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 163f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Enumerate all media items in this media set (including the ones in sub 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // media sets), in an efficient order. ItemConsumer.consumer() will be 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // called for each media item with its index. 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void enumerateMediaItems(ItemConsumer consumer) { 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin enumerateMediaItems(consumer, 0); 169f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 170f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 171f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void enumerateTotalMediaItems(ItemConsumer consumer) { 172f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin enumerateTotalMediaItems(consumer, 0); 173f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 174f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 175f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static interface ItemConsumer { 176f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin void consume(int index, MediaItem item); 177f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 179f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The default implementation uses getMediaItem() for enumerateMediaItems(). 180f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Subclasses may override this and use more efficient implementations. 181f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Returns the number of items enumerated. 182f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int enumerateMediaItems(ItemConsumer consumer, int startIndex) { 183f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int total = getMediaItemCount(); 184f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = 0; 185f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin while (start < total) { 186f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int count = Math.min(MEDIAITEM_BATCH_FETCH_COUNT, total - start); 187f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<MediaItem> items = getMediaItem(start, count); 188f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0, n = items.size(); i < n; i++) { 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaItem item = items.get(i); 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin consumer.consume(startIndex + start + i, item); 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start += count; 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return total; 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Recursively enumerate all media items under this set. 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Returns the number of items enumerated. 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin protected int enumerateTotalMediaItems( 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ItemConsumer consumer, int startIndex) { 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int start = 0; 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start += enumerateMediaItems(consumer, startIndex); 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int m = getSubMediaSetCount(); 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < m; i++) { 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin start += getSubMediaSet(i).enumerateTotalMediaItems( 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin consumer, startIndex + start); 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return start; 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 21157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan /** 21257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * Requests sync on this MediaSet. It returns a Future object that can be used by the caller 21357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * to query the status of the sync. The sync result code is one of the SYNC_RESULT_* constants 21457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * defined in this class and can be obtained by Future.get(). 21557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * 21657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * Subclasses should perform sync on a different thread. 21757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * 21857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * The default implementation here returns a Future stub that does nothing and returns 21957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan * SYNC_RESULT_SUCCESS by get(). 22057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan */ 22157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public Future<Integer> requestSync(SyncListener listener) { 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return FUTURE_STUB; 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 22557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private static final Future<Integer> FUTURE_STUB = new Future<Integer>() { 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void cancel() {} 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isCancelled() { 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return false; 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public boolean isDone() { 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return true; 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 24057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public Integer get() { 24157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan return SYNC_RESULT_SUCCESS; 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void waitDone() {} 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin }; 24757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 24857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan protected Future<Integer> requestSyncOnEmptySets(MediaSet[] sets, SyncListener listener) { 24957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan MultiSetSyncFuture future = new MultiSetSyncFuture(listener); 25057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan future.requestSyncOnEmptySets(sets); 25157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan return future; 25257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 25357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 25457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private class MultiSetSyncFuture implements Future<Integer>, SyncListener { 25557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private static final String TAG = "Gallery.MultiSetSync"; 25657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 25757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private final HashMap<MediaSet, Future<Integer>> mMediaSetMap = 25857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan new HashMap<MediaSet, Future<Integer>>(); 25957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private final SyncListener mListener; 26057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 26157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private boolean mIsCancelled = false; 26257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan private int mResult = -1; 26357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 26457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan MultiSetSyncFuture(SyncListener listener) { 26557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan mListener = listener; 26657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 26757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 26857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan synchronized void requestSyncOnEmptySets(MediaSet[] sets) { 26957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan for (MediaSet set : sets) { 27057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if ((set.getMediaItemCount() == 0) && !mMediaSetMap.containsKey(set)) { 27157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan // Sync results are handled in this.onSyncDone(). 27257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan Future<Integer> future = set.requestSync(this); 27357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (!future.isDone()) { 27457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan mMediaSetMap.put(set, future); 27557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan Log.d(TAG, " request sync: " + Utils.maskDebugInfo(set.getName())); 27657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 27757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 27857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 27957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan Log.d(TAG, "requestSyncOnEmptySets actual=" + mMediaSetMap.size()); 28057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 28157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 28257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 28357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized void cancel() { 28457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (mIsCancelled) return; 28557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan mIsCancelled = true; 28657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan for (Future<Integer> future : mMediaSetMap.values()) future.cancel(); 28757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan mMediaSetMap.clear(); 28857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (mResult < 0) mResult = SYNC_RESULT_CANCELLED; 28957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 29057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 29157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 29257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized boolean isCancelled() { 29357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan return mIsCancelled; 29457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 29557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 29657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 29757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized boolean isDone() { 29857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan return mMediaSetMap.isEmpty(); 29957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 30057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 30157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 30257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized Integer get() { 30357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan waitDone(); 30457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan return mResult; 30557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 30657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 30757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 30857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public synchronized void waitDone() { 30957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan try { 31057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan while (!isDone()) wait(); 31157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } catch (InterruptedException e) { 31257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan Log.d(TAG, "waitDone() interrupted"); 31357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 31457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 31557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan 31657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan // SyncListener callback 31757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan @Override 31857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan public void onSyncDone(MediaSet mediaSet, int resultCode) { 31957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan SyncListener listener = null; 32057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan synchronized (this) { 32157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (mMediaSetMap.remove(mediaSet) != null) { 32257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) 32357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan + " #pending=" + mMediaSetMap.size()); 32457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (resultCode == SYNC_RESULT_ERROR) { 32557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan mResult = SYNC_RESULT_ERROR; 32657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 32757cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (mMediaSetMap.isEmpty()) { 32857cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (mResult < 0) mResult = SYNC_RESULT_SUCCESS; 32957cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan notifyAll(); 33057cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan listener = mListener; 33157cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 33257cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 33357cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 33457cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan if (listener != null) listener.onSyncDone(MediaSet.this, mResult); 33557cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 33657cbaa1ef40d2215c6400f5ae4af3a09e67abb2dHung-ying Tyan } 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 338