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 192b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport android.database.ContentObserver; 202b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport android.net.Uri; 212b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport android.os.Handler; 222b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin 23f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.app.GalleryApp; 244b4dbd225685502f4249c2bf25bf74f7ce526645George Mountimport com.android.gallery3d.app.StitchingChangeListener; 2504ebde7418493debda790f3eae933b5f6c38e897Chih-Chung Changimport com.android.gallery3d.common.ApiHelper; 26f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.common.Utils; 274b4dbd225685502f4249c2bf25bf74f7ce526645George Mountimport com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; 28f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaSet.ItemConsumer; 29f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.data.MediaSource.PathId; 30f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport com.android.gallery3d.picasasource.PicasaSource; 31f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 32f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.ArrayList; 33f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.Comparator; 34f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.HashMap; 35f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.LinkedHashMap; 36f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.Map.Entry; 37f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Linimport java.util.WeakHashMap; 38f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 39f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// DataManager manages all media sets and media items in the system. 40f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 41f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// Each MediaSet and MediaItem has a unique 64 bits id. The most significant 42f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 32 bits represents its parent, and the least significant 32 bits represents 43f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// the self id. For MediaSet the self id is is globally unique, but for 44f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// MediaItem it's unique only relative to its parent. 45f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// 46f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// To make sure the id is the same when the MediaSet is re-created, a child key 47f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// is provided to obtainSetId() to make sure the same self id will be used as 48f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// when the parent and key are the same. A sequence of child keys is called a 49f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// path. And it's used to identify a specific media set even if the process is 50f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin// killed and re-created, so child keys should be stable identifiers. 51f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 524b4dbd225685502f4249c2bf25bf74f7ce526645George Mountpublic class DataManager implements StitchingChangeListener { 53f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INCLUDE_IMAGE = 1; 54f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INCLUDE_VIDEO = 2; 55f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INCLUDE_ALL = INCLUDE_IMAGE | INCLUDE_VIDEO; 56f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INCLUDE_LOCAL_ONLY = 4; 57f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INCLUDE_LOCAL_IMAGE_ONLY = 58f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin INCLUDE_LOCAL_ONLY | INCLUDE_IMAGE; 59f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INCLUDE_LOCAL_VIDEO_ONLY = 60f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin INCLUDE_LOCAL_ONLY | INCLUDE_VIDEO; 61f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final int INCLUDE_LOCAL_ALL_ONLY = 62f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin INCLUDE_LOCAL_ONLY | INCLUDE_IMAGE | INCLUDE_VIDEO; 63f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 64f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Any one who would like to access data should require this lock 65f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // to prevent concurrency issue. 66f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final Object LOCK = new Object(); 67f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 68f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TAG = "DataManager"; 69f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 70f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // This is the path for the media set seen by the user at top level. 71b200e27b998df8856bc060a9f418e662864458b2Owen Lin private static final String TOP_SET_PATH = ApiHelper.HAS_MTP 72b200e27b998df8856bc060a9f418e662864458b2Owen Lin ? "/combo/{/mtp,/local/all,/picasa/all}" 73b200e27b998df8856bc060a9f418e662864458b2Owen Lin : "/combo/{/local/all,/picasa/all}"; 74b200e27b998df8856bc060a9f418e662864458b2Owen Lin 75b200e27b998df8856bc060a9f418e662864458b2Owen Lin private static final String TOP_IMAGE_SET_PATH = ApiHelper.HAS_MTP 76b200e27b998df8856bc060a9f418e662864458b2Owen Lin ? "/combo/{/mtp,/local/image,/picasa/image}" 77b200e27b998df8856bc060a9f418e662864458b2Owen Lin : "/combo/{/local/image,/picasa/image}"; 78b200e27b998df8856bc060a9f418e662864458b2Owen Lin 79f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static final String TOP_VIDEO_SET_PATH = 80f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin "/combo/{/local/video,/picasa/video}"; 81b200e27b998df8856bc060a9f418e662864458b2Owen Lin 82b200e27b998df8856bc060a9f418e662864458b2Owen Lin private static final String TOP_LOCAL_SET_PATH = "/local/all"; 83b200e27b998df8856bc060a9f418e662864458b2Owen Lin 84b200e27b998df8856bc060a9f418e662864458b2Owen Lin private static final String TOP_LOCAL_IMAGE_SET_PATH = "/local/image"; 85b200e27b998df8856bc060a9f418e662864458b2Owen Lin 86b200e27b998df8856bc060a9f418e662864458b2Owen Lin private static final String TOP_LOCAL_VIDEO_SET_PATH = "/local/video"; 87f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 88f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public static final Comparator<MediaItem> sDateTakenComparator = 89f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new DateTakenComparator(); 90f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 91f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static class DateTakenComparator implements Comparator<MediaItem> { 927817979db0c52ffeacb951625b1e821eba303285Ahbong Chang @Override 93f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int compare(MediaItem item1, MediaItem item2) { 94f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return -Utils.compare(item1.getDateInMs(), item2.getDateInMs()); 95f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 96f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 97f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 98f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private final Handler mDefaultMainHandler; 99f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 100f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private GalleryApp mApplication; 101f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private int mActiveCount = 0; 102f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 103f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private HashMap<Uri, NotifyBroker> mNotifierMap = 104f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new HashMap<Uri, NotifyBroker>(); 105f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 106f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 107f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private HashMap<String, MediaSource> mSourceMap = 108f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new LinkedHashMap<String, MediaSource>(); 109f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 110f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public DataManager(GalleryApp application) { 111f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mApplication = application; 112f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mDefaultMainHandler = new Handler(application.getMainLooper()); 113f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 114f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 115f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void initializeSourceMap() { 116f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (!mSourceMap.isEmpty()) return; 117f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 118f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // the order matters, the UriSource must come last 119f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addSource(new LocalSource(mApplication)); 120f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addSource(new PicasaSource(mApplication)); 12104ebde7418493debda790f3eae933b5f6c38e897Chih-Chung Chang if (ApiHelper.HAS_MTP) { 12204ebde7418493debda790f3eae933b5f6c38e897Chih-Chung Chang addSource(new MtpSource(mApplication)); 12304ebde7418493debda790f3eae933b5f6c38e897Chih-Chung Chang } 124f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addSource(new ComboSource(mApplication)); 125f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addSource(new ClusterSource(mApplication)); 126f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addSource(new FilterSource(mApplication)); 127a0ce682e40c39ce046c48d8a7f989fff01bb9f2cWu-cheng Li addSource(new SecureSource(mApplication)); 128f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin addSource(new UriSource(mApplication)); 12915b351a22d02e89d882fc9fe32b3f4c512080e0aChih-Chung Chang addSource(new SnailSource(mApplication)); 130f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 131f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (mActiveCount > 0) { 132f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (MediaSource source : mSourceMap.values()) { 133f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin source.resume(); 134f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 135f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 136f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 137f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 138f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public String getTopSetPath(int typeBits) { 139f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 140f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin switch (typeBits) { 141f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case INCLUDE_IMAGE: return TOP_IMAGE_SET_PATH; 142f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case INCLUDE_VIDEO: return TOP_VIDEO_SET_PATH; 143f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case INCLUDE_ALL: return TOP_SET_PATH; 144f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case INCLUDE_LOCAL_IMAGE_ONLY: return TOP_LOCAL_IMAGE_SET_PATH; 145f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case INCLUDE_LOCAL_VIDEO_ONLY: return TOP_LOCAL_VIDEO_SET_PATH; 146f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin case INCLUDE_LOCAL_ALL_ONLY: return TOP_LOCAL_SET_PATH; 147f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin default: throw new IllegalArgumentException(); 148f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 149f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 150f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 151f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // open for debug 152f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin void addSource(MediaSource source) { 153c64d127c976f8ef647552063ff14ead4388ce699Angus Kong if (source == null) return; 154f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mSourceMap.put(source.getPrefix(), source); 155f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 156f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 157676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // A common usage of this method is: 158676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // synchronized (DataManager.LOCK) { 159676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // MediaObject object = peekMediaObject(path); 160676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // if (object == null) { 161676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // object = createMediaObject(...); 162676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // } 163676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin // } 164f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaObject peekMediaObject(Path path) { 165f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return path.getObject(); 166f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 167f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 168f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaObject getMediaObject(Path path) { 169676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin synchronized (LOCK) { 170676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin MediaObject obj = path.getObject(); 171676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (obj != null) return obj; 172676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin 173676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin MediaSource source = mSourceMap.get(path.getPrefix()); 174676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (source == null) { 175676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin Log.w(TAG, "cannot find media source for path: " + path); 176676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin return null; 177676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin } 178f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 179676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin try { 180676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin MediaObject object = source.createMediaObject(path); 181676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin if (object == null) { 182676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin Log.w(TAG, "cannot create media object: " + path); 183676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin } 184676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin return object; 185676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin } catch (Throwable t) { 186676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin Log.w(TAG, "exception in creating media object: " + path, t); 187676d4762496eddae66930c6f8b0bae22a22b3ef6Owen Lin return null; 188f31954e5b5f227b07fe377545fb05327d7e7ffe6Pin Ting } 189f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 190f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 191f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 192f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaObject getMediaObject(String s) { 193f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return getMediaObject(Path.fromString(s)); 194f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 195f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 196f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet getMediaSet(Path path) { 197f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return (MediaSet) getMediaObject(path); 198f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 199f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 200f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet getMediaSet(String s) { 201f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return (MediaSet) getMediaObject(s); 202f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 203f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 204f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public MediaSet[] getMediaSetsFromString(String segment) { 205f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String[] seq = Path.splitSequence(segment); 206f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int n = seq.length; 207f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaSet[] sets = new MediaSet[n]; 208f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < n; i++) { 209f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sets[i] = getMediaSet(seq[i]); 210f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 211f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return sets; 212f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 213f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 214f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Maps a list of Paths to MediaItems, and invoke consumer.consume() 215f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // for each MediaItem (may not be in the same order as the input list). 216f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // An index number is also passed to consumer.consume() to identify 217f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // the original position in the input list of the corresponding Path (plus 218f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // startIndex). 219f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void mapMediaItems(ArrayList<Path> list, ItemConsumer consumer, 220f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int startIndex) { 221f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin HashMap<String, ArrayList<PathId>> map = 222f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new HashMap<String, ArrayList<PathId>>(); 223f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 224f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Group the path by the prefix. 225f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin int n = list.size(); 226f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (int i = 0; i < n; i++) { 227f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin Path path = list.get(i); 228f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String prefix = path.getPrefix(); 229f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin ArrayList<PathId> group = map.get(prefix); 230f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (group == null) { 231f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin group = new ArrayList<PathId>(); 232f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin map.put(prefix, group); 233f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 234f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin group.add(new PathId(path, i + startIndex)); 235f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 236f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 237f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // For each group, ask the corresponding media source to map it. 238f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (Entry<String, ArrayList<PathId>> entry : map.entrySet()) { 239f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin String prefix = entry.getKey(); 240f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaSource source = mSourceMap.get(prefix); 241f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin source.mapMediaItems(entry.getValue(), consumer); 242f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 243f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 244f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 245f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // The following methods forward the request to the proper object. 246f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getSupportedOperations(Path path) { 247f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return getMediaObject(path).getSupportedOperations(); 248f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 249f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 2504b4dbd225685502f4249c2bf25bf74f7ce526645George Mount public void getPanoramaSupport(Path path, PanoramaSupportCallback callback) { 2514b4dbd225685502f4249c2bf25bf74f7ce526645George Mount getMediaObject(path).getPanoramaSupport(callback); 252825afb1b3e7d15b5c258d664ee008dc68da1c407Mangesh Ghiware } 253825afb1b3e7d15b5c258d664ee008dc68da1c407Mangesh Ghiware 254f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void delete(Path path) { 255f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin getMediaObject(path).delete(); 256f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 257f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 258f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void rotate(Path path, int degrees) { 259f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin getMediaObject(path).rotate(degrees); 260f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 261f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 262f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Uri getContentUri(Path path) { 263f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return getMediaObject(path).getContentUri(); 264f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 265f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 266f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public int getMediaType(Path path) { 267f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return getMediaObject(path).getMediaType(); 268f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 269f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 27021a412c93c9b0401b039f4eb86d4950752e5bb84Owen Lin public Path findPathByUri(Uri uri, String type) { 271f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (uri == null) return null; 272f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (MediaSource source : mSourceMap.values()) { 27321a412c93c9b0401b039f4eb86d4950752e5bb84Owen Lin Path path = source.findPathByUri(uri, type); 274f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (path != null) return path; 275f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 276f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return null; 277f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 278f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 279f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public Path getDefaultSetOf(Path item) { 280f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin MediaSource source = mSourceMap.get(item.getPrefix()); 281f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return source == null ? null : source.getDefaultSetOf(item); 282f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 283f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 284f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Returns number of bytes used by cached pictures currently downloaded. 285f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public long getTotalUsedCacheSize() { 286f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long sum = 0; 287f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (MediaSource source : mSourceMap.values()) { 288f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sum += source.getTotalUsedCacheSize(); 289f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 290f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return sum; 291f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 292f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 293f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // Returns number of bytes used by cached pictures if all pending 294f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin // downloads and removals are completed. 295f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public long getTotalTargetCacheSize() { 296f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin long sum = 0; 297f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (MediaSource source : mSourceMap.values()) { 298f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin sum += source.getTotalTargetCacheSize(); 299f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 300f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin return sum; 301f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 302f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 303f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void registerChangeNotifier(Uri uri, ChangeNotifier notifier) { 304f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin NotifyBroker broker = null; 305f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin synchronized (mNotifierMap) { 306f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin broker = mNotifierMap.get(uri); 307f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (broker == null) { 308f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin broker = new NotifyBroker(mDefaultMainHandler); 309f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mApplication.getContentResolver() 310f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin .registerContentObserver(uri, true, broker); 311f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNotifierMap.put(uri, broker); 312f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 313f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 314f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin broker.registerNotifier(notifier); 315f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 316f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 317f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void resume() { 318f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (++mActiveCount == 1) { 319f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (MediaSource source : mSourceMap.values()) { 320f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin source.resume(); 321f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 322f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 323f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 324f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 325f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public void pause() { 326f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin if (--mActiveCount == 0) { 327f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for (MediaSource source : mSourceMap.values()) { 328f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin source.pause(); 329f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 330f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 331f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 332f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 333f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private static class NotifyBroker extends ContentObserver { 334f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin private WeakHashMap<ChangeNotifier, Object> mNotifiers = 335f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin new WeakHashMap<ChangeNotifier, Object>(); 336f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 337f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public NotifyBroker(Handler handler) { 338f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin super(handler); 339f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 340f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 341f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void registerNotifier(ChangeNotifier notifier) { 342f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin mNotifiers.put(notifier, null); 343f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 344f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin 345f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin @Override 346f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin public synchronized void onChange(boolean selfChange) { 347f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin for(ChangeNotifier notifier : mNotifiers.keySet()) { 348f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin notifier.onChange(selfChange); 349f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 350f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 351f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin } 3524b4dbd225685502f4249c2bf25bf74f7ce526645George Mount 3534b4dbd225685502f4249c2bf25bf74f7ce526645George Mount @Override 3544b4dbd225685502f4249c2bf25bf74f7ce526645George Mount public void onStitchingQueued(Uri uri) { 3554b4dbd225685502f4249c2bf25bf74f7ce526645George Mount // Do nothing. 3564b4dbd225685502f4249c2bf25bf74f7ce526645George Mount } 3574b4dbd225685502f4249c2bf25bf74f7ce526645George Mount 3584b4dbd225685502f4249c2bf25bf74f7ce526645George Mount @Override 3594b4dbd225685502f4249c2bf25bf74f7ce526645George Mount public void onStitchingResult(Uri uri) { 3604b4dbd225685502f4249c2bf25bf74f7ce526645George Mount Path path = findPathByUri(uri, null); 3614b4dbd225685502f4249c2bf25bf74f7ce526645George Mount if (path != null) { 3624b4dbd225685502f4249c2bf25bf74f7ce526645George Mount MediaObject mediaObject = getMediaObject(path); 3634b4dbd225685502f4249c2bf25bf74f7ce526645George Mount if (mediaObject != null) { 3644b4dbd225685502f4249c2bf25bf74f7ce526645George Mount mediaObject.clearCachedPanoramaSupport(); 3654b4dbd225685502f4249c2bf25bf74f7ce526645George Mount } 3664b4dbd225685502f4249c2bf25bf74f7ce526645George Mount } 3674b4dbd225685502f4249c2bf25bf74f7ce526645George Mount } 3684b4dbd225685502f4249c2bf25bf74f7ce526645George Mount 3694b4dbd225685502f4249c2bf25bf74f7ce526645George Mount @Override 3704b4dbd225685502f4249c2bf25bf74f7ce526645George Mount public void onStitchingProgress(Uri uri, int progress) { 3714b4dbd225685502f4249c2bf25bf74f7ce526645George Mount // Do nothing. 3724b4dbd225685502f4249c2bf25bf74f7ce526645George Mount } 373f9a0a4306d589b4a4e20554fed512a603426bfa1Owen Lin} 374