28 #include <nsIAppStartupNotifier.h>
29 #include <nsICategoryManager.h>
30 #include <nsIComponentManager.h>
31 #include <nsIComponentRegistrar.h>
32 #include <nsIEventTarget.h>
34 #include <nsIIdleService.h>
35 #include <nsILocalFile.h>
36 #include <nsIObserverService.h>
37 #include <nsIPropertyBag2.h>
38 #include <nsISimpleEnumerator.h>
39 #include <nsISupportsPrimitives.h>
43 #include <sbILibrary.h>
44 #include <sbILibraryManager.h>
45 #include <sbIMediaItemController.h>
47 #include <nsAutoLock.h>
49 #include <nsServiceManagerUtils.h>
50 #include <nsStringAPI.h>
51 #include <nsTextFormatter.h>
52 #include <nsThreadUtils.h>
68 #define K_LAST_SEEN_TYPES_PROPERTY \
69 "http://songbirdnest.com/data/1.0#libraryItemControllerLastSeenTypes"
70 #define K_LAST_SEEN_TYPES_SEPARATOR '\x7F'
73 #define K_HIDDEN_FOR_CONTROLLER_PROPERTY \
74 "http://songbirdnest.com/data/1.0#libraryItemControllerTypeDisappeared"
77 #define K_CLEANUP_COMPLETE_OBSERVER_TOPIC \
78 "songbird-media-item-controller-cleanup-complete"
79 #define K_CLEANUP_INTERRUPTED_OBSERVER_TOPIC \
80 "songbird-media-item-controller-cleanup-interrupted"
81 #define K_CLEANUP_IDLE_OBSERVER_TOPIC \
82 "songbird-media-item-controller-cleanup-idle"
83 #define K_QUIT_APP_OBSERVER_TOPIC \
88 #define SB_THREADPOOLSERVICE_CONTRACTID \
89 "@songbirdnest.com/Songbird/ThreadPoolService;1"
98 : mAvailableTypesInitialized(
false),
99 mIdleServiceRegistered(false),
104 NS_PRECONDITION(NS_IsMainThread(),
105 "sbMediaItemControllerCleanup::sbMediaItemControllerCleanup"
106 " should be called on the main thread!");
113 "sbMediaItemControllerCleanup being destroyed while not idle");
121 sbMediaItemControllerCleanup::Observe(
nsISupports *aSubject,
123 const PRUnichar *
aData)
126 NS_PRECONDITION(NS_IsMainThread(),
127 "sbMediaItemControllerCleanup::Observe"
128 " should be called on the main thread!");
131 if (!strcmp(aTopic,
"idle")) {
133 nsAutoLock lock(
mLock);
135 TRACE(
"preparing to run: STATE->RUNNING");
139 NS_ENSURE_SUCCESS(rv, rv);
146 TRACE(
"Resuming: STATE->RUNNING");
153 TRACE(
"nothing to do, ignoring idle notification");
154 nsCOMPtr<nsIObserverService> obs =
156 NS_ENSURE_SUCCESS(rv, rv);
158 nsString notificationData;
160 notificationData.Adopt(nsTextFormatter::smprintf((PRUnichar*)NS_LL(
"%llx"),
162 TRACE(
"Notifying observers (%s) [%s]",
164 NS_ConvertUTF16toUTF8(notificationData).
get());
166 rv = obs->NotifyObservers(NS_ISUPPORTS_CAST(
nsIObserver*,
this),
168 notificationData.get());
169 NS_ENSURE_SUCCESS(rv, rv);
172 else if (!strcmp(aTopic,
"back")) {
174 nsAutoLock lock(
mLock);
176 TRACE(
"Stopping due to activity: STATE->STOPPING");
184 else if (!strcmp(aTopic, APPSTARTUP_TOPIC)) {
185 nsCOMPtr<nsIObserverService> obs =
186 do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
187 NS_ENSURE_SUCCESS(rv, rv);
188 rv = obs->AddObserver(static_cast<nsIObserver*>(
this),
191 NS_ENSURE_SUCCESS(rv, rv);
192 rv = obs->AddObserver(static_cast<nsIObserver*>(
this),
195 NS_ENSURE_SUCCESS(rv, rv);
197 NS_ENSURE_SUCCESS(rv, rv);
198 mLock = nsAutoLock::NewLock(__FUNCTION__);
199 NS_ENSURE_TRUE(
mLock, NS_ERROR_OUT_OF_MEMORY);
202 nsCOMPtr<sbILibraryManager> libManager =
203 do_GetService(
"@songbirdnest.com/Songbird/library/Manager;1", &rv);
204 NS_ENSURE_SUCCESS(rv, rv);
205 rv = libManager->AddListener(static_cast<sbILibraryManagerListener*>(
this));
206 NS_ENSURE_SUCCESS(rv, rv);
208 nsCOMPtr<nsIObserverService> obs =
209 do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
210 NS_ENSURE_SUCCESS(rv, rv);
211 rv = obs->RemoveObserver(static_cast<nsIObserver*>(
this),
213 NS_ENSURE_SUCCESS(rv, rv);
217 nsCOMPtr<nsISimpleEnumerator> libs;
218 rv = libManager->GetLibraries(getter_AddRefs(libs));
219 NS_ENSURE_SUCCESS(rv, rv);
221 while (NS_SUCCEEDED(libs->HasMoreElements(&hasLib)) && hasLib) {
222 nsCOMPtr<nsISupports> supports;
223 rv = libs->GetNext(getter_AddRefs(supports));
224 NS_ENSURE_SUCCESS(rv, rv);
225 nsCOMPtr<sbILibrary> lib = do_QueryInterface(supports, &rv);
226 NS_ENSURE_SUCCESS(rv, rv);
227 rv = OnLibraryRegistered(lib);
228 NS_ENSURE_SUCCESS(rv, rv);
232 nsCOMPtr<nsIIdleService> idleService =
233 do_GetService(
"@mozilla.org/widget/idleservice;1", &rv);
234 NS_ENSURE_SUCCESS(rv, rv);
235 (void)idleService->RemoveIdleObserver(static_cast<nsIObserver*>(
this),
240 nsCOMPtr<sbILibraryManager> libManager =
241 do_GetService(
"@songbirdnest.com/Songbird/library/Manager;1", &rv);
242 NS_ENSURE_SUCCESS(rv, rv);
243 rv = libManager->RemoveListener(static_cast<sbILibraryManagerListener*>(
this));
244 NS_ENSURE_SUCCESS(rv, rv);
246 nsCOMPtr<nsIObserverService> obs =
247 do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
248 NS_ENSURE_SUCCESS(rv, rv);
249 rv = obs->RemoveObserver(static_cast<nsIObserver*>(
this),
251 NS_ENSURE_SUCCESS(rv, rv);
254 NS_WARNING(
"unexpected topic");
262 sbMediaItemControllerCleanup::Run()
265 NS_PRECONDITION(!NS_IsMainThread(),
266 "sbMediaItemControllerCleanup::Run"
267 " should not be called on the main thread!");
272 nsAutoLock lock(
mLock);
274 "the act of getting things queued should have put"
275 " us into the running state");
287 PRBool complete =
true;
289 nsAutoLock lock(
mLock);
292 "should not have exit running!?");
294 TRACE(
"Run complete: STATE->IDLE");
301 TRACE(
"Run incomplete: STATE->QUEUED");
306 NS_ENSURE_SUCCESS(rv, rv);
313 "Unexpected state while stopping process!");
321 nsString notificationData;
323 notificationData.Adopt(nsTextFormatter::smprintf((PRUnichar*)NS_LL(
"%llx"),
325 TRACE(
"Notifying observers (%s) [%s]",
327 NS_ConvertUTF16toUTF8(notificationData).get());
329 nsCOMPtr<nsIObserverService> obs =
331 NS_ENSURE_SUCCESS(rv, rv);
333 rv = obs->NotifyObservers(NS_ISUPPORTS_CAST(
nsIObserver*,
this),
335 notificationData.get());
336 NS_ENSURE_SUCCESS(rv, rv);
345 template <
typename T>
346 struct STLIteratorValueIs {
347 STLIteratorValueIs(
typename T::second_type v) :m(v) {}
348 bool operator() (
const T&
t) {
349 return t.second == m;
351 typename T::second_type m;
359 sbMediaItemControllerCleanup::OnLibraryRegistered(
sbILibrary *aLibrary)
362 NS_PRECONDITION(NS_IsMainThread(),
363 "sbMediaItemControllerCleanup::OnLibraryRegistered"
364 " should be called on the main thread!");
365 NS_ENSURE_ARG_POINTER(aLibrary);
373 NS_ENSURE_SUCCESS(rv, rv);
374 contentSrc.Cut(0, contentSrc.RFindChar(PRUnichar(
'/')) + 1);
375 TRACE(
"library: %s", NS_ConvertUTF16toUTF8(contentSrc).BeginReading());
383 NS_ENSURE_SUCCESS(rv, rv);
385 nsString cachedTypesUnicode;
388 NS_ENSURE_SUCCESS(rv, rv);
390 nsCString cachedTypes;
391 LossyCopyUTF16toASCII(cachedTypesUnicode, cachedTypes);
393 TRACE(
"cached types: %s", cachedTypes.BeginReading());
395 PRInt32
start = 0, end;
405 TRACE(
"found cached type %s", type.c_str());
412 types.insert(types_t::value_type(type,
false));
416 TRACE(
"cache update check: removed types? (%i) added types? (%i)",
417 std::count_if(
types.begin(),
419 STLIteratorValueIs<types_t::value_type>(
false)),
420 std::count_if(
types.begin(),
422 STLIteratorValueIs<types_t::value_type>(
true)));
425 types_t::const_iterator it;
426 for (it =
types.begin(); it !=
types.end(); ++it) {
428 TRACE(
"type removed: %s", it->first.c_str());
431 for (it =
types.begin(); it !=
types.end(); ++it) {
433 TRACE(
"type added: %s", it->first.c_str());
439 if (!
types.empty()) {
448 types_t::const_iterator it;
450 newCache.Append(it->first.c_str(), it->first.length());
453 for (it =
types.begin(); it !=
types.end(); ++it) {
458 newCache.Append(it->first.c_str(), it->first.length());
461 newCache.SetLength(newCache.Length() - 1);
462 TRACE(
"updating cache to %s", newCache.BeginReading());
464 NS_ConvertASCIItoUTF16(newCache));
465 NS_ENSURE_SUCCESS(rv, rv);
471 nsCOMPtr<nsIIdleService> idleService =
472 do_GetService(
"@mozilla.org/widget/idleservice;1", &rv);
473 NS_ENSURE_SUCCESS(rv, rv);
476 rv = idleService->AddIdleObserver(static_cast<nsIObserver*>(
this),
478 NS_ENSURE_SUCCESS(rv, rv);
482 nsAutoLock lock(
mLock);
485 TRACE(
"Libraries added: STATE->QUEUED");
492 nsString fileName((
const PRUnichar*)NS_LL(
"<ERROR>"));
493 nsCOMPtr<nsIPropertyBag2> creationParams;
494 rv = aLibrary->GetCreationParameters(getter_AddRefs(creationParams));
495 NS_ENSURE_SUCCESS(rv, rv);
496 NS_NAMED_LITERAL_STRING(fileKey,
"databaseFile");
497 nsCOMPtr<nsILocalFile> databaseFile;
498 rv = creationParams->GetPropertyAsInterface(fileKey,
499 NS_GET_IID(nsILocalFile),
500 getter_AddRefs(databaseFile));
501 if (NS_SUCCEEDED(rv)) {
502 rv = databaseFile->GetLeafName(fileName);
504 TRACE(
"queued library %s for processing",
505 NS_ConvertUTF16toUTF8(fileName).
get());
510 rv = idleService->GetIdleTime(&idleTime);
511 NS_ENSURE_SUCCESS(rv, rv);
514 rv = Observe(idleService,
"idle", nsnull);
515 NS_ENSURE_SUCCESS(rv, rv);
524 sbMediaItemControllerCleanup::OnLibraryUnregistered(
sbILibrary *aLibrary)
527 NS_PRECONDITION(NS_IsMainThread(),
528 "sbMediaItemControllerCleanup::OnLibraryUnregistered"
529 " should be called on the main thread!");
530 NS_ENSURE_ARG_POINTER(aLibrary);
532 nsAutoLock lock(
mLock);
535 nsCOMPtr<sbIMediaList> list =
mListener->GetMediaList();
537 if (list && NS_SUCCEEDED(list->Equals(aLibrary, &equals)) && equals) {
542 libraries_t::iterator it =
mLibraries.find(aLibrary);
555 NS_PRECONDITION(NS_IsMainThread(),
556 "sbMediaItemControllerCleanup::EnsureAvailableTypes"
557 " should be called on the main thread!");
564 nsCOMPtr<nsIComponentRegistrar>
registrar;
565 rv = NS_GetComponentRegistrar(getter_AddRefs(registrar));
566 NS_ENSURE_SUCCESS(rv, rv);
568 nsCOMPtr<nsISimpleEnumerator> enumerator;
569 rv = registrar->EnumerateContractIDs(getter_AddRefs(enumerator));
570 NS_ENSURE_SUCCESS(rv, rv);
573 NS_NAMED_LITERAL_CSTRING(CONTRACT_PREFIX,
575 while (NS_SUCCEEDED(enumerator->HasMoreElements(&hasMore)) && hasMore) {
576 nsCOMPtr<nsISupports> supports;
577 rv = enumerator->GetNext(getter_AddRefs(supports));
578 NS_ENSURE_SUCCESS(rv, rv);
579 nsCOMPtr<nsISupportsCString>
string = do_QueryInterface(supports, &rv);
580 NS_ENSURE_SUCCESS(rv, rv);
582 rv =
string->GetData(value);
583 NS_ENSURE_SUCCESS(rv, rv);
584 if (StringBeginsWith(value, CONTRACT_PREFIX))
586 std::string type(value.BeginReading() + CONTRACT_PREFIX.Length(),
587 value.Length() - CONTRACT_PREFIX.Length());
600 NS_PRECONDITION(!NS_IsMainThread(),
601 "sbMediaItemControllerCleanup::ProcessLibraries"
602 " was expected to run on a background thread!");
610 nsCOMPtr<sbILibrary> lib;
613 nsAutoLock lock(
mLock);
617 libraries_t::const_iterator it =
mLibraries.begin();
621 NS_ASSERTION(!types.empty(),
622 "Attempted to process a library with neither added nor removed types!");
625 nsString fileName((
const PRUnichar*)NS_LL(
"<ERROR>"));
626 nsCOMPtr<nsIPropertyBag2> creationParams;
627 rv = lib->GetCreationParameters(getter_AddRefs(creationParams));
628 NS_ENSURE_SUCCESS(rv, rv);
629 NS_NAMED_LITERAL_STRING(fileKey,
"databaseFile");
630 nsCOMPtr<nsILocalFile> databaseFile;
631 rv = creationParams->GetPropertyAsInterface(fileKey,
632 NS_GET_IID(nsILocalFile),
633 getter_AddRefs(databaseFile));
634 if (NS_SUCCEEDED(rv)) {
635 rv = databaseFile->GetLeafName(fileName);
637 TRACE(
"got new library %p to process", NS_ConvertUTF16toUTF8(fileName).
get());
641 types_t::const_iterator it;
643 for (it = types.begin(); it != types.end(); ++it) {
645 (it->second ?
"adding" :
"removing"),
647 NS_ConvertASCIItoUTF16 type(it->first.c_str(), it->first.length());
649 nsCOMPtr<sbIMutablePropertyArray> mutableProp =
650 do_CreateInstance(
"@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1", &rv);
651 NS_ENSURE_SUCCESS(rv, rv);
653 it->second ? NS_LITERAL_STRING(
"0")
654 : NS_LITERAL_STRING(
"1"));
655 NS_ENSURE_SUCCESS(rv, rv);
658 : NS_LITERAL_STRING(
"1"));
659 NS_ENSURE_SUCCESS(rv, rv);
660 nsCOMPtr<sbIPropertyArray> propsToSet = do_QueryInterface(mutableProp, &rv);
661 NS_ENSURE_SUCCESS(rv, rv);
664 do_CreateInstance(
"@songbirdnest.com/Songbird/Properties/MutablePropertyArray;1", &rv);
665 NS_ENSURE_SUCCESS(rv, rv);
668 NS_ENSURE_SUCCESS(rv, rv);
672 NS_LITERAL_STRING(
"1"));
673 NS_ENSURE_SUCCESS(rv, rv);
675 nsCOMPtr<sbIPropertyArray> propsToFilter =
676 do_QueryInterface(mutableProp, &rv);
677 NS_ENSURE_SUCCESS(rv, rv);
679 nsCOMPtr<sbIMediaList> list = do_QueryInterface(lib, &rv);
680 NS_ENSURE_SUCCESS(rv, rv);
682 nsAutoLock lock(
mLock);
684 NS_ENSURE_TRUE(
mListener, NS_ERROR_OUT_OF_MEMORY);
687 rv = lib->RunInBatchMode(
mListener, nsnull);
688 NS_ENSURE_SUCCESS(rv, rv);
689 TRACE(
"batch complete");
692 nsAutoLock lock(
mLock);
697 TRACE(
"run aborted");
704 nsString cachedTypes;
707 NS_ENSURE_SUCCESS(rv, rv);
714 PRInt32
pos = cachedTypes.Find(type);
716 cachedTypes.Cut(pos, type.Length() - 1);
718 cachedTypes.Trim(SEP);
719 TRACE(
"setting types to \"%s\"",
720 NS_LossyConvertUTF16toASCII(cachedTypes).BeginReading());
723 NS_ENSURE_SUCCESS(rv, rv);
726 TRACE(
"Failed to find \"%s\" in \"%s\"",
727 NS_LossyConvertUTF16toASCII(type).BeginReading(),
728 NS_LossyConvertUTF16toASCII(cachedTypes).BeginReading());
735 nsAutoLock lock(
mLock);
742 nsAutoLock lock(
mLock);
743 TRACE(
"completed? %s",
756 const char* aLoaderStr,
758 const nsModuleComponentInfo *aInfo)
763 nsresult rv = NS_ERROR_UNEXPECTED;
764 nsCOMPtr<nsICategoryManager> categoryManager =
765 do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
766 NS_ENSURE_SUCCESS(rv, rv);
768 rv = categoryManager->AddCategoryEntry(APPSTARTUP_TOPIC,
772 PR_TRUE, PR_TRUE, nsnull);
773 NS_ENSURE_SUCCESS(rv, rv);
795 mPropsToFilter = aPropertiesToFilter;
796 mPropsToSet = aPropertiesToSet;
801 sbMediaItemControllerCleanup::sbEnumerationHelper::OnEnumerationBegin(
803 PRUint16 *_retval NS_OUTPARAM)
806 NS_PRECONDITION(!NS_IsMainThread(),
807 "sbEnumerationHelper::OnEnumerationBegin"
808 " should be called on the background thread!");
809 NS_ENSURE_ARG_POINTER(aMediaList);
810 NS_ENSURE_ARG_POINTER(_retval);
817 sbMediaItemControllerCleanup::sbEnumerationHelper::OnEnumeratedItem(
820 PRUint16 *_retval NS_OUTPARAM)
823 NS_PRECONDITION(!NS_IsMainThread(),
824 "sbEnumerationHelper::OnEnumeratedItem"
825 " should be called on the background thread!");
826 NS_ENSURE_ARG_POINTER(aMediaList);
827 NS_ENSURE_ARG_POINTER(aMediaItem);
828 NS_ENSURE_ARG_POINTER(_retval);
837 rv = aMediaItem->SetProperties(mPropsToSet);
838 NS_ENSURE_SUCCESS(rv, rv);
845 sbMediaItemControllerCleanup::sbEnumerationHelper::OnEnumerationEnd(
847 nsresult aStatusCode)
850 NS_PRECONDITION(!NS_IsMainThread(),
851 "sbEnumerationHelper::OnEnumerationEnd"
852 " should be called on the background thread!");
853 mCompleted = NS_SUCCEEDED(aStatusCode);
858 rv = mPropsToFilter->ToString(filter);
859 if (NS_FAILED(rv)) filter.AssignLiteral(
"<error>");
860 rv = mPropsToSet->ToString(filter);
861 if (NS_FAILED(rv)) filter.AssignLiteral(
"<error>");
862 TRACE(
"filter: %s set: %s complete? %s",
863 NS_ConvertUTF16toUTF8(filter).
get(),
864 NS_ConvertUTF16toUTF8(set).
get(),
865 mCompleted ?
"yes" :
"no");
873 sbMediaItemControllerCleanup::sbEnumerationHelper::RunBatched(
879 rv = mList->EnumerateItemsByProperties(mPropsToFilter,
882 NS_ENSURE_SUCCESS(rv, rv);
909 already_AddRefed<sbIMediaList>
913 return nsCOMPtr<sbIMediaList>(mList).forget();
Manages the lifecycle of libraries in the system.
#define SB_PRLOG_SETUP(x)
const SB_LIBRARY_MANAGER_READY_TOPIC
#define SB_PROPERTY_TRACKTYPE
#define SB_PROPERTY_HIDDEN
const sbCreateProxiedComponent do_ProxiedGetService(const nsCID &aCID, nsresult *error=0)
#define TRACE_FUNCTION(...)
Media library abstraction.
StringArrayEnumerator prototype hasMore
#define SB_PROPERTY_CONTENTURL
An interface to carry around arrays of nsIProperty instances. Users of this interface should only QI ...
Array filter(tab.attributes, function(aAttr){return(_this.xulAttributes.indexOf(aAttr.name) >-1);}).forEach(tab.removeAttribute
_updateTextAndScrollDataForFrame aData