1 /* 2 * Copyright (C) 2009 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.cooliris.media; 18 19 import java.util.ArrayList; 20 import java.util.HashMap; 21 22 public final class MediaBucketList { 23 private static final Boolean TRUE = new Boolean(true); 24 private static final Boolean FALSE = new Boolean(false); 25 26 private ArrayList<MediaBucket> mBuckets = new ArrayList<MediaBucket>(1024); 27 private boolean mDirtyCount; 28 private boolean mDirtyAcceleratedLookup; 29 private int mCount; 30 private HashMap<MediaItem, Boolean> mCachedItems = new HashMap<MediaItem, Boolean>(1024); 31 32 // If only albums are selected, a bucket contains mediaSets. 33 // If items are selected, a bucket contains mediaSets and mediaItems. 34 35 // Returns the first item selection (ignoring items within set selections). 36 public static MediaItem getFirstItemSelection(ArrayList<MediaBucket> buckets) { 37 MediaItem item = null; 38 if (buckets != null) { 39 int numBuckets = buckets.size(); 40 for (int i = 0; i < numBuckets; i++) { 41 MediaBucket bucket = buckets.get(0); 42 if (bucket != null && !isSetSelection(bucket)) { 43 ArrayList<MediaItem> items = bucket.mediaItems; 44 if (items != null && items.size() > 0) { 45 item = items.get(0); 46 break; 47 } 48 } 49 } 50 } 51 return item; 52 } 53 54 // Returns the first set selection (ignoring sets corresponding to item 55 // selections). 56 public static MediaSet getFirstSetSelection(ArrayList<MediaBucket> buckets) { 57 MediaSet set = null; 58 if (buckets != null) { 59 int numBuckets = buckets.size(); 60 for (int i = 0; i < numBuckets; i++) { 61 MediaBucket bucket = buckets.get(0); 62 if (bucket != null && isSetSelection(bucket)) { 63 set = bucket.mediaSet; 64 } 65 } 66 } 67 return set; 68 } 69 70 public ArrayList<MediaBucket> get() { 71 return mBuckets; 72 } 73 74 public int size() { 75 if (mDirtyCount) { 76 ArrayList<MediaBucket> buckets = mBuckets; 77 int numBuckets = buckets.size(); 78 int count = 0; 79 for (int i = 0; i < numBuckets; ++i) { 80 MediaBucket bucket = buckets.get(i); 81 int numItems = 0; 82 if (bucket.mediaItems == null && bucket.mediaSet != null) { 83 numItems = bucket.mediaSet.getNumItems(); 84 // This selection reflects the bucket itself, and not the 85 // items inside the bucket (which is 0). 86 if (numItems == 0) { 87 numItems = 1; 88 } 89 } else if (bucket.mediaItems != null && bucket.mediaItems != null) { 90 numItems = bucket.mediaItems.size(); 91 } 92 count += numItems; 93 } 94 mCount = count; 95 mDirtyCount = false; 96 } 97 return mCount; 98 } 99 100 public void add(int slotId, MediaFeed feed, boolean removeIfAlreadyAdded) { 101 if (slotId == Shared.INVALID) { 102 return; 103 } 104 setDirty(); 105 final ArrayList<MediaBucket> selectedBuckets = mBuckets; 106 final int numSelectedBuckets = selectedBuckets.size(); 107 MediaSet mediaSetToAdd = null; 108 ArrayList<MediaItem> selectedItems = null; 109 MediaBucket bucket = null; 110 final boolean hasExpandedMediaSet = feed.hasExpandedMediaSet(); 111 if (!hasExpandedMediaSet) { 112 ArrayList<MediaSet> mediaSets = feed.getMediaSets(); 113 if (slotId >= mediaSets.size()) { 114 return; 115 } 116 mediaSetToAdd = mediaSets.get(slotId); 117 } else { 118 int numSlots = feed.getNumSlots(); 119 if (slotId < numSlots) { 120 MediaSet set = feed.getSetForSlot(slotId); 121 if (set != null) { 122 ArrayList<MediaItem> items = set.getItems(); 123 if (set.getNumItems() > 0) { 124 mediaSetToAdd = items.get(0).mParentMediaSet; 125 } 126 } 127 } 128 } 129 130 // Search for the bucket for this media set 131 for (int i = 0; i < numSelectedBuckets; ++i) { 132 final MediaBucket bucketCompare = selectedBuckets.get(i); 133 if (bucketCompare.mediaSet != null && mediaSetToAdd != null && bucketCompare.mediaSet.mId == mediaSetToAdd.mId) { 134 // We found the MediaSet. 135 if (!hasExpandedMediaSet) { 136 // Remove this bucket from the list since this bucket was 137 // already selected. 138 if (removeIfAlreadyAdded) { 139 selectedBuckets.remove(bucketCompare); 140 } 141 return; 142 } else { 143 bucket = bucketCompare; 144 break; 145 } 146 } 147 } 148 if (bucket == null) { 149 // Did not find the media bucket. 150 bucket = new MediaBucket(); 151 bucket.mediaSet = mediaSetToAdd; 152 bucket.mediaItems = selectedItems; 153 selectedBuckets.add(bucket); 154 } 155 if (hasExpandedMediaSet) { 156 int numSlots = feed.getNumSlots(); 157 if (slotId < numSlots) { 158 MediaSet set = feed.getSetForSlot(slotId); 159 if (set != null) { 160 ArrayList<MediaItem> items = set.getItems(); 161 int numItems = set.getNumItems(); 162 selectedItems = bucket.mediaItems; 163 if (selectedItems == null) { 164 selectedItems = new ArrayList<MediaItem>(numItems); 165 bucket.mediaItems = selectedItems; 166 } 167 for (int i = 0; i < numItems; ++i) { 168 MediaItem item = items.get(i); 169 // We see if this item has already been added. 170 int numPresentItems = selectedItems.size(); 171 boolean foundIndex = false; 172 for (int j = 0; j < numPresentItems; ++j) { 173 final MediaItem selectedItem = selectedItems.get(j); 174 if (selectedItem != null && item != null && selectedItem.mId == item.mId) { 175 // This index was already present, we need to 176 // remove it. 177 foundIndex = true; 178 if (removeIfAlreadyAdded) { 179 selectedItems.remove(j); 180 } 181 break; 182 } 183 } 184 if (foundIndex == false) { 185 selectedItems.add(item); 186 } 187 } 188 } 189 } 190 } 191 setDirty(); 192 } 193 194 public boolean find(MediaItem item) { 195 HashMap<MediaItem, Boolean> cachedItems = mCachedItems; 196 if (mDirtyAcceleratedLookup) { 197 cachedItems.clear(); 198 mDirtyAcceleratedLookup = false; 199 } 200 Boolean itemAdded = cachedItems.get(item); 201 if (itemAdded == null) { 202 ArrayList<MediaBucket> selectedBuckets = mBuckets; 203 int numSelectedBuckets = selectedBuckets.size(); 204 for (int i = 0; i < numSelectedBuckets; ++i) { 205 MediaBucket bucket = selectedBuckets.get(i); 206 ArrayList<MediaItem> mediaItems = bucket.mediaItems; 207 if (mediaItems == null) { 208 MediaSet parentMediaSet = item.mParentMediaSet; 209 if (parentMediaSet != null && parentMediaSet.equals(bucket.mediaSet)) { 210 cachedItems.put(item, TRUE); 211 return true; 212 } 213 } else { 214 int numMediaItems = mediaItems.size(); 215 for (int j = 0; j < numMediaItems; ++j) { 216 MediaItem itemCompare = mediaItems.get(j); 217 if (itemCompare == item) { 218 cachedItems.put(item, TRUE); 219 return true; 220 } 221 } 222 } 223 } 224 cachedItems.put(item, FALSE); 225 return false; 226 } else { 227 return itemAdded.booleanValue(); 228 } 229 } 230 231 public void clear() { 232 mBuckets.clear(); 233 setDirty(); 234 } 235 236 private void setDirty() { 237 mDirtyCount = true; 238 mDirtyAcceleratedLookup = true; 239 } 240 241 // Assumption: No item and set selection combinations. 242 protected static boolean isSetSelection(ArrayList<MediaBucket> buckets) { 243 if (buckets != null) { 244 int numBuckets = buckets.size(); 245 if (numBuckets == 0) { 246 return false; 247 } else if (numBuckets == 1) { 248 return isSetSelection(buckets.get(0)); 249 } else { 250 // If there are multiple sets, must be a set selection. 251 return true; 252 } 253 } 254 return false; 255 } 256 257 protected static boolean isSetSelection(MediaBucket bucket) { 258 return (bucket.mediaSet != null && bucket.mediaItems == null) ? true : false; 259 } 260 261 // Assumption: If multiple items are selected, they must all be in the first 262 // bucket. 263 protected static boolean isMultipleItemSelection(ArrayList<MediaBucket> buckets) { 264 if (buckets != null) { 265 int numBuckets = buckets.size(); 266 if (numBuckets == 0) { 267 return false; 268 } else { 269 return isMultipleSetSelection(buckets.get(0)); 270 } 271 } 272 return false; 273 } 274 275 protected static boolean isMultipleSetSelection(MediaBucket bucket) { 276 return (bucket.mediaItems != null && bucket.mediaItems.size() > 1) ? true : false; 277 } 278 } 279