|
1 /* |
|
2 * Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: Cache implementation for media items sharing the same Id space |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 |
|
20 |
|
21 #include "glxcache.h" |
|
22 |
|
23 #include <glxassert.h> |
|
24 #include <mpxmediadrmdefs.h> // for DRM attributes |
|
25 #include <mpxmediacontainerdefs.h> |
|
26 #include <mpxmediacollectiondetaildefs.h> |
|
27 #include <glxthumbnailattributeinfo.h> |
|
28 #include <glxtracer.h> |
|
29 #include <lbsposition.h> //for TCoordinate |
|
30 |
|
31 #include "glxcachemanager.h" |
|
32 #include "glxmedialist.h" |
|
33 |
|
34 // ----------------------------------------------------------------------------- |
|
35 // Constructor |
|
36 // ----------------------------------------------------------------------------- |
|
37 // |
|
38 CGlxCache::CGlxCache( const TGlxIdSpaceId& aIdSpaceId, CGlxCacheManager* aCacheManager ) |
|
39 : iIdSpaceId( aIdSpaceId ), iCacheManager(aCacheManager) |
|
40 { |
|
41 TRACER("CGlxCache::CGlxCache"); |
|
42 } |
|
43 |
|
44 // ----------------------------------------------------------------------------- |
|
45 // Destructor |
|
46 // ----------------------------------------------------------------------------- |
|
47 // |
|
48 CGlxCache::~CGlxCache() |
|
49 { |
|
50 TRACER("CGlxCache::Destructor"); |
|
51 iItemPool.ResetAndDestroy(); |
|
52 } |
|
53 |
|
54 // ----------------------------------------------------------------------------- |
|
55 // IdSpaceId |
|
56 // ----------------------------------------------------------------------------- |
|
57 // |
|
58 TGlxIdSpaceId CGlxCache::IdSpaceId() const |
|
59 { |
|
60 TRACER("CGlxCache::IdSpaceId"); |
|
61 |
|
62 return iIdSpaceId; |
|
63 } |
|
64 |
|
65 // ----------------------------------------------------------------------------- |
|
66 // return a media object or null |
|
67 // ----------------------------------------------------------------------------- |
|
68 // |
|
69 CGlxMedia* CGlxCache::Media( const TGlxMediaId& aId ) const |
|
70 { |
|
71 TRACER("CGlxCache::Media"); |
|
72 |
|
73 TInt index = iItemPool.FindInOrder(aId, (&MediaItemOrderByKey)); |
|
74 if ( KErrNotFound != index ) |
|
75 { |
|
76 return iItemPool[index]; |
|
77 } |
|
78 |
|
79 return NULL; |
|
80 } |
|
81 |
|
82 // ----------------------------------------------------------------------------- |
|
83 // FindItemForceCreateL |
|
84 // ----------------------------------------------------------------------------- |
|
85 // |
|
86 CGlxMedia* CGlxCache::FindItemForceCreateL( const TGlxMediaId& aId ) |
|
87 { |
|
88 TRACER("CGlxCache::FindItemForceCreateL"); |
|
89 |
|
90 CGlxMedia* media = Media( aId ); |
|
91 |
|
92 if ( !media ) |
|
93 { |
|
94 media = CreateItemL( aId ); |
|
95 } |
|
96 |
|
97 return media; |
|
98 } |
|
99 |
|
100 // ----------------------------------------------------------------------------- |
|
101 // CreateItemL |
|
102 // ----------------------------------------------------------------------------- |
|
103 // |
|
104 CGlxMedia* CGlxCache::CreateItemL(const TGlxMediaId& aId) |
|
105 { |
|
106 TRACER("CGlxCache::CreateItemL"); |
|
107 |
|
108 CGlxMedia* item = NULL; |
|
109 |
|
110 iItemPool.ReserveL( iItemPool.Count() + 1 ); |
|
111 item = new (ELeave) CGlxMedia(aId); |
|
112 TLinearOrder<CGlxMedia> orderer (&MediaItemOrderById); |
|
113 iItemPool.InsertInOrder(item, orderer); |
|
114 |
|
115 // Safe to fail, since if the media objects is not used by any lists, |
|
116 // garbage collection will simply delete it |
|
117 RPointerArray<CGlxMediaList>& mediaLists = CGlxMediaList::MediaListsL(); |
|
118 |
|
119 TInt count = mediaLists.Count(); |
|
120 item->ReserveUsersL(count); |
|
121 for (TInt i = 0; i < count; i++) |
|
122 { |
|
123 mediaLists[i]->OfferMedia(iIdSpaceId, item); |
|
124 } |
|
125 |
|
126 return item; |
|
127 } |
|
128 |
|
129 // ----------------------------------------------------------------------------- |
|
130 // MediaUpdatedL |
|
131 // ----------------------------------------------------------------------------- |
|
132 // |
|
133 void CGlxCache::MediaUpdatedL(const CMPXMedia& aMedia) |
|
134 { |
|
135 TRACER("CGlxCache::MediaUpdatedL"); |
|
136 |
|
137 if (aMedia.IsSupported(KMPXMediaArrayContents)) |
|
138 { |
|
139 CMPXMediaArray* mediaArray = aMedia.ValueCObjectL<CMPXMediaArray>(KMPXMediaArrayContents); |
|
140 CleanupStack::PushL(mediaArray); |
|
141 |
|
142 TInt arrayCount = mediaArray->Count(); |
|
143 GLX_DEBUG2("CGlxCache::MediaUpdatedL() arrayCount=%d", arrayCount); |
|
144 for (TInt count = 0; count < arrayCount; ++count) |
|
145 { |
|
146 UpdateMediaL(*((*mediaArray)[count])); |
|
147 } |
|
148 |
|
149 CleanupStack::PopAndDestroy(mediaArray); |
|
150 } |
|
151 else |
|
152 { |
|
153 UpdateMediaL(aMedia); |
|
154 } |
|
155 } |
|
156 |
|
157 // ----------------------------------------------------------------------------- |
|
158 // UpdateMediaL |
|
159 // ----------------------------------------------------------------------------- |
|
160 void CGlxCache::UpdateMediaL(const CMPXMedia& aMedia) |
|
161 { |
|
162 TRACER("CGlxCache::UpdateMediaL"); |
|
163 |
|
164 if ( !aMedia.IsSupported(KMPXMediaGeneralId) ) |
|
165 { |
|
166 return; |
|
167 } |
|
168 // Copy/synchronize attributes |
|
169 TGlxMediaId id ((TUint32)aMedia.ValueTObjectL<TMPXItemId>(KMPXMediaGeneralId)); |
|
170 GLX_DEBUG2("CGlxCache::UpdateMediaL() id=%d", id.Value()); |
|
171 CGlxMedia* item = Media( id ); |
|
172 |
|
173 RArray<TMPXAttribute> newAttributes; |
|
174 CleanupClosePushL(newAttributes); |
|
175 |
|
176 if ( item ) |
|
177 { |
|
178 GLX_DEBUG2("MGallery - CGlxCacheManager::HandleCollectionMediaL() existing item for item id %d", id.Value()); |
|
179 CopyNewAndModifiedL(*item, aMedia, newAttributes); |
|
180 } |
|
181 else |
|
182 { |
|
183 GLX_DEBUG2("MGallery - CGlxCacheManager::HandleCollectionMediaL() new item for item id %d", id.Value()); |
|
184 |
|
185 // This is a new item. Create a media object and offer it to all lists. |
|
186 // If the item is no longer needed by any list, then this is ok, since |
|
187 // garbage collection will delete the item |
|
188 // Add in id order. |
|
189 item = CreateItemL(id); |
|
190 |
|
191 CopyNewAndModifiedL(*item, aMedia, newAttributes); |
|
192 } |
|
193 |
|
194 // Broadcast the new attributes to all observers of the item and the cache |
|
195 if (newAttributes.Count() > 0) |
|
196 { |
|
197 TInt count = item->UserCount(); |
|
198 for (TInt i = 0; i < count; i++) |
|
199 { |
|
200 item->User( i ).HandleAttributesAvailableL( item->IndexInUser( i ), newAttributes ); |
|
201 } |
|
202 |
|
203 // Broadcast to cache observers |
|
204 // iCacheManager->BroadcastAttributesAvailableL(iIdSpaceId, id, newAttributes, item); |
|
205 } |
|
206 |
|
207 CleanupStack::PopAndDestroy(&newAttributes); |
|
208 } |
|
209 // ----------------------------------------------------------------------------- |
|
210 // Deletes the media item |
|
211 // ----------------------------------------------------------------------------- |
|
212 void CGlxCache::CleanupMedia(const TGlxMediaId& aMediaId) |
|
213 { |
|
214 TRACER("CGlxCache::CleanupMedia"); |
|
215 GLX_DEBUG2("CGlxCache::CleanupMedia - aMediaId = %d", aMediaId.Value()); |
|
216 if(iCacheManager) |
|
217 { |
|
218 iCacheManager->CleanupMedia(aMediaId); |
|
219 } |
|
220 } |
|
221 |
|
222 // ----------------------------------------------------------------------------- |
|
223 // Handles modifications of item in cache |
|
224 // ----------------------------------------------------------------------------- |
|
225 void CGlxCache::HandleItemModified(const TGlxMediaId& aId, const RArray<TMPXAttribute>& aAttributes) |
|
226 { |
|
227 TRACER("CGlxCache::HandleItemModified"); |
|
228 |
|
229 TInt index = iItemPool.FindInOrder(aId, (&MediaItemOrderByKey)); |
|
230 if (index != KErrNotFound) |
|
231 { |
|
232 iItemPool[index]->HandleModified(aAttributes); |
|
233 } |
|
234 } |
|
235 |
|
236 // ----------------------------------------------------------------------------- |
|
237 // Copies new and modified attributes from the provided media object |
|
238 // ----------------------------------------------------------------------------- |
|
239 // |
|
240 void CGlxCache::CopyNewAndModifiedL(CGlxMedia& aTarget, const CMPXMedia& aSource, |
|
241 RArray<TMPXAttribute>& aNewAttributes) |
|
242 { |
|
243 TRACER("CGlxCache::CopyNewAndModifiedL"); |
|
244 CleanupClosePushL(aNewAttributes); |
|
245 |
|
246 /// @todo This is all temporary until global chunk based CMPXMedia is available |
|
247 TInt count = aSource.Count(); |
|
248 GLX_DEBUG2("CGlxCache::CopyNewAndModifiedL() Attribs count=%d", count); |
|
249 aNewAttributes.ReserveL( count ); |
|
250 |
|
251 for (TInt i = 0; i < count; i++) |
|
252 { |
|
253 const TMPXAttribute& attrib = aSource.Attribute(i); |
|
254 |
|
255 if (attrib == KMPXMediaGeneralId) |
|
256 { |
|
257 // Ignore id |
|
258 __ASSERT_DEBUG((TUint32)aSource.ValueTObjectL<TMPXItemId>(attrib) == aTarget.Id().Value(), |
|
259 Panic(EGlxPanicIllegalArgument)); // aMedia relates to another media object than this |
|
260 } |
|
261 else |
|
262 { |
|
263 if (!aTarget.IsSupported(attrib)) |
|
264 { |
|
265 TMPXAttributeType type = aSource.Type(i); |
|
266 |
|
267 if (type == EMPXTypeText) |
|
268 { |
|
269 aTarget.SetTextValueL(attrib, aSource.ValueText(attrib)); |
|
270 } |
|
271 else if (type == EMPXTypeCObject) |
|
272 { |
|
273 if ( KGlxMediaIdThumbnail == attrib.ContentId() ) |
|
274 { |
|
275 // This is a thumbnail |
|
276 CFbsBitmap* thumbnail = iCacheManager->TempThumbnail(); |
|
277 |
|
278 if ( thumbnail && iCacheManager->TempThumbnailId() == aTarget.Id() ) |
|
279 { |
|
280 // Add new thumbnail attribute |
|
281 CGlxThumbnailAttribute* value = |
|
282 aSource.ValueNoNewLCObjectL<CGlxThumbnailAttribute>(attrib); |
|
283 CleanupStack::PushL(value); |
|
284 value->iBitmap = thumbnail; |
|
285 GLX_DEBUG3("CGlxCache::CopyNewAndModifiedL() TN Attrib w(%d) h(%d)", |
|
286 thumbnail->SizeInPixels().iWidth, thumbnail->SizeInPixels().iHeight); |
|
287 iCacheManager->SetTempThumbnailToNull(); |
|
288 aTarget.SetCObjectValueL(attrib, value); |
|
289 CleanupStack::Pop(value); |
|
290 } |
|
291 } |
|
292 else |
|
293 { |
|
294 __DEBUG_ONLY(Panic(EGlxPanicNotImplemented)); // Add support for the attribute here |
|
295 } |
|
296 } |
|
297 else if (type == EMPXTypeTObject) |
|
298 { |
|
299 if (attrib == KMPXMediaGeneralThumbnail1) |
|
300 { |
|
301 // Old thumbnail attribute - ignore |
|
302 } |
|
303 else if (attrib == KMPXMediaGeneralDate) |
|
304 { |
|
305 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt64>(attrib)); |
|
306 } |
|
307 else if (attrib == KGlxMediaGeneralLastModifiedDate) |
|
308 { |
|
309 TTime modified = aSource.ValueTObjectL<TInt64>(attrib); |
|
310 TTimeIntervalSeconds utcOffset = User::UTCOffset(); |
|
311 modified += utcOffset; |
|
312 aTarget.SetTObjectValueL(attrib, modified); |
|
313 } |
|
314 else if (attrib == KMPXMediaGeneralSize) |
|
315 { |
|
316 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TUint>(attrib)); |
|
317 } |
|
318 else if (attrib == KMPXMediaColDetailSpaceId) |
|
319 { |
|
320 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TGlxIdSpaceId>(attrib)); |
|
321 } |
|
322 else if (attrib == KMPXMediaGeneralType) |
|
323 { |
|
324 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib)); |
|
325 } |
|
326 else if (attrib == KMPXMediaGeneralCategory) |
|
327 { |
|
328 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib)); |
|
329 } |
|
330 else if (attrib == KMPXMediaGeneralCount) |
|
331 { |
|
332 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib)); |
|
333 } |
|
334 else if (attrib == KGlxMediaGeneralDimensions) |
|
335 { |
|
336 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TSize>(attrib)); |
|
337 } |
|
338 else if (attrib == KGlxMediaGeneralLocation) |
|
339 { |
|
340 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TCoordinate>(attrib)); |
|
341 } |
|
342 else if (attrib == KMPXMediaGeneralDuration) |
|
343 { |
|
344 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib)); |
|
345 } |
|
346 else if (attrib == KMPXMediaDrmProtected) |
|
347 { |
|
348 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TBool>(attrib)); |
|
349 } |
|
350 else if (attrib == KGlxMediaGeneralDRMRightsValid) |
|
351 { |
|
352 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TBool>(attrib)); |
|
353 } |
|
354 else if (attrib == KGlxMediaGeneralSystemItem) |
|
355 { |
|
356 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TBool>(attrib)); |
|
357 } |
|
358 else if (attrib == KGlxMediaGeneralFramecount) |
|
359 { |
|
360 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib)); |
|
361 } |
|
362 else if(attrib == KGlxMediaGeneralSlideshowableContent) |
|
363 { |
|
364 aTarget.SetTObjectValueL(attrib, aSource.ValueTObjectL<TInt>(attrib)); |
|
365 } |
|
366 else |
|
367 { |
|
368 __DEBUG_ONLY(Panic(EGlxPanicNotImplemented)); // Add support for the attribute here |
|
369 } |
|
370 } |
|
371 else |
|
372 { |
|
373 __DEBUG_ONLY(Panic(EGlxPanicNotImplemented)); |
|
374 } |
|
375 |
|
376 aNewAttributes.AppendL(attrib); |
|
377 } |
|
378 } |
|
379 } |
|
380 CleanupStack::Pop(&aNewAttributes); |
|
381 } |
|
382 |
|
383 // ----------------------------------------------------------------------------- |
|
384 // Delete |
|
385 // ----------------------------------------------------------------------------- |
|
386 // |
|
387 void CGlxCache::Delete( TInt aIndex ) |
|
388 { |
|
389 TRACER("CGlxCache::Delete"); |
|
390 |
|
391 GLX_ASSERT_DEBUG( 0 <= aIndex && aIndex < iItemPool.Count(), |
|
392 Panic(EGlxPanicIllegalArgument), "deleting attribute out of bounds"); |
|
393 |
|
394 CGlxMedia* media = iItemPool[aIndex]; |
|
395 |
|
396 // Cleanup the media from all users, example texture manager |
|
397 CleanupMedia(media->Id()); |
|
398 |
|
399 GLX_DEBUG2("MGallery - CGlxCache::Delete() for item id %d", media->Id().Value()); |
|
400 // notify users that the media object is about to be deleted. This allows |
|
401 // users to remove their references |
|
402 // (loop does not t iterate indexes, since the contents of the User array |
|
403 // will change during calls to RemoveReferences, as users are removed) |
|
404 |
|
405 // safety check that RemoveReference actually removed the reference |
|
406 __DEBUG_ONLY( TInt _maxLoopCount = 1000 ); |
|
407 |
|
408 while ( media->UserCount() > 0 ) |
|
409 { |
|
410 // The user must remove a reference and that will decrement the |
|
411 // UserCount() |
|
412 media->User( 0 ).RemoveReference( media->IndexInUser( 0 ) ); |
|
413 |
|
414 // protect against a bug that would cause hard-to-find infinite loop |
|
415 __DEBUG_ONLY( _maxLoopCount-- ); |
|
416 GLX_ASSERT_DEBUG( _maxLoopCount != 0, Panic( EGlxPanicLogicError ), |
|
417 "infinite loop when removing a media object" ); |
|
418 } |
|
419 |
|
420 delete media; |
|
421 iItemPool.Remove( aIndex ); |
|
422 } |
|
423 |
|
424 // ----------------------------------------------------------------------------- |
|
425 // Reserve space for a number of users, for all items in the cache |
|
426 // ----------------------------------------------------------------------------- |
|
427 // |
|
428 void CGlxCache::ReserveUsersL(TInt aCount) |
|
429 { |
|
430 TRACER("CGlxCache::ReserveUsersL"); |
|
431 |
|
432 TInt count = iItemPool.Count(); |
|
433 for ( TInt i = 0; i < count ; ++i ) |
|
434 { |
|
435 iItemPool[i]->ReserveUsersL( aCount ); |
|
436 } |
|
437 } |
|
438 |
|
439 // ----------------------------------------------------------------------------- |
|
440 // MediaItemOrderById |
|
441 // ----------------------------------------------------------------------------- |
|
442 // |
|
443 TInt CGlxCache::MediaItemOrderById(const CGlxMedia& aItem1, const CGlxMedia& aItem2) |
|
444 { |
|
445 TRACER("CGlxCache::MediaItemOrderById"); |
|
446 |
|
447 // Cannot do aItem1.Id() - aItem2.Id(), since Id().Value() returns an unsigned value |
|
448 TGlxMediaId id1 = aItem1.Id(); |
|
449 return MediaItemOrderByKey( &id1, aItem2 ); |
|
450 } |
|
451 |
|
452 // ----------------------------------------------------------------------------- |
|
453 // MediaItemOrderByKey |
|
454 // ----------------------------------------------------------------------------- |
|
455 // |
|
456 TInt CGlxCache::MediaItemOrderByKey(const TGlxMediaId* aMediaId, const CGlxMedia& aItem2) |
|
457 { |
|
458 TRACER("CGlxCache::MediaItemOrderByKey"); |
|
459 |
|
460 TGlxMediaId id2 = aItem2.Id(); |
|
461 if (*aMediaId < id2) |
|
462 { |
|
463 return -1; |
|
464 } |
|
465 |
|
466 if (*aMediaId > id2) |
|
467 { |
|
468 return 1; |
|
469 } |
|
470 |
|
471 return 0; |
|
472 } |
|
473 |
|
474 // ----------------------------------------------------------------------------- |
|
475 // Return count of media objects |
|
476 // ----------------------------------------------------------------------------- |
|
477 // |
|
478 TInt CGlxCache::Count() |
|
479 { |
|
480 TRACER("CGlxCache::Count"); |
|
481 |
|
482 return iItemPool.Count(); |
|
483 } |
|
484 |
|
485 // ----------------------------------------------------------------------------- |
|
486 // Return media object by index |
|
487 // ----------------------------------------------------------------------------- |
|
488 // |
|
489 CGlxMedia& CGlxCache::Media( TInt aIndex ) |
|
490 { |
|
491 TRACER("CGlxCache::Media"); |
|
492 |
|
493 return *iItemPool[aIndex]; |
|
494 } |
|
495 |
|
496 // ----------------------------------------------------------------------------- |
|
497 // Return media index |
|
498 // ----------------------------------------------------------------------------- |
|
499 // |
|
500 TInt CGlxCache::FindMediaIndexInCache(TGlxMediaId aMediaId) |
|
501 { |
|
502 TRACER("CGlxCache::FindMediaIndexInCache"); |
|
503 |
|
504 return iItemPool.FindInOrder(aMediaId, (&MediaItemOrderByKey)); |
|
505 } |
|
506 |