diff -r 000000000000 -r 6474c204b198 dom/speakermanager/SpeakerManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dom/speakermanager/SpeakerManager.cpp Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,225 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SpeakerManager.h" +#include "nsIDOMClassInfo.h" +#include "nsIDOMEvent.h" +#include "nsIDOMEventListener.h" +#include "SpeakerManagerService.h" +#include "nsIPermissionManager.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsIDocShell.h" +#include "AudioChannelService.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_QUERY_INTERFACE_INHERITED(SpeakerManager, DOMEventTargetHelper, + nsIDOMEventListener) +NS_IMPL_ADDREF_INHERITED(SpeakerManager, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(SpeakerManager, DOMEventTargetHelper) + +SpeakerManager::SpeakerManager() + : mForcespeaker(false) + , mVisible(false) +{ + SetIsDOMBinding(); + SpeakerManagerService *service = + SpeakerManagerService::GetSpeakerManagerService(); + if (service) { + service->RegisterSpeakerManager(this); + } +} + +SpeakerManager::~SpeakerManager() +{ + SpeakerManagerService *service = SpeakerManagerService::GetSpeakerManagerService(); + if (service) { + service->UnRegisterSpeakerManager(this); + } + nsCOMPtr target = do_QueryInterface(GetOwner()); + NS_ENSURE_TRUE_VOID(target); + + target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), + this, + /* useCapture = */ true); +} + +bool +SpeakerManager::Speakerforced() +{ + // If a background app calls forcespeaker=true that doesn't change anything. + // 'speakerforced' remains false everywhere. + if (mForcespeaker && !mVisible) { + return false; + } + SpeakerManagerService *service = SpeakerManagerService::GetSpeakerManagerService(); + if (service) { + return service->GetSpeakerStatus(); + } + return false; +} + +bool +SpeakerManager::Forcespeaker() +{ + return mForcespeaker; +} + +void +SpeakerManager::SetForcespeaker(bool aEnable) +{ + SpeakerManagerService *service = SpeakerManagerService::GetSpeakerManagerService(); + if (service) { + service->ForceSpeaker(aEnable, mVisible); + } + mForcespeaker = aEnable; +} + +void +SpeakerManager::DispatchSimpleEvent(const nsAString& aStr) +{ + NS_ABORT_IF_FALSE(NS_IsMainThread(), "Not running on main thread"); + nsresult rv = CheckInnerWindowCorrectness(); + if (NS_FAILED(rv)) { + return; + } + + nsCOMPtr event; + rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr); + if (NS_FAILED(rv)) { + NS_WARNING("Failed to create the error event!!!"); + return; + } + rv = event->InitEvent(aStr, false, false); + + if (NS_FAILED(rv)) { + NS_WARNING("Failed to init the error event!!!"); + return; + } + + event->SetTrusted(true); + + rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr); + if (NS_FAILED(rv)) { + NS_ERROR("Failed to dispatch the event!!!"); + return; + } +} + +void +SpeakerManager::Init(nsPIDOMWindow* aWindow) +{ + BindToOwner(aWindow); + + nsCOMPtr docshell = do_GetInterface(GetOwner()); + NS_ENSURE_TRUE_VOID(docshell); + docshell->GetIsActive(&mVisible); + + nsCOMPtr target = do_QueryInterface(GetOwner()); + NS_ENSURE_TRUE_VOID(target); + + target->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), + this, + /* useCapture = */ true, + /* wantsUntrusted = */ false); +} + +nsPIDOMWindow* +SpeakerManager::GetParentObject() const +{ + return GetOwner(); +} + +/* static */ already_AddRefed +SpeakerManager::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) +{ + nsCOMPtr sgo = do_QueryInterface(aGlobal.GetAsSupports()); + if (!sgo) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr ownerWindow = do_QueryInterface(aGlobal.GetAsSupports()); + if (!ownerWindow) { + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; + } + + nsCOMPtr permMgr = + do_GetService(NS_PERMISSIONMANAGER_CONTRACTID); + NS_ENSURE_TRUE(permMgr, nullptr); + + uint32_t permission = nsIPermissionManager::DENY_ACTION; + nsresult rv = + permMgr->TestPermissionFromWindow(ownerWindow, "speaker-control", + &permission); + NS_ENSURE_SUCCESS(rv, nullptr); + + if (permission != nsIPermissionManager::ALLOW_ACTION) { + aRv.Throw(NS_ERROR_DOM_SECURITY_ERR); + return nullptr; + } + + nsRefPtr object = new SpeakerManager(); + object->Init(ownerWindow); + return object.forget(); +} + +JSObject* +SpeakerManager::WrapObject(JSContext* aCx) +{ + return MozSpeakerManagerBinding::Wrap(aCx, this); +} + +NS_IMETHODIMP +SpeakerManager::HandleEvent(nsIDOMEvent* aEvent) +{ + nsAutoString type; + aEvent->GetType(type); + + if (!type.EqualsLiteral("visibilitychange")) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr docshell = do_GetInterface(GetOwner()); + NS_ENSURE_TRUE(docshell, NS_ERROR_FAILURE); + docshell->GetIsActive(&mVisible); + + // If an app that has called forcespeaker=true is switched + // from the background to the foreground 'speakerforced' + // switches to true in all apps. I.e. the app doesn't have to + // call forcespeaker=true again when it comes into foreground. + SpeakerManagerService *service = + SpeakerManagerService::GetSpeakerManagerService(); + if (service && mVisible && mForcespeaker) { + service->ForceSpeaker(mForcespeaker, mVisible); + } + // If an application that has called forcespeaker=true, but no audio is + // currently playing in the app itself, if application switch to + // the background, we switch 'speakerforced' to false. + if (!mVisible && mForcespeaker) { + AudioChannelService* audioChannelService = + AudioChannelService::GetAudioChannelService(); + if (audioChannelService && !audioChannelService->AnyAudioChannelIsActive()) { + service->ForceSpeaker(false, mVisible); + } + } + return NS_OK; +} + +void +SpeakerManager::SetAudioChannelActive(bool isActive) +{ + if (!isActive && !mVisible) { + SpeakerManagerService *service = + SpeakerManagerService::GetSpeakerManagerService(); + if (service) { + service->ForceSpeaker(false, mVisible); + } + } +} + +} // namespace dom +} // namespace mozilla