mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-06 23:37:31 +09:00
import FIREFOX_52_6_0esr_RELEASE from mozilla-esr52 hg repo
This commit is contained in:
commit
dcd9973243
150858 changed files with 23884658 additions and 0 deletions
217
dom/speakermanager/SpeakerManager.cpp
Normal file
217
dom/speakermanager/SpeakerManager.cpp
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
/* -*- 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;
|
||||
}
|
||||
|
||||
RefPtr<Event> event = NS_NewDOMEvent(this, nullptr, nullptr);
|
||||
event->InitEvent(aStr, false, false);
|
||||
event->SetTrusted(true);
|
||||
|
||||
rv = DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Failed to dispatch the event!!!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManager::Init(nsPIDOMWindowInner* aWindow)
|
||||
{
|
||||
BindToOwner(aWindow);
|
||||
|
||||
nsCOMPtr<nsIDocShell> docshell = GetOwner()->GetDocShell();
|
||||
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);
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner*
|
||||
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<nsPIDOMWindowInner> 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;
|
||||
}
|
||||
|
||||
RefPtr<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) {
|
||||
RefPtr<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
|
||||
66
dom/speakermanager/SpeakerManager.h
Normal file
66
dom/speakermanager/SpeakerManager.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeakerManager_h
|
||||
#define mozilla_dom_SpeakerManager_h
|
||||
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "mozilla/dom/MozSpeakerManagerBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
/* This class is used for UA to control devices's speaker status.
|
||||
* After UA set the speaker status, the UA should handle the
|
||||
* forcespeakerchange event and change the speaker status in UI.
|
||||
* The device's speaker status would set back to normal when UA close the application.
|
||||
*/
|
||||
class SpeakerManager final
|
||||
: public DOMEventTargetHelper
|
||||
, public nsIDOMEventListener
|
||||
{
|
||||
friend class SpeakerManagerService;
|
||||
friend class SpeakerManagerServiceChild;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
public:
|
||||
void Init(nsPIDOMWindowInner* aWindow);
|
||||
|
||||
nsPIDOMWindowInner* GetParentObject() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
/**
|
||||
* WebIDL Interface
|
||||
*/
|
||||
// Get this api's force speaker setting.
|
||||
bool Forcespeaker();
|
||||
// Force acoustic sound go through speaker. Don't force to speaker if application
|
||||
// stay in the background and re-force when application
|
||||
// go to foreground
|
||||
void SetForcespeaker(bool aEnable);
|
||||
// Get the device's speaker forced setting.
|
||||
bool Speakerforced();
|
||||
|
||||
void SetAudioChannelActive(bool aIsActive);
|
||||
IMPL_EVENT_HANDLER(speakerforcedchange)
|
||||
|
||||
static already_AddRefed<SpeakerManager>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
SpeakerManager();
|
||||
~SpeakerManager();
|
||||
void DispatchSimpleEvent(const nsAString& aStr);
|
||||
// This api's force speaker setting
|
||||
bool mForcespeaker;
|
||||
bool mVisible;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_SpeakerManager_h
|
||||
224
dom/speakermanager/SpeakerManagerService.cpp
Normal file
224
dom/speakermanager/SpeakerManagerService.cpp
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
/* -*- 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 "SpeakerManagerService.h"
|
||||
#include "SpeakerManagerServiceChild.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "nsIPropertyBag2.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include <cutils/properties.h>
|
||||
|
||||
#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
|
||||
#include "nsIAudioManager.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
StaticRefPtr<SpeakerManagerService> gSpeakerManagerService;
|
||||
|
||||
// static
|
||||
SpeakerManagerService*
|
||||
SpeakerManagerService::GetOrCreateSpeakerManagerService()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return SpeakerManagerServiceChild::GetOrCreateSpeakerManagerService();
|
||||
}
|
||||
|
||||
// If we already exist, exit early
|
||||
if (gSpeakerManagerService) {
|
||||
return gSpeakerManagerService;
|
||||
}
|
||||
|
||||
// Create new instance, register, return
|
||||
RefPtr<SpeakerManagerService> service = new SpeakerManagerService();
|
||||
|
||||
gSpeakerManagerService = service;
|
||||
|
||||
return gSpeakerManagerService;
|
||||
}
|
||||
|
||||
SpeakerManagerService*
|
||||
SpeakerManagerService::GetSpeakerManagerService()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return SpeakerManagerServiceChild::GetSpeakerManagerService();
|
||||
}
|
||||
|
||||
return gSpeakerManagerService;
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerService::Shutdown()
|
||||
{
|
||||
if (!XRE_IsParentProcess()) {
|
||||
return SpeakerManagerServiceChild::Shutdown();
|
||||
}
|
||||
|
||||
if (gSpeakerManagerService) {
|
||||
gSpeakerManagerService = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(SpeakerManagerService, nsIObserver)
|
||||
|
||||
void
|
||||
SpeakerManagerService::ForceSpeaker(bool aEnable, uint64_t aChildId)
|
||||
{
|
||||
TurnOnSpeaker(aEnable);
|
||||
if (aEnable) {
|
||||
mSpeakerStatusSet.Put(aChildId);
|
||||
}
|
||||
Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerService::ForceSpeaker(bool aEnable, bool aVisible)
|
||||
{
|
||||
// b2g main process without oop
|
||||
TurnOnSpeaker(aEnable && aVisible);
|
||||
mVisible = aVisible;
|
||||
mOrgSpeakerStatus = aEnable;
|
||||
Notify();
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerService::TurnOnSpeaker(bool aOn)
|
||||
{
|
||||
nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE_VOID(audioManager);
|
||||
int32_t phoneState;
|
||||
audioManager->GetPhoneState(&phoneState);
|
||||
int32_t forceuse = (phoneState == nsIAudioManager::PHONE_STATE_IN_CALL ||
|
||||
phoneState == nsIAudioManager::PHONE_STATE_IN_COMMUNICATION)
|
||||
? nsIAudioManager::USE_COMMUNICATION : nsIAudioManager::USE_MEDIA;
|
||||
if (aOn) {
|
||||
audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_SPEAKER);
|
||||
} else {
|
||||
audioManager->SetForceForUse(forceuse, nsIAudioManager::FORCE_NONE);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SpeakerManagerService::GetSpeakerStatus()
|
||||
{
|
||||
char propQemu[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.kernel.qemu", propQemu, "");
|
||||
if (!strncmp(propQemu, "1", 1)) {
|
||||
return mOrgSpeakerStatus;
|
||||
}
|
||||
nsCOMPtr<nsIAudioManager> audioManager = do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(audioManager, false);
|
||||
int32_t usage;
|
||||
audioManager->GetForceForUse(nsIAudioManager::USE_MEDIA, &usage);
|
||||
return usage == nsIAudioManager::FORCE_SPEAKER;
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerService::Notify()
|
||||
{
|
||||
// Parent Notify to all the child processes.
|
||||
nsTArray<ContentParent*> children;
|
||||
ContentParent::GetAll(children);
|
||||
for (uint32_t i = 0; i < children.Length(); i++) {
|
||||
Unused << children[i]->SendSpeakerManagerNotify();
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < mRegisteredSpeakerManagers.Length(); i++) {
|
||||
mRegisteredSpeakerManagers[i]->
|
||||
DispatchSimpleEvent(NS_LITERAL_STRING("speakerforcedchange"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerService::SetAudioChannelActive(bool aIsActive)
|
||||
{
|
||||
if (!aIsActive && !mVisible) {
|
||||
ForceSpeaker(!mOrgSpeakerStatus, mVisible);
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
SpeakerManagerService::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
if (!strcmp(aTopic, "ipc:content-shutdown")) {
|
||||
nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
|
||||
if (!props) {
|
||||
NS_WARNING("ipc:content-shutdown message without property bag as subject");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
uint64_t childID = 0;
|
||||
nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
|
||||
&childID);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
// If the audio has paused by audiochannel,
|
||||
// the enable flag should be false and don't need to handle.
|
||||
if (mSpeakerStatusSet.Contains(childID)) {
|
||||
TurnOnSpeaker(false);
|
||||
mSpeakerStatusSet.Remove(childID);
|
||||
}
|
||||
if (mOrgSpeakerStatus) {
|
||||
TurnOnSpeaker(!mOrgSpeakerStatus);
|
||||
mOrgSpeakerStatus = false;
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("ipc:content-shutdown message without childID property");
|
||||
}
|
||||
} else if (!strcmp(aTopic, "xpcom-will-shutdown")) {
|
||||
// Note that we need to do this before xpcom-shutdown, since the
|
||||
// AudioChannelService cannot be used past that point.
|
||||
RefPtr<AudioChannelService> audioChannelService =
|
||||
AudioChannelService::GetOrCreate();
|
||||
if (audioChannelService) {
|
||||
audioChannelService->UnregisterSpeakerManager(this);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "ipc:content-shutdown");
|
||||
obs->RemoveObserver(this, "xpcom-will-shutdown");
|
||||
}
|
||||
|
||||
Shutdown();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SpeakerManagerService::SpeakerManagerService()
|
||||
: mOrgSpeakerStatus(false),
|
||||
mVisible(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(SpeakerManagerService);
|
||||
if (XRE_IsParentProcess()) {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "ipc:content-shutdown", false);
|
||||
obs->AddObserver(this, "xpcom-will-shutdown", false);
|
||||
}
|
||||
}
|
||||
RefPtr<AudioChannelService> audioChannelService =
|
||||
AudioChannelService::GetOrCreate();
|
||||
if (audioChannelService) {
|
||||
audioChannelService->RegisterSpeakerManager(this);
|
||||
}
|
||||
}
|
||||
|
||||
SpeakerManagerService::~SpeakerManagerService()
|
||||
{
|
||||
MOZ_COUNT_DTOR(SpeakerManagerService);
|
||||
}
|
||||
79
dom/speakermanager/SpeakerManagerService.h
Normal file
79
dom/speakermanager/SpeakerManagerService.h
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeakerManagerService_h__
|
||||
#define mozilla_dom_SpeakerManagerService_h__
|
||||
|
||||
#include "nsIObserver.h"
|
||||
#include "nsTArray.h"
|
||||
#include "SpeakerManager.h"
|
||||
#include "nsIAudioManager.h"
|
||||
#include "nsCheapSets.h"
|
||||
#include "nsHashKeys.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SpeakerManagerService : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
/*
|
||||
* Return null or instance which has been created.
|
||||
*/
|
||||
static SpeakerManagerService* GetSpeakerManagerService();
|
||||
/*
|
||||
* Return SpeakerManagerService instance.
|
||||
* If SpeakerManagerService is not exist, create and return new one.
|
||||
*/
|
||||
static SpeakerManagerService* GetOrCreateSpeakerManagerService();
|
||||
virtual void ForceSpeaker(bool aEnable, bool aVisible);
|
||||
virtual bool GetSpeakerStatus();
|
||||
virtual void SetAudioChannelActive(bool aIsActive);
|
||||
// Called by child
|
||||
void ForceSpeaker(bool enable, uint64_t aChildid);
|
||||
// Register the SpeakerManager to service for notify the speakerforcedchange event
|
||||
void RegisterSpeakerManager(SpeakerManager* aSpeakerManager)
|
||||
{
|
||||
mRegisteredSpeakerManagers.AppendElement(aSpeakerManager);
|
||||
}
|
||||
void UnRegisterSpeakerManager(SpeakerManager* aSpeakerManager)
|
||||
{
|
||||
mRegisteredSpeakerManagers.RemoveElement(aSpeakerManager);
|
||||
}
|
||||
|
||||
protected:
|
||||
SpeakerManagerService();
|
||||
|
||||
virtual ~SpeakerManagerService();
|
||||
// Notify to UA if device speaker status changed
|
||||
virtual void Notify();
|
||||
|
||||
void TurnOnSpeaker(bool aEnable);
|
||||
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
nsTArray<RefPtr<SpeakerManager> > mRegisteredSpeakerManagers;
|
||||
// Set for remember all the child speaker status
|
||||
nsCheapSet<nsUint64HashKey> mSpeakerStatusSet;
|
||||
// The Speaker status assign by UA
|
||||
bool mOrgSpeakerStatus;
|
||||
|
||||
bool mVisible;
|
||||
// This is needed for IPC communication between
|
||||
// SpeakerManagerServiceChild and this class.
|
||||
friend class ContentParent;
|
||||
friend class ContentChild;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
121
dom/speakermanager/SpeakerManagerServiceChild.cpp
Normal file
121
dom/speakermanager/SpeakerManagerServiceChild.cpp
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/* -*- 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 "SpeakerManagerServiceChild.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "AudioChannelService.h"
|
||||
#include <cutils/properties.h>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
StaticRefPtr<SpeakerManagerServiceChild> gSpeakerManagerServiceChild;
|
||||
|
||||
// static
|
||||
SpeakerManagerService*
|
||||
SpeakerManagerServiceChild::GetOrCreateSpeakerManagerService()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// If we already exist, exit early
|
||||
if (gSpeakerManagerServiceChild) {
|
||||
return gSpeakerManagerServiceChild;
|
||||
}
|
||||
|
||||
// Create new instance, register, return
|
||||
RefPtr<SpeakerManagerServiceChild> service = new SpeakerManagerServiceChild();
|
||||
|
||||
gSpeakerManagerServiceChild = service;
|
||||
|
||||
return gSpeakerManagerServiceChild;
|
||||
}
|
||||
|
||||
// static
|
||||
SpeakerManagerService*
|
||||
SpeakerManagerServiceChild::GetSpeakerManagerService()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
return gSpeakerManagerServiceChild;
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerServiceChild::ForceSpeaker(bool aEnable, bool aVisible)
|
||||
{
|
||||
mVisible = aVisible;
|
||||
mOrgSpeakerStatus = aEnable;
|
||||
ContentChild *cc = ContentChild::GetSingleton();
|
||||
if (cc) {
|
||||
cc->SendSpeakerManagerForceSpeaker(aEnable && aVisible);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
SpeakerManagerServiceChild::GetSpeakerStatus()
|
||||
{
|
||||
ContentChild *cc = ContentChild::GetSingleton();
|
||||
bool status = false;
|
||||
if (cc) {
|
||||
cc->SendSpeakerManagerGetSpeakerStatus(&status);
|
||||
}
|
||||
char propQemu[PROPERTY_VALUE_MAX];
|
||||
property_get("ro.kernel.qemu", propQemu, "");
|
||||
if (!strncmp(propQemu, "1", 1)) {
|
||||
return mOrgSpeakerStatus;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerServiceChild::Shutdown()
|
||||
{
|
||||
if (gSpeakerManagerServiceChild) {
|
||||
gSpeakerManagerServiceChild = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerServiceChild::SetAudioChannelActive(bool aIsActive)
|
||||
{
|
||||
// Content process and switch to background with no audio and speaker forced.
|
||||
// Then disable speaker
|
||||
for (uint32_t i = 0; i < mRegisteredSpeakerManagers.Length(); i++) {
|
||||
mRegisteredSpeakerManagers[i]->SetAudioChannelActive(aIsActive);
|
||||
}
|
||||
}
|
||||
|
||||
SpeakerManagerServiceChild::SpeakerManagerServiceChild()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
RefPtr<AudioChannelService> audioChannelService = AudioChannelService::GetOrCreate();
|
||||
if (audioChannelService) {
|
||||
audioChannelService->RegisterSpeakerManager(this);
|
||||
}
|
||||
MOZ_COUNT_CTOR(SpeakerManagerServiceChild);
|
||||
}
|
||||
|
||||
SpeakerManagerServiceChild::~SpeakerManagerServiceChild()
|
||||
{
|
||||
RefPtr<AudioChannelService> audioChannelService = AudioChannelService::GetOrCreate();
|
||||
if (audioChannelService) {
|
||||
audioChannelService->UnregisterSpeakerManager(this);
|
||||
}
|
||||
MOZ_COUNT_DTOR(SpeakerManagerServiceChild);
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerServiceChild::Notify()
|
||||
{
|
||||
for (uint32_t i = 0; i < mRegisteredSpeakerManagers.Length(); i++) {
|
||||
mRegisteredSpeakerManagers[i]->DispatchSimpleEvent(NS_LITERAL_STRING("speakerforcedchange"));
|
||||
}
|
||||
}
|
||||
44
dom/speakermanager/SpeakerManagerServiceChild.h
Normal file
44
dom/speakermanager/SpeakerManagerServiceChild.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
/* -*- 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/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeakerManagerServicechild_h__
|
||||
#define mozilla_dom_SpeakerManagerServicechild_h__
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "SpeakerManagerService.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
/* This class is used to do the IPC to enable/disable speaker status
|
||||
Also handle the application speaker competition problem
|
||||
*/
|
||||
class SpeakerManagerServiceChild : public SpeakerManagerService
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Return null or instance which has been created.
|
||||
*/
|
||||
static SpeakerManagerService* GetSpeakerManagerService();
|
||||
/*
|
||||
* Return SpeakerManagerServiceChild instance.
|
||||
* If SpeakerManagerServiceChild is not exist, create and return new one.
|
||||
*/
|
||||
static SpeakerManagerService* GetOrCreateSpeakerManagerService();
|
||||
static void Shutdown();
|
||||
virtual void ForceSpeaker(bool aEnable, bool aVisible) override;
|
||||
virtual bool GetSpeakerStatus() override;
|
||||
virtual void SetAudioChannelActive(bool aIsActive) override;
|
||||
virtual void Notify() override;
|
||||
protected:
|
||||
SpeakerManagerServiceChild();
|
||||
virtual ~SpeakerManagerServiceChild();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
||||
23
dom/speakermanager/moz.build
Normal file
23
dom/speakermanager/moz.build
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
|
||||
|
||||
EXPORTS += [
|
||||
'SpeakerManager.h',
|
||||
'SpeakerManagerService.h',
|
||||
'SpeakerManagerServiceChild.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'SpeakerManager.cpp',
|
||||
'SpeakerManagerService.cpp',
|
||||
'SpeakerManagerServiceChild.cpp',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
3
dom/speakermanager/tests/mochitest.ini
Normal file
3
dom/speakermanager/tests/mochitest.ini
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[DEFAULT]
|
||||
|
||||
[test_speakermanager.html]
|
||||
53
dom/speakermanager/tests/test_speakermanager.html
Normal file
53
dom/speakermanager/tests/test_speakermanager.html
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test MozSpeakerManager API</title>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
"use strict";
|
||||
|
||||
function testObject() {
|
||||
var mgr = new MozSpeakerManager();
|
||||
var spkforced = false;
|
||||
mgr.onspeakerforcedchange = function() {
|
||||
if (spkforced) {
|
||||
is(mgr.speakerforced, true, 'speaker should be true');
|
||||
spkforced = false;
|
||||
mgr.forcespeaker = false;
|
||||
} else {
|
||||
is(mgr.speakerforced, false, 'speaker should be false');
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
spkforced = true;
|
||||
mgr.forcespeaker = true;
|
||||
}
|
||||
|
||||
function startTests() {
|
||||
// Currently applicable only on FxOS
|
||||
if (navigator.userAgent.indexOf("Mobile") != -1 &&
|
||||
navigator.appVersion.indexOf("Android") == -1) {
|
||||
testObject();
|
||||
} else {
|
||||
ok(true, "MozSpeakerManager on Firefox OS only.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "speaker-control", "allow": 1, "context": document }],
|
||||
startTests);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue