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