mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 14:22:01 +00:00
224 lines
6.2 KiB
C++
224 lines
6.2 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
|
/* 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 "mozilla/Services.h"
|
|
|
|
#include "mozilla/dom/Event.h"
|
|
|
|
#include "AudioChannelService.h"
|
|
#include "nsIDocShell.h"
|
|
#include "nsIDOMClassInfo.h"
|
|
#include "nsIDOMEventListener.h"
|
|
#include "nsIInterfaceRequestorUtils.h"
|
|
#include "nsIPermissionManager.h"
|
|
#include "SpeakerManagerService.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)
|
|
{
|
|
SpeakerManagerService *service =
|
|
SpeakerManagerService::GetOrCreateSpeakerManagerService();
|
|
MOZ_ASSERT(service);
|
|
service->RegisterSpeakerManager(this);
|
|
}
|
|
|
|
SpeakerManager::~SpeakerManager()
|
|
{
|
|
SpeakerManagerService *service = SpeakerManagerService::GetOrCreateSpeakerManagerService();
|
|
MOZ_ASSERT(service);
|
|
|
|
service->UnRegisterSpeakerManager(this);
|
|
nsCOMPtr<EventTarget> 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::GetOrCreateSpeakerManagerService();
|
|
MOZ_ASSERT(service);
|
|
return service->GetSpeakerStatus();
|
|
|
|
}
|
|
|
|
bool
|
|
SpeakerManager::Forcespeaker()
|
|
{
|
|
return mForcespeaker;
|
|
}
|
|
|
|
void
|
|
SpeakerManager::SetForcespeaker(bool aEnable)
|
|
{
|
|
SpeakerManagerService *service = SpeakerManagerService::GetOrCreateSpeakerManagerService();
|
|
MOZ_ASSERT(service);
|
|
|
|
service->ForceSpeaker(aEnable, mVisible);
|
|
mForcespeaker = aEnable;
|
|
}
|
|
|
|
void
|
|
SpeakerManager::DispatchSimpleEvent(const nsAString& aStr)
|
|
{
|
|
MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
|
|
nsresult rv = CheckInnerWindowCorrectness();
|
|
if (NS_FAILED(rv)) {
|
|
return;
|
|
}
|
|
|
|
nsRefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
|
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<nsIDocShell> docshell = do_GetInterface(GetOwner());
|
|
NS_ENSURE_TRUE_VOID(docshell);
|
|
docshell->GetIsActive(&mVisible);
|
|
|
|
nsCOMPtr<nsIDOMEventTarget> 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>
|
|
SpeakerManager::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv)
|
|
{
|
|
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aGlobal.GetAsSupports());
|
|
if (!sgo) {
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
return nullptr;
|
|
}
|
|
|
|
nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
|
|
if (!ownerWindow) {
|
|
aRv.Throw(NS_ERROR_FAILURE);
|
|
return nullptr;
|
|
}
|
|
|
|
nsCOMPtr<nsIPermissionManager> permMgr = services::GetPermissionManager();
|
|
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<SpeakerManager> object = new SpeakerManager();
|
|
object->Init(ownerWindow);
|
|
return object.forget();
|
|
}
|
|
|
|
JSObject*
|
|
SpeakerManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
|
{
|
|
return MozSpeakerManagerBinding::Wrap(aCx, this, aGivenProto);
|
|
}
|
|
|
|
NS_IMETHODIMP
|
|
SpeakerManager::HandleEvent(nsIDOMEvent* aEvent)
|
|
{
|
|
nsAutoString type;
|
|
aEvent->GetType(type);
|
|
|
|
if (!type.EqualsLiteral("visibilitychange")) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
|
|
nsCOMPtr<nsIDocShell> 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::GetOrCreateSpeakerManagerService();
|
|
MOZ_ASSERT(service);
|
|
|
|
if (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) {
|
|
nsRefPtr<AudioChannelService> audioChannelService =
|
|
AudioChannelService::GetOrCreate();
|
|
if (audioChannelService && !audioChannelService->AnyAudioChannelIsActive()) {
|
|
service->ForceSpeaker(false, mVisible);
|
|
}
|
|
}
|
|
return NS_OK;
|
|
}
|
|
|
|
void
|
|
SpeakerManager::SetAudioChannelActive(bool isActive)
|
|
{
|
|
if (mForcespeaker) {
|
|
SpeakerManagerService *service =
|
|
SpeakerManagerService::GetOrCreateSpeakerManagerService();
|
|
MOZ_ASSERT(service);
|
|
service->ForceSpeaker(isActive, mVisible);
|
|
}
|
|
}
|
|
|
|
} // namespace dom
|
|
} // namespace mozilla
|