зеркало из https://github.com/mozilla/gecko-dev.git
Merge b2g-inbound to m-c
This commit is contained in:
Коммит
9d54e7a157
|
@ -66,7 +66,7 @@ PaymentUI.prototype = {
|
|||
// Once the user confirm the payment request and makes his choice, we get
|
||||
// back to the DOM part to get the appropriate payment flow information
|
||||
// based on the selected payment provider.
|
||||
content.addEventListener("mozContentEvent", function handleSelection(evt) {
|
||||
this._handleSelection = (function _handleSelection(evt) {
|
||||
let msg = evt.detail;
|
||||
if (msg.id != id) {
|
||||
return;
|
||||
|
@ -78,8 +78,10 @@ PaymentUI.prototype = {
|
|||
_error(msg.errorMsg);
|
||||
}
|
||||
|
||||
content.removeEventListener("mozContentEvent", handleSelection);
|
||||
});
|
||||
content.removeEventListener("mozContentEvent", this._handleSelection);
|
||||
this._handleSelection = null;
|
||||
}).bind(this);
|
||||
content.addEventListener("mozContentEvent", this._handleSelection);
|
||||
|
||||
browser.shell.sendChromeEvent(detail);
|
||||
},
|
||||
|
@ -114,21 +116,31 @@ PaymentUI.prototype = {
|
|||
// At some point the UI would send the created iframe back so the
|
||||
// callbacks for firing DOMRequest events can be loaded on its
|
||||
// content.
|
||||
content.addEventListener("mozContentEvent", (function loadPaymentShim(evt) {
|
||||
if (evt.detail.id != id) {
|
||||
content.removeEventListener("mozContentEvent", loadPaymentShim);
|
||||
this._loadPaymentShim = (function _loadPaymentShim(evt) {
|
||||
let msg = evt.detail;
|
||||
if (msg.id != id) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (msg.errorMsg) {
|
||||
content.removeEventListener("mozContentEvent", this._loadPaymentShim);
|
||||
this._loadPaymentShim = null;
|
||||
_error("ERROR_LOADING_PAYMENT_SHIM: " + msg.errorMsg);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!msg.frame) {
|
||||
content.removeEventListener("mozContentEvent", this._loadPaymentShim);
|
||||
this._loadPaymentShim = null;
|
||||
_error("ERROR_LOADING_PAYMENT_SHIM");
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to load the payment shim file containing the payment callbacks
|
||||
// in the content script.
|
||||
if (!evt.detail.frame && !evt.detail.errorMsg) {
|
||||
_error("ERROR_LOADING_PAYMENT_SHIM");
|
||||
return;
|
||||
}
|
||||
let frame = evt.detail.frame;
|
||||
let frame = msg.frame;
|
||||
let frameLoader = frame.QueryInterface(Ci.nsIFrameLoaderOwner)
|
||||
.frameLoader;
|
||||
.frameLoader;
|
||||
let mm = frameLoader.messageManager;
|
||||
try {
|
||||
mm.loadFrameScript(kPaymentShimFile, true);
|
||||
|
@ -140,25 +152,33 @@ PaymentUI.prototype = {
|
|||
}
|
||||
_error("ERROR_LOADING_PAYMENT_SHIM");
|
||||
} finally {
|
||||
content.removeEventListener("mozContentEvent", loadPaymentShim);
|
||||
content.removeEventListener("mozContentEvent", this._loadPaymentShim);
|
||||
this._loadPaymentShim = null;
|
||||
}
|
||||
}).bind(this));
|
||||
}).bind(this);
|
||||
content.addEventListener("mozContentEvent", this._loadPaymentShim);
|
||||
|
||||
// We also listen for UI notifications about a closed payment flow. The UI
|
||||
// should provide the reason of the closure within the 'errorMsg' parameter
|
||||
this._notifyPayFlowClosed = function _notifyPayFlowClosed (evt) {
|
||||
if (evt.detail.id != id) {
|
||||
this._notifyPayFlowClosed = (function _notifyPayFlowClosed(evt) {
|
||||
let msg = evt.detail;
|
||||
if (msg.id != id) {
|
||||
return;
|
||||
}
|
||||
if (evt.detail.errorMsg) {
|
||||
_error(evt.detail.errorMsg);
|
||||
content.removeEventListener("mozContentEvent",
|
||||
this._notifyPayFlowClosed);
|
||||
|
||||
if (msg.type != 'cancel') {
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
if (msg.errorMsg) {
|
||||
_error(msg.errorMsg);
|
||||
}
|
||||
content.removeEventListener("mozContentEvent",
|
||||
this._notifyPayFlowClosed);
|
||||
this._notifyPayFlowClosed = null;
|
||||
}).bind(this);
|
||||
content.addEventListener("mozContentEvent",
|
||||
this._notifyPayFlowClosed.bind(this));
|
||||
this._notifyPayFlowClosed);
|
||||
|
||||
browser.shell.sendChromeEvent(detail);
|
||||
},
|
||||
|
@ -169,7 +189,21 @@ PaymentUI.prototype = {
|
|||
if (!content) {
|
||||
return;
|
||||
}
|
||||
content.removeEventListener("mozContentEvent", this._notifyPayFlowClosed);
|
||||
|
||||
if (this._handleSelection) {
|
||||
content.removeEventListener("mozContentEvent", this._handleSelection);
|
||||
this._handleSelection = null;
|
||||
}
|
||||
|
||||
if (this._notifyPayFlowClosed) {
|
||||
content.removeEventListener("mozContentEvent", this._notifyPayFlowClosed);
|
||||
this._notifyPayFlowClosed = null;
|
||||
}
|
||||
|
||||
if (this._loadPaymentShim) {
|
||||
content.removeEventListener("mozContentEvent", this._loadPaymentShim);
|
||||
this._loadPaymentShim = null;
|
||||
}
|
||||
},
|
||||
|
||||
getRandomId: function getRandomId() {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"revision": "fefcf4aab784c6e9a0c8b3f4b282c21fb0e0ac6e",
|
||||
"revision": "70f416f866858cb2068bffa31118fc4b15b482c9",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
|
|
@ -712,6 +712,7 @@ GK_ATOM(onerror, "onerror")
|
|||
GK_ATOM(onfailed, "onfailed")
|
||||
GK_ATOM(onfocus, "onfocus")
|
||||
GK_ATOM(onfrequencychange, "onfrequencychange")
|
||||
GK_ATOM(onspeakerforcedchange, "onspeakerforcedchange")
|
||||
GK_ATOM(onget, "onget")
|
||||
GK_ATOM(ongroupchange, "ongroupchange")
|
||||
GK_ATOM(onhashchange, "onhashchange")
|
||||
|
|
|
@ -654,6 +654,11 @@ NON_IDL_EVENT(warning,
|
|||
EventNameType_None,
|
||||
NS_EVENT)
|
||||
|
||||
NON_IDL_EVENT(speakerforcedchange,
|
||||
NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE,
|
||||
EventNameType_None,
|
||||
NS_EVENT)
|
||||
|
||||
// Events that only have on* attributes on XUL elements
|
||||
NON_IDL_EVENT(text,
|
||||
NS_TEXT_TEXT,
|
||||
|
|
|
@ -313,6 +313,11 @@ this.PermissionsTable = { geolocation: {
|
|||
privileged: DENY_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
"speaker-control": {
|
||||
app: DENY_ACTION,
|
||||
privileged: ALLOW_ACTION,
|
||||
certified: ALLOW_ACTION
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "nsJSUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
#include "nsIAudioManager.h"
|
||||
#include "SpeakerManagerService.h"
|
||||
#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
|
||||
#endif
|
||||
|
||||
|
@ -170,6 +171,12 @@ AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
|
|||
UnregisterType(data->mType, data->mElementHidden,
|
||||
CONTENT_PROCESS_ID_MAIN, data->mWithVideo);
|
||||
}
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
bool active = AnyAudioChannelIsActive();
|
||||
for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
|
||||
mSpeakerManager[i]->SetAudioChannelActive(active);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -559,6 +566,19 @@ AudioChannelService::Notify(nsITimer* aTimer)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioChannelService::AnyAudioChannelIsActive()
|
||||
{
|
||||
for (int i = AUDIO_CHANNEL_INT_LAST - 1;
|
||||
i >= AUDIO_CHANNEL_INT_NORMAL; --i) {
|
||||
if (!mChannelCounters[i].IsEmpty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioChannelService::ChannelsActiveWithHigherPriorityThan(
|
||||
AudioChannelInternalType aType)
|
||||
|
|
|
@ -18,7 +18,9 @@
|
|||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
class SpeakerManagerService;
|
||||
#endif
|
||||
class AudioChannelService
|
||||
: public nsIObserver
|
||||
, public nsITimerCallback
|
||||
|
@ -81,6 +83,21 @@ public:
|
|||
virtual void SetDefaultVolumeControlChannel(AudioChannelType aType,
|
||||
bool aHidden);
|
||||
|
||||
bool AnyAudioChannelIsActive();
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
void RegisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
|
||||
{
|
||||
if (!mSpeakerManager.Contains(aSpeakerManager)) {
|
||||
mSpeakerManager.AppendElement(aSpeakerManager);
|
||||
}
|
||||
}
|
||||
|
||||
void UnregisterSpeakerManager(SpeakerManagerService* aSpeakerManager)
|
||||
{
|
||||
mSpeakerManager.RemoveElement(aSpeakerManager);
|
||||
}
|
||||
#endif
|
||||
protected:
|
||||
void Notify();
|
||||
|
||||
|
@ -163,7 +180,9 @@ protected:
|
|||
AudioChannelAgentData* aData, void *aUnused);
|
||||
|
||||
nsClassHashtable< nsPtrHashKey<AudioChannelAgent>, AudioChannelAgentData > mAgents;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsTArray<SpeakerManagerService*> mSpeakerManager;
|
||||
#endif
|
||||
nsTArray<uint64_t> mChannelCounters[AUDIO_CHANNEL_INT_LAST];
|
||||
|
||||
AudioChannelType mCurrentHigherChannel;
|
||||
|
|
|
@ -17,6 +17,10 @@
|
|||
#include "nsIObserverService.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "SpeakerManagerService.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
using namespace mozilla::hal;
|
||||
|
@ -120,6 +124,12 @@ AudioChannelServiceChild::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
|
|||
if (obs) {
|
||||
obs->NotifyObservers(nullptr, "audio-channel-agent-changed", nullptr);
|
||||
}
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
bool active = AnyAudioChannelIsActive();
|
||||
for (uint32_t i = 0; i < mSpeakerManager.Length(); i++) {
|
||||
mSpeakerManager[i]->SetAudioChannelActive(active);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -802,6 +802,11 @@ DOMInterfaces = {
|
|||
'nativeType': 'nsDOMAttributeMap',
|
||||
},
|
||||
|
||||
'MozSpeakerManager': {
|
||||
'nativeType': 'mozilla::dom::SpeakerManager',
|
||||
'headerFile': 'SpeakerManager.h'
|
||||
},
|
||||
|
||||
'MozPowerManager': {
|
||||
'nativeType': 'mozilla::dom::PowerManager',
|
||||
},
|
||||
|
|
|
@ -81,6 +81,7 @@
|
|||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include "nsVolume.h"
|
||||
#include "nsVolumeService.h"
|
||||
#include "SpeakerManagerService.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -586,6 +587,20 @@ ContentChild::RecvSetProcessPrivileges(const ChildPrivileges& aPrivs)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvSpeakerManagerNotify()
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsRefPtr<SpeakerManagerService> service =
|
||||
SpeakerManagerService::GetSpeakerManagerService();
|
||||
if (service) {
|
||||
service->Notify();
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
static CancelableTask* sFirstIdleTask;
|
||||
|
||||
static void FirstIdle(void)
|
||||
|
|
|
@ -178,6 +178,8 @@ public:
|
|||
|
||||
virtual bool RecvSetOffline(const bool& offline);
|
||||
|
||||
virtual bool RecvSpeakerManagerNotify();
|
||||
|
||||
virtual bool RecvNotifyVisited(const URIParams& aURI);
|
||||
// auto remove when alertfinished is received.
|
||||
nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsIVolume.h"
|
||||
#include "nsIVolumeService.h"
|
||||
#include "SpeakerManagerService.h"
|
||||
using namespace mozilla::system;
|
||||
#endif
|
||||
|
||||
|
@ -2478,6 +2479,35 @@ ContentParent::RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvSpeakerManagerGetSpeakerStatus(bool* aValue)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
*aValue = false;
|
||||
nsRefPtr<SpeakerManagerService> service =
|
||||
SpeakerManagerService::GetSpeakerManagerService();
|
||||
if (service) {
|
||||
*aValue = service->GetSpeakerStatus();
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvSpeakerManagerForceSpeaker(const bool& aEnable)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsRefPtr<SpeakerManagerService> service =
|
||||
SpeakerManagerService::GetSpeakerManagerService();
|
||||
if (service) {
|
||||
service->ForceSpeaker(aEnable, mChildID);
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvStartVisitedQuery(const URIParams& aURI)
|
||||
{
|
||||
|
@ -2800,6 +2830,8 @@ AddGeolocationListener(nsIDOMGeoPositionCallback* watcher, bool highAccuracy)
|
|||
}
|
||||
|
||||
PositionOptions* options = new PositionOptions();
|
||||
options->mTimeout = 0;
|
||||
options->mMaximumAge = 0;
|
||||
options->mEnableHighAccuracy = highAccuracy;
|
||||
int32_t retval = 1;
|
||||
geo->WatchPosition(watcher, nullptr, options, &retval);
|
||||
|
|
|
@ -474,6 +474,10 @@ private:
|
|||
|
||||
virtual bool RecvBroadcastVolume(const nsString& aVolumeName);
|
||||
|
||||
virtual bool RecvSpeakerManagerGetSpeakerStatus(bool* aValue);
|
||||
|
||||
virtual bool RecvSpeakerManagerForceSpeaker(const bool& aEnable);
|
||||
|
||||
virtual bool RecvSystemMessageHandled() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvNuwaReady() MOZ_OVERRIDE;
|
||||
|
|
|
@ -238,6 +238,8 @@ child:
|
|||
*/
|
||||
async AudioChannelNotify();
|
||||
|
||||
async SpeakerManagerNotify();
|
||||
|
||||
/**
|
||||
* Do a memory info dump to a file in our temp directory.
|
||||
*
|
||||
|
@ -247,7 +249,6 @@ child:
|
|||
async DumpMemoryInfoToTempDir(nsString identifier,
|
||||
bool minimizeMemoryUsage,
|
||||
bool dumpChildProcesses);
|
||||
|
||||
/**
|
||||
* Dump this process's GC and CC logs.
|
||||
*
|
||||
|
@ -471,6 +472,11 @@ parent:
|
|||
sync KeywordToURI(nsCString keyword)
|
||||
returns (OptionalInputStreamParams postData, OptionalURIParams uri);
|
||||
|
||||
sync SpeakerManagerForceSpeaker(bool aEnable);
|
||||
|
||||
sync SpeakerManagerGetSpeakerStatus()
|
||||
returns (bool value);
|
||||
|
||||
both:
|
||||
AsyncMessage(nsString aMessage, ClonedMessageData aData,
|
||||
CpowEntry[] aCpows, Principal aPrincipal);
|
||||
|
|
|
@ -1781,7 +1781,10 @@ MobileMessageDatabaseService.prototype = {
|
|||
forEachMatchedMmsDeliveryInfo:
|
||||
function forEachMatchedMmsDeliveryInfo(aDeliveryInfo, aNeedle, aCallback) {
|
||||
|
||||
let typedAddress = MMS.Address.resolveType(aNeedle);
|
||||
let typedAddress = {
|
||||
type: MMS.Address.resolveType(aNeedle),
|
||||
address: aNeedle
|
||||
};
|
||||
let normalizedAddress, parsedAddress;
|
||||
if (typedAddress.type === "PLMN") {
|
||||
normalizedAddress = PhoneNumberUtils.normalize(aNeedle, false);
|
||||
|
@ -1789,7 +1792,10 @@ MobileMessageDatabaseService.prototype = {
|
|||
}
|
||||
|
||||
for (let element of aDeliveryInfo) {
|
||||
let typedStoredAddress = MMS.Address.resolveType(element.receiver);
|
||||
let typedStoredAddress = {
|
||||
type: MMS.Address.resolveType(element.receiver),
|
||||
address: element.receiver
|
||||
};
|
||||
if (typedAddress.type !== typedStoredAddress.type) {
|
||||
// Not even my type. Skip.
|
||||
continue;
|
||||
|
|
|
@ -81,7 +81,10 @@ if CONFIG['OS_ARCH'] == 'WINNT':
|
|||
PARALLEL_DIRS += ['plugins/ipc/hangui']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
PARALLEL_DIRS += ['wifi']
|
||||
PARALLEL_DIRS += [
|
||||
'speakermanager',
|
||||
'wifi',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_B2G_RIL']:
|
||||
PARALLEL_DIRS += [
|
||||
|
|
|
@ -0,0 +1,219 @@
|
|||
/* 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 "nsIDOMEventListener.h"
|
||||
#include "SpeakerManagerService.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "AudioChannelService.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
NS_IMPL_QUERY_INTERFACE_INHERITED1(SpeakerManager, nsDOMEventTargetHelper,
|
||||
nsIDOMEventListener)
|
||||
NS_IMPL_ADDREF_INHERITED(SpeakerManager, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(SpeakerManager, nsDOMEventTargetHelper)
|
||||
|
||||
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<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::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<nsIDOMEvent> 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->IsOuterWindow() ?
|
||||
aWindow->GetCurrentInnerWindow() : aWindow);
|
||||
|
||||
mVisible = !GetOwner()->IsBackground();
|
||||
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 =
|
||||
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<SpeakerManager> object = new SpeakerManager();
|
||||
object->Init(ownerWindow);
|
||||
return object.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
SpeakerManager::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return MozSpeakerManagerBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
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::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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/* 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 "nsDOMEventTargetHelper.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 MOZ_FINAL
|
||||
: public nsDOMEventTargetHelper
|
||||
, public nsIDOMEventListener
|
||||
{
|
||||
friend class SpeakerManagerService;
|
||||
friend class SpeakerManagerServiceChild;
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMEVENTLISTENER
|
||||
|
||||
public:
|
||||
void Init(nsPIDOMWindow* aWindow);
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const;
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope) MOZ_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
|
|
@ -0,0 +1,199 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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/Util.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::GetSpeakerManagerService()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return SpeakerManagerServiceChild::GetSpeakerManagerService();
|
||||
}
|
||||
|
||||
// If we already exist, exit early
|
||||
if (gSpeakerManagerService) {
|
||||
return gSpeakerManagerService;
|
||||
}
|
||||
|
||||
// Create new instance, register, return
|
||||
nsRefPtr<SpeakerManagerService> service = new SpeakerManagerService();
|
||||
NS_ENSURE_TRUE(service, nullptr);
|
||||
|
||||
gSpeakerManagerService = service;
|
||||
return gSpeakerManagerService;
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerService::Shutdown()
|
||||
{
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return SpeakerManagerServiceChild::Shutdown();
|
||||
}
|
||||
|
||||
if (gSpeakerManagerService) {
|
||||
gSpeakerManagerService = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(SpeakerManagerService, nsIObserver)
|
||||
|
||||
void
|
||||
SpeakerManagerService::ForceSpeaker(bool aEnable, uint64_t aChildId)
|
||||
{
|
||||
TuruOnSpeaker(aEnable);
|
||||
if (aEnable) {
|
||||
mSpeakerStatusSet.Put(aChildId);
|
||||
}
|
||||
Notify();
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerService::ForceSpeaker(bool aEnable, bool aVisible)
|
||||
{
|
||||
// b2g main process without oop
|
||||
TuruOnSpeaker(aEnable && aVisible);
|
||||
mVisible = aVisible;
|
||||
mOrgSpeakerStatus = aEnable;
|
||||
Notify();
|
||||
}
|
||||
|
||||
void
|
||||
SpeakerManagerService::TuruOnSpeaker(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 PRUnichar* 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)) {
|
||||
TuruOnSpeaker(false);
|
||||
mSpeakerStatusSet.Remove(childID);
|
||||
}
|
||||
if (mOrgSpeakerStatus) {
|
||||
TuruOnSpeaker(!mOrgSpeakerStatus);
|
||||
mOrgSpeakerStatus = false;
|
||||
}
|
||||
} else {
|
||||
NS_WARNING("ipc:content-shutdown message without childID property");
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SpeakerManagerService::SpeakerManagerService()
|
||||
: mOrgSpeakerStatus(false),
|
||||
mVisible(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(SpeakerManagerService);
|
||||
if (XRE_GetProcessType() == GeckoProcessType_Default) {
|
||||
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->AddObserver(this, "ipc:content-shutdown", false);
|
||||
}
|
||||
}
|
||||
AudioChannelService* audioChannelService =
|
||||
AudioChannelService::GetAudioChannelService();
|
||||
if (audioChannelService) {
|
||||
audioChannelService->RegisterSpeakerManager(this);
|
||||
}
|
||||
}
|
||||
|
||||
SpeakerManagerService::~SpeakerManagerService()
|
||||
{
|
||||
MOZ_COUNT_DTOR(SpeakerManagerService);
|
||||
AudioChannelService* audioChannelService =
|
||||
AudioChannelService::GetAudioChannelService();
|
||||
if (audioChannelService)
|
||||
audioChannelService->UnregisterSpeakerManager(this);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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 "nsAutoPtr.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
|
||||
|
||||
static SpeakerManagerService* GetSpeakerManagerService();
|
||||
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);
|
||||
}
|
||||
/**
|
||||
* Shutdown the singleton.
|
||||
*/
|
||||
static void Shutdown();
|
||||
|
||||
protected:
|
||||
SpeakerManagerService();
|
||||
|
||||
virtual ~SpeakerManagerService();
|
||||
// Notify to UA if device speaker status changed
|
||||
virtual void Notify();
|
||||
|
||||
void TuruOnSpeaker(bool aEnable);
|
||||
|
||||
nsTArray<nsRefPtr<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
|
|
@ -0,0 +1,113 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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/Util.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::GetSpeakerManagerService()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// If we already exist, exit early
|
||||
if (gSpeakerManagerServiceChild) {
|
||||
return gSpeakerManagerServiceChild;
|
||||
}
|
||||
|
||||
// Create new instance, register, return
|
||||
nsRefPtr<SpeakerManagerServiceChild> service = new SpeakerManagerServiceChild();
|
||||
NS_ENSURE_TRUE(service, nullptr);
|
||||
|
||||
gSpeakerManagerServiceChild = service;
|
||||
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());
|
||||
AudioChannelService* audioChannelService = AudioChannelService::GetAudioChannelService();
|
||||
if (audioChannelService) {
|
||||
audioChannelService->RegisterSpeakerManager(this);
|
||||
}
|
||||
MOZ_COUNT_CTOR(SpeakerManagerServiceChild);
|
||||
}
|
||||
|
||||
SpeakerManagerServiceChild::~SpeakerManagerServiceChild()
|
||||
{
|
||||
AudioChannelService* audioChannelService = AudioChannelService::GetAudioChannelService();
|
||||
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"));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=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 "nsAutoPtr.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:
|
||||
static SpeakerManagerService* GetSpeakerManagerService();
|
||||
static void Shutdown();
|
||||
virtual void ForceSpeaker(bool aEnable, bool aVisible) MOZ_OVERRIDE;
|
||||
virtual bool GetSpeakerStatus() MOZ_OVERRIDE;
|
||||
virtual void SetAudioChannelActive(bool aIsActive) MOZ_OVERRIDE;
|
||||
virtual void Notify() MOZ_OVERRIDE;
|
||||
protected:
|
||||
SpeakerManagerServiceChild();
|
||||
virtual ~SpeakerManagerServiceChild();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# -*- Mode: python; c-basic-offset: 4; 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']
|
||||
|
||||
XPIDL_MODULE = 'dom_speakermanager'
|
||||
|
||||
EXPORTS += [
|
||||
'SpeakerManager.h',
|
||||
'SpeakerManagerService.h',
|
||||
'SpeakerManagerServiceChild.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'SpeakerManager.cpp',
|
||||
'SpeakerManagerService.cpp',
|
||||
'SpeakerManagerServiceChild.cpp',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'gklayout'
|
|
@ -0,0 +1,3 @@
|
|||
[DEFAULT]
|
||||
|
||||
[test_speakermanager.html]
|
|
@ -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, "mozAlarms on Firefox OS only.");
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPermissions(
|
||||
[{ "type": "speaker-control", "allow": 1, "context": document }],
|
||||
startTests);
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1613,12 +1613,6 @@ RadioInterface.prototype = {
|
|||
this.clientId, status);
|
||||
},
|
||||
|
||||
_isRadioChanging: function _isRadioChanging() {
|
||||
let state = this.rilContext.detailedRadioState;
|
||||
return state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING ||
|
||||
state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING;
|
||||
},
|
||||
|
||||
_convertRadioState: function _converRadioState(state) {
|
||||
switch (state) {
|
||||
case RIL.GECKO_RADIOSTATE_OFF:
|
||||
|
@ -1858,7 +1852,11 @@ RadioInterface.prototype = {
|
|||
if (DEBUG) this.debug("Don't connect data call when Wifi is connected.");
|
||||
return;
|
||||
}
|
||||
if (this._isRadioChanging()) {
|
||||
|
||||
let detailedRadioState = this.rilContext.detailedRadioState;
|
||||
if (gRadioEnabledController.isDeactivatingDataCalls() ||
|
||||
detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_ENABLING ||
|
||||
detailedRadioState == RIL.GECKO_DETAILED_RADIOSTATE_DISABLING) {
|
||||
// We're changing the radio power currently, ignore any changes.
|
||||
return;
|
||||
}
|
||||
|
@ -2065,7 +2063,7 @@ RadioInterface.prototype = {
|
|||
// At this point we could send a message to content to notify the user
|
||||
// that storing an incoming SMS failed, most likely due to a full disk.
|
||||
if (DEBUG) {
|
||||
this.debug("Could not store SMS " + message.id + ", error code " + rv);
|
||||
this.debug("Could not store SMS, error code " + rv);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -2075,8 +2073,8 @@ RadioInterface.prototype = {
|
|||
}.bind(this);
|
||||
|
||||
if (message.messageClass != RIL.GECKO_SMS_MESSAGE_CLASSES[RIL.PDU_DCS_MSG_CLASS_0]) {
|
||||
message.id = gMobileMessageDatabaseService.saveReceivedMessage(message,
|
||||
notifyReceived);
|
||||
gMobileMessageDatabaseService.saveReceivedMessage(message,
|
||||
notifyReceived);
|
||||
} else {
|
||||
message.id = -1;
|
||||
message.threadId = 0;
|
||||
|
@ -2638,18 +2636,15 @@ RadioInterface.prototype = {
|
|||
},
|
||||
|
||||
isValidStateForSetRadioEnabled: function() {
|
||||
let state = this.rilContext.radioState;
|
||||
|
||||
return !this._isRadioChanging() &&
|
||||
(state == RIL.GECKO_RADIOSTATE_READY ||
|
||||
state == RIL.GECKO_RADIOSTATE_OFF);
|
||||
let state = this.rilContext.detailedRadioState;
|
||||
return state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED ||
|
||||
state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED;
|
||||
},
|
||||
|
||||
isDummyForSetRadioEnabled: function(message) {
|
||||
let state = this.rilContext.radioState;
|
||||
|
||||
return (state == RIL.GECKO_RADIOSTATE_READY && message.enabled) ||
|
||||
(state == RIL.GECKO_RADIOSTATE_OFF && !message.enabled);
|
||||
let state = this.rilContext.detailedRadioState;
|
||||
return (state == RIL.GECKO_DETAILED_RADIOSTATE_ENABLED && message.enabled) ||
|
||||
(state == RIL.GECKO_DETAILED_RADIOSTATE_DISABLED && !message.enabled);
|
||||
},
|
||||
|
||||
setRadioEnabledResponse: function(target, message, errorMsg) {
|
||||
|
|
|
@ -374,6 +374,7 @@ var interfaceNamesInGlobalScope =
|
|||
"MozSmsFilter",
|
||||
"MozSmsMessage",
|
||||
"MozSmsSegmentInfo",
|
||||
{name: "MozSpeakerManager", b2g: true},
|
||||
{name: "MozStkCommandEvent", b2g: true, pref: "dom.icc.enabled"},
|
||||
{name: "MozTimeManager", b2g: true},
|
||||
{name: "MozVoicemail", b2g: true, pref: "dom.voicemail.enabled"},
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* 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/.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Allow application can control acoustic sound output through speaker.
|
||||
* Reference https://wiki.mozilla.org/WebAPI/SpeakerManager
|
||||
*/
|
||||
[Constructor()]
|
||||
interface MozSpeakerManager : EventTarget {
|
||||
/* query the speaker status */
|
||||
readonly attribute boolean speakerforced;
|
||||
/* force device device's acoustic sound output through speaker */
|
||||
attribute boolean forcespeaker;
|
||||
/* this event will be fired when device's speaker forced status change */
|
||||
attribute EventHandler onspeakerforcedchange;
|
||||
};
|
|
@ -532,6 +532,7 @@ if CONFIG['MOZ_NFC']:
|
|||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
|
||||
WEBIDL_FILES += [
|
||||
'MozSpeakerManager.webidl',
|
||||
'MozWifiConnectionInfoEvent.webidl',
|
||||
'MozWifiStatusChangeEvent.webidl',
|
||||
]
|
||||
|
|
|
@ -36,8 +36,8 @@ static int sRadioFD;
|
|||
static bool sRadioEnabled;
|
||||
static pthread_t sRadioThread;
|
||||
static hal::FMRadioSettings sRadioSettings;
|
||||
static int sTavaruaVersion;
|
||||
static bool sTavaruaMode;
|
||||
static int sMsmFMVersion;
|
||||
static bool sMsmFMMode;
|
||||
|
||||
static int
|
||||
setControl(uint32_t id, int32_t value)
|
||||
|
@ -69,12 +69,12 @@ public:
|
|||
|
||||
/* Runs on the radio thread */
|
||||
static void
|
||||
initTavaruaRadio(hal::FMRadioSettings &aInfo)
|
||||
initMsmFMRadio(hal::FMRadioSettings &aInfo)
|
||||
{
|
||||
mozilla::ScopedClose fd(sRadioFD);
|
||||
char version[64];
|
||||
int rc;
|
||||
snprintf(version, sizeof(version), "%d", sTavaruaVersion);
|
||||
snprintf(version, sizeof(version), "%d", sMsmFMVersion);
|
||||
property_set("hw.fm.version", version);
|
||||
|
||||
/* Set the mode for soc downloader */
|
||||
|
@ -199,9 +199,9 @@ initTavaruaRadio(hal::FMRadioSettings &aInfo)
|
|||
|
||||
/* Runs on the radio thread */
|
||||
static void *
|
||||
runTavaruaRadio(void *)
|
||||
runMsmFMRadio(void *)
|
||||
{
|
||||
initTavaruaRadio(sRadioSettings);
|
||||
initMsmFMRadio(sRadioSettings);
|
||||
if (!sRadioEnabled) {
|
||||
NS_DispatchToMainThread(new RadioUpdate(hal::FM_RADIO_OPERATION_ENABLE,
|
||||
hal::FM_RADIO_OPERATION_STATUS_FAIL));
|
||||
|
@ -275,7 +275,8 @@ EnableFMRadio(const hal::FMRadioSettings& aInfo)
|
|||
return;
|
||||
}
|
||||
|
||||
sTavaruaMode = !strcmp((char *)cap.driver, "radio-tavarua");
|
||||
sMsmFMMode = !strcmp((char *)cap.driver, "radio-tavarua") ||
|
||||
!strcmp((char *)cap.driver, "radio-iris");
|
||||
HAL_LOG(("Radio: %s (%s)\n", cap.driver, cap.card));
|
||||
|
||||
if (!(cap.capabilities & V4L2_CAP_RADIO)) {
|
||||
|
@ -289,10 +290,10 @@ EnableFMRadio(const hal::FMRadioSettings& aInfo)
|
|||
}
|
||||
sRadioSettings = aInfo;
|
||||
|
||||
if (sTavaruaMode) {
|
||||
if (sMsmFMMode) {
|
||||
sRadioFD = fd.forget();
|
||||
sTavaruaVersion = cap.version;
|
||||
pthread_create(&sRadioThread, nullptr, runTavaruaRadio, nullptr);
|
||||
sMsmFMVersion = cap.version;
|
||||
pthread_create(&sRadioThread, nullptr, runMsmFMRadio, nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -323,7 +324,7 @@ DisableFMRadio()
|
|||
|
||||
sRadioEnabled = false;
|
||||
|
||||
if (sTavaruaMode) {
|
||||
if (sMsmFMMode) {
|
||||
int rc = setControl(V4L2_CID_PRIVATE_TAVARUA_STATE, FM_OFF);
|
||||
if (rc < 0) {
|
||||
HAL_LOG(("Unable to turn off radio"));
|
||||
|
@ -355,7 +356,7 @@ FMRadioSeek(const hal::FMRadioSeekDirection& aDirection)
|
|||
#endif
|
||||
|
||||
int rc = ioctl(sRadioFD, VIDIOC_S_HW_FREQ_SEEK, &seek);
|
||||
if (sTavaruaMode && rc >= 0)
|
||||
if (sMsmFMMode && rc >= 0)
|
||||
return;
|
||||
|
||||
hal::FMRadioOperationInformation info;
|
||||
|
@ -403,7 +404,7 @@ SetFMRadioFrequency(const uint32_t frequency)
|
|||
if (rc < 0)
|
||||
HAL_LOG(("Could not set radio frequency"));
|
||||
|
||||
if (sTavaruaMode && rc >= 0)
|
||||
if (sMsmFMMode && rc >= 0)
|
||||
return;
|
||||
|
||||
hal::FMRadioOperationInformation info;
|
||||
|
|
|
@ -186,6 +186,14 @@ PollSensors()
|
|||
if (buffer[i].type == SENSOR_TYPE_MAGNETIC_FIELD)
|
||||
continue;
|
||||
|
||||
// Bug 938035, transfer HAL data for orientation sensor to meet w3c spec
|
||||
// ex: HAL report alpha=90 means East but alpha=90 means West in w3c spec
|
||||
if (buffer[i].type == SENSOR_TYPE_ORIENTATION) {
|
||||
buffer[i].orientation.azimuth = 360 - buffer[i].orientation.azimuth;
|
||||
buffer[i].orientation.pitch = -buffer[i].orientation.pitch;
|
||||
buffer[i].orientation.roll = -buffer[i].orientation.roll;
|
||||
}
|
||||
|
||||
if (HardwareSensorToHalSensor(buffer[i].type) == SENSOR_UNKNOWN) {
|
||||
// Emulator is broken and gives us events without types set
|
||||
int index;
|
||||
|
|
|
@ -78,6 +78,7 @@ LOCAL_INCLUDES += -I$(srcdir)/../base \
|
|||
-I$(topsrcdir)/dom/audiochannel \
|
||||
-I$(topsrcdir)/dom/telephony \
|
||||
-I$(topsrcdir)/dom/media \
|
||||
-I$(topsrcdir)/dom/speakermanager \
|
||||
-I. \
|
||||
-I$(topsrcdir)/editor/libeditor/base \
|
||||
-I$(topsrcdir)/editor/libeditor/text \
|
||||
|
@ -100,6 +101,7 @@ endif
|
|||
|
||||
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/system/gonk
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/speakermanager
|
||||
endif #}
|
||||
|
||||
ifdef MOZ_B2G_FM #{
|
||||
|
|
|
@ -100,6 +100,7 @@
|
|||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#include "nsVolumeService.h"
|
||||
#include "SpeakerManagerService.h"
|
||||
using namespace mozilla::system;
|
||||
#endif
|
||||
|
||||
|
@ -372,6 +373,7 @@ nsLayoutStatics::Shutdown()
|
|||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
nsVolumeService::Shutdown();
|
||||
SpeakerManagerService::Shutdown();
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
|
|
|
@ -460,6 +460,10 @@ enum nsEventStructType
|
|||
#define NS_MEDIARECORDER_WARNING (NS_MEDIARECORDER_EVENT_START + 2)
|
||||
#define NS_MEDIARECORDER_STOP (NS_MEDIARECORDER_EVENT_START + 3)
|
||||
|
||||
// SpeakerManager events
|
||||
#define NS_SPEAKERMANAGER_EVENT_START 5800
|
||||
#define NS_SPEAKERMANAGER_SPEAKERFORCEDCHANGE (NS_SPEAKERMANAGER_EVENT_START + 1)
|
||||
|
||||
#ifdef MOZ_GAMEPAD
|
||||
// Gamepad input events
|
||||
#define NS_GAMEPAD_START 6000
|
||||
|
|
|
@ -312,7 +312,14 @@ nsAppShell::ProcessNextNativeEvent(bool mayWait)
|
|||
mozilla::hal::SensorType type = (mozilla::hal::SensorType) curEvent->Flags();
|
||||
|
||||
switch (type) {
|
||||
// Bug 938035, transfer HAL data for orientation sensor to meet w3c
|
||||
// spec, ex: HAL report alpha=90 means East but alpha=90 means West
|
||||
// in w3c spec
|
||||
case hal::SENSOR_ORIENTATION:
|
||||
values.AppendElement(360 -curEvent->X());
|
||||
values.AppendElement(-curEvent->Y());
|
||||
values.AppendElement(-curEvent->Z());
|
||||
break;
|
||||
case hal::SENSOR_LINEAR_ACCELERATION:
|
||||
case hal::SENSOR_ACCELERATION:
|
||||
case hal::SENSOR_GYROSCOPE:
|
||||
|
|
Загрузка…
Ссылка в новой задаче