Merge mozilla-central and b2g-inbound

This commit is contained in:
Ed Morley 2013-09-19 16:28:54 +01:00
commit 01d078a07c
24 changed files with 683 additions and 68 deletions

View File

@ -391,6 +391,9 @@ pref("dom.sms.strict7BitEncoding", false); // Disabled by default.
pref("dom.sms.requestStatusReport", true); // Enabled by default.
pref("dom.mms.requestStatusReport", true); // Enabled by default.
//The waiting time in network manager.
pref("network.gonk.ms-release-mms-connection", 30000);
// WebContacts
pref("dom.mozContacts.enabled", true);
pref("dom.navigator-property.disable.mozContacts", false);

View File

@ -1,4 +1,4 @@
{
"revision": "9bf9368a1110d6c365225593e0f145c343ea8cd8",
"revision": "ca3e0c37006fb38e756288cc87b67834ad88a9ad",
"repo_path": "/integration/gaia-central"
}

View File

@ -3811,8 +3811,13 @@ void HTMLMediaElement::UpdateAudioChannelPlayingState()
if (!mAudioChannelAgent) {
return;
}
nsCOMPtr<nsIDOMHTMLVideoElement> video = do_QueryObject(this);
// Use a weak ref so the audio channel agent can't leak |this|.
mAudioChannelAgent->InitWithWeakCallback(mAudioChannelType, this);
if (AUDIO_CHANNEL_NORMAL == mAudioChannelType && video) {
mAudioChannelAgent->InitWithVideo(mAudioChannelType, this, true);
} else {
mAudioChannelAgent->InitWithWeakCallback(mAudioChannelType, this);
}
mAudioChannelAgent->SetVisibilityState(!OwnerDoc()->Hidden());
}

View File

@ -22,6 +22,7 @@ AudioChannelAgent::AudioChannelAgent()
: mAudioChannelType(AUDIO_AGENT_CHANNEL_ERROR)
, mIsRegToService(false)
, mVisible(true)
, mWithVideo(false)
{
}
@ -54,10 +55,18 @@ AudioChannelAgent::InitWithWeakCallback(int32_t channelType,
return InitInternal(channelType, callback, /* useWeakRef = */ true);
}
NS_IMETHODIMP
AudioChannelAgent::InitWithVideo(int32_t channelType,
nsIAudioChannelAgentCallback *callback,
bool aUseWeakRef)
{
return InitInternal(channelType, callback, aUseWeakRef, true);
}
nsresult
AudioChannelAgent::InitInternal(int32_t aChannelType,
nsIAudioChannelAgentCallback *aCallback,
bool aUseWeakRef)
bool aUseWeakRef, bool aWithVideo)
{
// We syncd the enum of channel type between nsIAudioChannelAgent.idl and
// AudioChannelCommon.h the same.
@ -91,6 +100,8 @@ AudioChannelAgent::InitInternal(int32_t aChannelType,
mCallback = aCallback;
}
mWithVideo = aWithVideo;
return NS_OK;
}
@ -104,7 +115,7 @@ NS_IMETHODIMP AudioChannelAgent::StartPlaying(int32_t *_retval)
}
service->RegisterAudioChannelAgent(this,
static_cast<AudioChannelType>(mAudioChannelType));
static_cast<AudioChannelType>(mAudioChannelType), mWithVideo);
*_retval = service->GetState(this, !mVisible);
mIsRegToService = true;
return NS_OK;

View File

@ -41,13 +41,14 @@ private:
nsresult InitInternal(int32_t aAudioAgentType,
nsIAudioChannelAgentCallback* aCallback,
bool aUseWeakRef);
bool aUseWeakRef, bool aWithVideo=false);
nsCOMPtr<nsIAudioChannelAgentCallback> mCallback;
nsWeakPtr mWeakCallback;
int32_t mAudioChannelType;
bool mIsRegToService;
bool mVisible;
bool mWithVideo;
};
} // namespace dom

View File

@ -93,19 +93,21 @@ AudioChannelService::~AudioChannelService()
void
AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
AudioChannelType aType)
AudioChannelType aType,
bool aWithVideo)
{
MOZ_ASSERT(aType != AUDIO_CHANNEL_DEFAULT);
AudioChannelAgentData* data = new AudioChannelAgentData(aType,
true /* aElementHidden */,
AUDIO_CHANNEL_STATE_MUTED /* aState */);
AUDIO_CHANNEL_STATE_MUTED /* aState */,
aWithVideo);
mAgents.Put(aAgent, data);
RegisterType(aType, CONTENT_PROCESS_ID_MAIN);
RegisterType(aType, CONTENT_PROCESS_ID_MAIN, aWithVideo);
}
void
AudioChannelService::RegisterType(AudioChannelType aType, uint64_t aChildID)
AudioChannelService::RegisterType(AudioChannelType aType, uint64_t aChildID, bool aWithVideo)
{
AudioChannelInternalType type = GetInternalType(aType, true);
mChannelCounters[type].AppendElement(aChildID);
@ -116,7 +118,11 @@ AudioChannelService::RegisterType(AudioChannelType aType, uint64_t aChildID)
if (mDeferTelChannelTimer && aType == AUDIO_CHANNEL_TELEPHONY) {
mDeferTelChannelTimer->Cancel();
mDeferTelChannelTimer = nullptr;
UnregisterTypeInternal(aType, mTimerElementHidden, mTimerChildID);
UnregisterTypeInternal(aType, mTimerElementHidden, mTimerChildID, false);
}
if (aWithVideo) {
mWithVideoChildIDs.AppendElement(aChildID);
}
// In order to avoid race conditions, it's safer to notify any existing
@ -133,14 +139,16 @@ AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
mAgents.RemoveAndForget(aAgent, data);
if (data) {
UnregisterType(data->mType, data->mElementHidden, CONTENT_PROCESS_ID_MAIN);
UnregisterType(data->mType, data->mElementHidden,
CONTENT_PROCESS_ID_MAIN, data->mWithVideo);
}
}
void
AudioChannelService::UnregisterType(AudioChannelType aType,
bool aElementHidden,
uint64_t aChildID)
uint64_t aChildID,
bool aWithVideo)
{
// There are two reasons to defer the decrease of telephony channel.
// 1. User can have time to remove device from his ear before music resuming.
@ -156,13 +164,14 @@ AudioChannelService::UnregisterType(AudioChannelType aType,
return;
}
UnregisterTypeInternal(aType, aElementHidden, aChildID);
UnregisterTypeInternal(aType, aElementHidden, aChildID, aWithVideo);
}
void
AudioChannelService::UnregisterTypeInternal(AudioChannelType aType,
bool aElementHidden,
uint64_t aChildID)
uint64_t aChildID,
bool aWithVideo)
{
// The array may contain multiple occurrence of this appId but
// this should remove only the first one.
@ -181,6 +190,12 @@ AudioChannelService::UnregisterTypeInternal(AudioChannelType aType,
!mChannelCounters[AUDIO_CHANNEL_INT_CONTENT].Contains(aChildID)) {
mActiveContentChildIDs.RemoveElement(aChildID);
}
if (aWithVideo) {
MOZ_ASSERT(mWithVideoChildIDs.Contains(aChildID));
mWithVideoChildIDs.RemoveElement(aChildID);
}
SendAudioChannelChangedNotification(aChildID);
Notify();
}
@ -258,8 +273,19 @@ AudioChannelService::GetStateInternal(AudioChannelType aType, uint64_t aChildID,
mActiveContentChildIDs.RemoveElement(aChildID);
}
}
else if (newType == AUDIO_CHANNEL_INT_NORMAL &&
oldType == AUDIO_CHANNEL_INT_NORMAL_HIDDEN &&
mWithVideoChildIDs.Contains(aChildID)) {
if (mActiveContentChildIDsFrozen) {
mActiveContentChildIDsFrozen = false;
mActiveContentChildIDs.Clear();
}
}
if (newType != oldType && aType == AUDIO_CHANNEL_CONTENT) {
if (newType != oldType &&
(aType == AUDIO_CHANNEL_CONTENT ||
(aType == AUDIO_CHANNEL_NORMAL &&
mWithVideoChildIDs.Contains(aChildID)))) {
Notify();
}
@ -508,7 +534,7 @@ AudioChannelService::Notify()
NS_IMETHODIMP
AudioChannelService::Notify(nsITimer* aTimer)
{
UnregisterTypeInternal(AUDIO_CHANNEL_TELEPHONY, mTimerElementHidden, mTimerChildID);
UnregisterTypeInternal(AUDIO_CHANNEL_TELEPHONY, mTimerElementHidden, mTimerChildID, false);
mDeferTelChannelTimer = nullptr;
return NS_OK;
}
@ -569,6 +595,7 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const PR
return NS_OK;
}
int32_t index;
uint64_t childID = 0;
nsresult rv = props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"),
&childID);
@ -576,14 +603,17 @@ AudioChannelService::Observe(nsISupports* aSubject, const char* aTopic, const PR
for (int32_t type = AUDIO_CHANNEL_INT_NORMAL;
type < AUDIO_CHANNEL_INT_LAST;
++type) {
int32_t index;
while ((index = mChannelCounters[type].IndexOf(childID)) != -1) {
mChannelCounters[type].RemoveElementAt(index);
}
}
if ((index = mActiveContentChildIDs.IndexOf(childID)) != -1) {
mActiveContentChildIDs.RemoveElementAt(index);
}
while ((index = mActiveContentChildIDs.IndexOf(childID)) != -1) {
mActiveContentChildIDs.RemoveElementAt(index);
}
while ((index = mWithVideoChildIDs.IndexOf(childID)) != -1) {
mWithVideoChildIDs.RemoveElementAt(index);
}
// We don't have to remove the agents from the mAgents hashtable because if

View File

@ -46,7 +46,8 @@ public:
* this service, sharing the AudioChannelType.
*/
virtual void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
AudioChannelType aType);
AudioChannelType aType,
bool aWithVideo);
/**
* Any audio channel agent that stops playing should unregister itself to
@ -90,11 +91,11 @@ protected:
void SendAudioChannelChangedNotification(uint64_t aChildID);
/* Register/Unregister IPC types: */
void RegisterType(AudioChannelType aType, uint64_t aChildID);
void RegisterType(AudioChannelType aType, uint64_t aChildID, bool aWithVideo);
void UnregisterType(AudioChannelType aType, bool aElementHidden,
uint64_t aChildID);
uint64_t aChildID, bool aWithVideo);
void UnregisterTypeInternal(AudioChannelType aType, bool aElementHidden,
uint64_t aChildID);
uint64_t aChildID, bool aWithVideo);
AudioChannelState GetStateInternal(AudioChannelType aType, uint64_t aChildID,
bool aElementHidden,
@ -143,15 +144,18 @@ protected:
public:
AudioChannelAgentData(AudioChannelType aType,
bool aElementHidden,
AudioChannelState aState)
AudioChannelState aState,
bool aWithVideo)
: mType(aType)
, mElementHidden(aElementHidden)
, mState(aState)
, mWithVideo(aWithVideo)
{}
AudioChannelType mType;
bool mElementHidden;
AudioChannelState mState;
const bool mWithVideo;
};
static PLDHashOperator
@ -166,6 +170,7 @@ protected:
AudioChannelType mCurrentVisibleHigherChannel;
nsTArray<uint64_t> mActiveContentChildIDs;
nsTArray<uint64_t> mWithVideoChildIDs;
bool mActiveContentChildIDsFrozen;
nsCOMPtr<nsITimer> mDeferTelChannelTimer;

View File

@ -66,7 +66,6 @@ AudioChannelServiceChild::GetState(AudioChannelAgent* aAgent, bool aElementHidde
return AUDIO_CHANNEL_STATE_MUTED;
}
ContentChild *cc = ContentChild::GetSingleton();
AudioChannelState state = AUDIO_CHANNEL_STATE_MUTED;
bool oldElementHidden = data->mElementHidden;
@ -75,30 +74,24 @@ AudioChannelServiceChild::GetState(AudioChannelAgent* aAgent, bool aElementHidde
// Update visibility.
data->mElementHidden = aElementHidden;
if (cc) {
cc->SendAudioChannelGetState(data->mType, aElementHidden, oldElementHidden, &state);
}
ContentChild* cc = ContentChild::GetSingleton();
cc->SendAudioChannelGetState(data->mType, aElementHidden, oldElementHidden, &state);
data->mState = state;
if (cc) {
cc->SendAudioChannelChangedNotification();
}
cc->SendAudioChannelChangedNotification();
return state;
}
void
AudioChannelServiceChild::RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
AudioChannelType aType)
AudioChannelType aType,
bool aWithVideo)
{
MOZ_ASSERT(aType != AUDIO_CHANNEL_DEFAULT);
AudioChannelService::RegisterAudioChannelAgent(aAgent, aType);
AudioChannelService::RegisterAudioChannelAgent(aAgent, aType, aWithVideo);
ContentChild *cc = ContentChild::GetSingleton();
if (cc) {
cc->SendAudioChannelRegisterType(aType);
}
ContentChild::GetSingleton()->SendAudioChannelRegisterType(aType, aWithVideo);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {
@ -120,10 +113,8 @@ AudioChannelServiceChild::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent)
AudioChannelService::UnregisterAudioChannelAgent(aAgent);
ContentChild *cc = ContentChild::GetSingleton();
if (cc) {
cc->SendAudioChannelUnregisterType(data.mType, data.mElementHidden);
}
ContentChild::GetSingleton()->SendAudioChannelUnregisterType(
data.mType, data.mElementHidden, data.mWithVideo);
nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
if (obs) {

View File

@ -31,7 +31,8 @@ public:
static void Shutdown();
virtual void RegisterAudioChannelAgent(AudioChannelAgent* aAgent,
AudioChannelType aType);
AudioChannelType aType,
bool aWithVideo);
virtual void UnregisterAudioChannelAgent(AudioChannelAgent* aAgent);
/**

View File

@ -32,7 +32,7 @@ interface nsIAudioChannelAgentCallback : nsISupports
* 1. Changes to the playable status of this channel.
*/
[scriptable, uuid(7a4c0b06-63a4-11e2-8c1b-10bf48d64bd4)]
[scriptable, uuid(86ef883d-9cec-4c04-994f-5de198286e7c)]
interface nsIAudioChannelAgent : nsISupports
{
const long AUDIO_AGENT_CHANNEL_NORMAL = 0;
@ -78,6 +78,14 @@ interface nsIAudioChannelAgent : nsISupports
*/
void initWithWeakCallback(in long channelType, in nsIAudioChannelAgentCallback callback);
/**
* This method is just like init(), and specify the channel is associated with video.
*
* @param weak
* true if weak reference should be hold.
*/
void initWithVideo(in long channelType, in nsIAudioChannelAgentCallback callback, in boolean weak);
/**
* Notify the agent that we want to start playing.
* Note: Gecko component SHOULD call this function first then start to
@ -110,6 +118,5 @@ interface nsIAudioChannelAgent : nsISupports
* True if the window associated with the agent is visible.
*/
void setVisibilityState(in boolean visible);
};

View File

@ -0,0 +1,14 @@
[DEFAULT]
b2g = true
browser = false
; We don't support FM radio emulation yet, see bug 872417
qemu = false
[test_enable_disable.js]
[test_set_frequency.js]
[test_cancel_seek.js]
[test_one_seek_at_once.js]
[test_seek_up_and_down.js]
[test_bug862672.js]
[test_bug876597.js]

View File

@ -0,0 +1,53 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
SpecialPowers.addPermission("fmradio", true, document);
let FMRadio = window.navigator.mozFMRadio;
function verifyInitialState() {
log("Verifying initial state.");
ok(FMRadio);
is(FMRadio.enabled, false);
enableThenDisable();
}
function enableThenDisable() {
log("Enable FM Radio and disable it immediately.");
var frequency = FMRadio.frequencyLowerBound + FMRadio.channelWidth;
var request = FMRadio.enable(frequency);
ok(request);
var failedToEnable = false;
request.onerror = function() {
failedToEnable = true;
};
var enableCompleted = false;
request.onsuccess = function() {
ok(!failedToEnable);
enableCompleted = true;
};
var disableReq = FMRadio.disable();
ok(disableReq);
disableReq.onsuccess = function() {
// There are two possibilities which depends on the system
// process scheduling (bug 911063 comment 0):
// - enable fails
// - enable's onsuccess fires before disable's onsucess
ok(failedToEnable || enableCompleted);
ok(!FMRadio.enabled);
finish();
};
disableReq.onerror = function() {
ok(false, "Disable request should not fail.");
};
}
verifyInitialState();

View File

@ -0,0 +1,90 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
SpecialPowers.addPermission("fmradio", true, document);
SpecialPowers.addPermission("settings-read", true, document);
SpecialPowers.addPermission("settings-write", true, document);
let FMRadio = window.navigator.mozFMRadio;
let mozSettings = window.navigator.mozSettings;
let KEY = "ril.radio.disabled";
function verifyInitialState() {
log("Verifying initial state.");
ok(FMRadio);
is(FMRadio.enabled, false);
ok(mozSettings);
checkRilSettings();
}
function checkRilSettings() {
log("Checking airplane mode settings");
let req = mozSettings.createLock().get(KEY);
req.onsuccess = function(event) {
ok(!req.result[KEY], "Airplane mode is disabled.");
enableFMRadio();
};
req.onerror = function() {
ok(false, "Error occurs when reading settings value.");
finish();
};
}
function enableFMRadio() {
log("Enable FM radio");
let frequency = FMRadio.frequencyLowerBound + FMRadio.channelWidth;
let req = FMRadio.enable(frequency);
req.onsuccess = function() {
enableAirplaneMode();
};
req.onerror = function() {
ok(false, "Failed to enable FM radio.");
};
}
function enableAirplaneMode() {
log("Enable airplane mode");
FMRadio.ondisabled = function() {
FMRadio.ondisabled = null;
enableFMRadioWithAirplaneModeEnabled();
};
let settings = {};
settings[KEY] = true;
mozSettings.createLock().set(settings);
}
function enableFMRadioWithAirplaneModeEnabled() {
log("Enable FM radio with airplane mode enabled");
let frequency = FMRadio.frequencyLowerBound + FMRadio.channelWidth;
let req = FMRadio.enable(frequency);
req.onerror = cleanUp();
req.onsuccess = function() {
ok(false, "FMRadio could be enabled when airplane mode is enabled.");
};
}
function cleanUp() {
let settings = {};
settings[KEY] = false;
let req = mozSettings.createLock().set(settings);
req.onsuccess = function() {
ok(!FMRadio.enabled);
finish();
};
req.onerror = function() {
ok(false, "Error occurs when setting value");
};
}
verifyInitialState();

View File

@ -0,0 +1,69 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
SpecialPowers.addPermission("fmradio", true, document);
let FMRadio = window.navigator.mozFMRadio;
function verifyInitialState() {
log("Verifying initial state.");
ok(FMRadio);
is(FMRadio.enabled, false);
setUp();
}
function setUp() {
let frequency = FMRadio.frequencyLowerBound + FMRadio.channelWidth;
FMRadio.enable(frequency);
FMRadio.onenabled = seek;
}
function seek() {
log("Seek up");
var request = FMRadio.seekUp();
ok(request);
var seekUpIsCancelled = false;
request.onerror = function() {
seekUpIsCancelled = true;
};
var seekUpCompleted = false;
request.onsuccess = function() {
ok(!seekUpIsCancelled);
seekUpCompleted = true;
};
log("Seek up");
var cancelSeekReq = FMRadio.cancelSeek();
ok(cancelSeekReq);
// There are two possibilities which depends on the system
// process scheduling (bug 911063 comment 0):
// - seekup action is canceled
// - seekup's onsuccess fires before cancelSeek's onerror
cancelSeekReq.onsuccess = function() {
ok(seekUpIsCancelled, "Seekup request failed.");
cleanUp();
};
cancelSeekReq.onerror = function() {
ok(seekUpCompleted);
cleanUp();
};
}
function cleanUp() {
FMRadio.disable();
FMRadio.ondisabled = function() {
FMRadio.ondisabled = null;
ok(!FMRadio.enabled);
finish();
};
}
verifyInitialState();

View File

@ -0,0 +1,85 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
SpecialPowers.addPermission("fmradio", true, document);
let FMRadio = window.navigator.mozFMRadio;
function verifyInitialState() {
log("Verifying initial state.");
ok(FMRadio);
is(FMRadio.enabled, false);
log("Verifying attributes when disabled.");
is(FMRadio.frequency, null);
ok(FMRadio.frequencyLowerBound);
ok(FMRadio.frequencyUpperBound);
ok(FMRadio.frequencyUpperBound > FMRadio.frequencyLowerBound);
ok(FMRadio.channelWidth);
enableFMRadio();
}
function enableFMRadio() {
log("Verifying behaviors when enabled.");
var frequency = FMRadio.frequencyLowerBound + FMRadio.channelWidth;
var request = FMRadio.enable(frequency);
ok(request, "FMRadio.enable(r" + frequency + ") returns request");
request.onsuccess = function() {
ok(FMRadio.enabled);
ok(typeof FMRadio.frequency == "number");
ok(FMRadio.frequency > FMRadio.frequencyLowerBound);
};
request.onerror = function() {
ok(null, "Failed to enable");
};
var enabled = false;
FMRadio.onenabled = function() {
FMRadio.onenabled = null;
enabled = FMRadio.enabled;
};
FMRadio.onfrequencychange = function() {
log("Check if 'onfrequencychange' event is fired after the 'enabled' event");
FMRadio.onfrequencychange = null;
ok(enabled, "FMRadio is enabled when handling `onfrequencychange`");
disableFMRadio();
};
}
function disableFMRadio() {
log("Verify behaviors when disabled");
// There are two possibilities which depends on the system
// process scheduling (bug 911063 comment 0):
// - seek fails
// - seek's onsuccess fires before disable's onsucess
var seekRequest = FMRadio.seekUp();
var seekCompletes = false;
var failedToSeek = false;
seekRequest.onerror = function() {
ok(!seekCompletes);
failedToSeek = true;
};
seekRequest.onsuccess = function() {
ok(!failedToSeek);
seekCompletes = true;
};
FMRadio.disable();
FMRadio.ondisabled = function() {
FMRadio.ondisabled = null;
ok(seekCompletes || failedToSeek);
ok(!FMRadio.enabled);
finish();
};
}
verifyInitialState();

View File

@ -0,0 +1,73 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
SpecialPowers.addPermission("fmradio", true, document);
let FMRadio = window.navigator.mozFMRadio;
function verifyInitialState() {
log("Verifying initial state.");
ok(FMRadio);
is(FMRadio.enabled, false);
setUp();
}
function setUp() {
let frequency = FMRadio.frequencyLowerBound + FMRadio.channelWidth;
FMRadio.enable(frequency);
FMRadio.onenabled = seek;
}
function seek() {
var request = FMRadio.seekUp();
ok(request);
// There are two possibilities which depends on the system
// process scheduling (bug 911063 comment 0):
// - the second seek fails
// - both seeks are executed
request.onerror = function() {
ok(!firstSeekCompletes);
cleanUp();
};
var firstSeekCompletes = false;
request.onsuccess = function() {
firstSeekCompletes = true;
};
var seekAgainReq = FMRadio.seekUp();
ok(seekAgainReq);
seekAgainReq.onerror = function() {
log("Cancel the first seek to finish the test");
let cancelReq = FMRadio.cancelSeek();
ok(cancelReq);
// It's possible that the first seek completes when the
// cancel request is handled.
cancelReq.onerror = function() {
cleanUp();
};
};
seekAgainReq.onsuccess = function() {
ok(firstSeekCompletes);
cleanUp();
};
}
function cleanUp() {
FMRadio.disable();
FMRadio.ondisabled = function() {
FMRadio.ondisabled = null;
ok(!FMRadio.enabled);
finish();
};
}
verifyInitialState();

View File

@ -0,0 +1,61 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 30000;
SpecialPowers.addPermission("fmradio", true, document);
let FMRadio = window.navigator.mozFMRadio;
function verifyInitialState() {
log("Verifying initial state.");
ok(FMRadio);
is(FMRadio.enabled, false);
setUp();
}
function setUp() {
let frequency = FMRadio.frequencyLowerBound + FMRadio.channelWidth;
FMRadio.enable(frequency);
FMRadio.onenabled = seekUp;
}
function seekUp() {
log("Seek up");
var request = FMRadio.seekUp();
ok(request);
request.onsuccess = function() {
seekDown();
};
request.onerror = function() {
ok(false, "Seekup request should not fail.");
};
}
function seekDown() {
log("Seek down");
var request = FMRadio.seekDown();
ok(request);
request.onsuccess = function() {
cleanUp();
};
request.onerror = function() {
ok(false, "Seekdown request should not fail.");
};
}
function cleanUp() {
FMRadio.disable();
FMRadio.ondisabled = function() {
FMRadio.ondisabled = null;
ok(!FMRadio.enabled);
finish();
};
}
verifyInitialState();

View File

@ -0,0 +1,87 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
SpecialPowers.addPermission("fmradio", true, document);
let FMRadio = window.navigator.mozFMRadio;
function verifyInitialState() {
log("Verifying initial state.");
ok(FMRadio);
is(FMRadio.enabled, false);
setUp();
}
function setUp() {
let frequency = FMRadio.frequencyLowerBound + FMRadio.channelWidth;
FMRadio.enable(frequency);
FMRadio.onenabled = setFrequency;
}
function setFrequency() {
log("Set Frequency");
let frequency = FMRadio.frequency + FMRadio.channelWidth;
var request = FMRadio.setFrequency(frequency);
ok(request);
request.onsuccess = setOutOfRangeFrequency;
request.onerror = function() {
ok(false, "setFrequency request should not fail.");
};
}
function setOutOfRangeFrequency() {
log("Set Frequency that out of the range");
var request = FMRadio.setFrequency(FMRadio.frequencyUpperBound + 1);
ok(request);
request.onsuccess = function() {
ok(false, "The request of setting an out-of-range frequency should fail.");
};
request.onerror = setFrequencyWhenSeeking;
}
function setFrequencyWhenSeeking() {
log("Set frequency when seeking");
var request = FMRadio.seekUp();
ok(request);
// There are two possibilities which depends on the system
// process scheduling (bug 911063 comment 0):
// - seek fails
// - seek's onsuccess fires before setFrequency's onsucess
var failedToSeek = false;
request.onerror = function() {
failedToSeek = true;
};
var seekCompletes = false;
request.onsuccess = function() {
ok(!failedToSeek);
seekCompletes = true;
};
var frequency = FMRadio.frequencyUpperBound - FMRadio.channelWidth;
var setFreqRequest = FMRadio.setFrequency(frequency);
ok(setFreqRequest);
setFreqRequest.onsuccess = function() {
ok(failedToSeek || seekCompletes);
cleanUp();
};
}
function cleanUp() {
FMRadio.disable();
FMRadio.ondisabled = function() {
FMRadio.ondisabled = null;
ok(!FMRadio.enabled);
finish();
};
}
verifyInitialState();

View File

@ -1597,24 +1597,26 @@ ContentParent::RecvAudioChannelGetState(const AudioChannelType& aType,
}
bool
ContentParent::RecvAudioChannelRegisterType(const AudioChannelType& aType)
ContentParent::RecvAudioChannelRegisterType(const AudioChannelType& aType,
const bool& aWithVideo)
{
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetAudioChannelService();
if (service) {
service->RegisterType(aType, mChildID);
service->RegisterType(aType, mChildID, aWithVideo);
}
return true;
}
bool
ContentParent::RecvAudioChannelUnregisterType(const AudioChannelType& aType,
const bool& aElementHidden)
const bool& aElementHidden,
const bool& aWithVideo)
{
nsRefPtr<AudioChannelService> service =
AudioChannelService::GetAudioChannelService();
if (service) {
service->UnregisterType(aType, aElementHidden, mChildID);
service->UnregisterType(aType, aElementHidden, mChildID, aWithVideo);
}
return true;
}

View File

@ -420,9 +420,11 @@ private:
const bool& aElementWasHidden,
AudioChannelState* aValue);
virtual bool RecvAudioChannelRegisterType(const AudioChannelType& aType);
virtual bool RecvAudioChannelRegisterType(const AudioChannelType& aType,
const bool& aWithVideo);
virtual bool RecvAudioChannelUnregisterType(const AudioChannelType& aType,
const bool& aElementHidden);
const bool& aElementHidden,
const bool& aWithVideo);
virtual bool RecvAudioChannelChangedNotification();

View File

@ -442,9 +442,10 @@ parent:
bool aElementWasHidden)
returns (AudioChannelState value);
sync AudioChannelRegisterType(AudioChannelType aType);
sync AudioChannelRegisterType(AudioChannelType aType, bool aWithVideo);
sync AudioChannelUnregisterType(AudioChannelType aType,
bool aElementHidden);
bool aElementHidden,
bool aWithVideo);
async AudioChannelChangedNotification();
async AudioChannelChangeDefVolChannel(AudioChannelType aType,

View File

@ -332,28 +332,37 @@ TabChild::HandleEvent(nsIDOMEvent* aEvent)
if (!nsLayoutUtils::FindIDFor(content, &viewId))
return NS_ERROR_UNEXPECTED;
scrollFrame = nsLayoutUtils::FindScrollableFrameFor(viewId);
if (scrollFrame) {
CSSIntPoint scrollOffset = scrollFrame->GetScrollPositionCSSPixels();
// Note that we cannot use FindScrollableFrameFor(ROOT_SCROLL_ID) because
// it might return the root element from a different page in the case where
// that page is in the bfcache and this page is not run through layout
// before being drawn to the screen. Hence the code blocks below treat
// ROOT_SCROLL_ID separately from the non-ROOT_SCROLL_ID case.
CSSIntPoint scrollOffset;
if (viewId != FrameMetrics::ROOT_SCROLL_ID) {
scrollFrame = nsLayoutUtils::FindScrollableFrameFor(viewId);
if (!scrollFrame) {
return NS_OK;
}
scrollOffset = scrollFrame->GetScrollPositionCSSPixels();
} else {
// For the root frame, we store the last metrics, including the last
// scroll offset, sent by APZC. (This is updated in ProcessUpdateFrame()).
// We use this here to avoid sending APZC back a scroll event that
// originally came from APZC (besides being unnecessary, the event might
// be slightly out of date by the time it reaches APZC).
// We should probably do this for subframes, too.
if (viewId == FrameMetrics::ROOT_SCROLL_ID) {
if (RoundedToInt(mLastMetrics.mScrollOffset) == scrollOffset)
return NS_OK;
else
// Update the last scroll offset now, otherwise RecvUpdateDimensions()
// might trigger a scroll to the old offset before RecvUpdateFrame()
// gets a chance to update it.
mLastMetrics.mScrollOffset = scrollOffset;
utils->GetScrollXY(false, &scrollOffset.x, &scrollOffset.y);
if (RoundedToInt(mLastMetrics.mScrollOffset) == scrollOffset) {
return NS_OK;
}
SendUpdateScrollOffset(presShellId, viewId, scrollOffset);
// Update the last scroll offset now, otherwise RecvUpdateDimensions()
// might trigger a scroll to the old offset before RecvUpdateFrame()
// gets a chance to update it.
mLastMetrics.mScrollOffset = scrollOffset;
}
SendUpdateScrollOffset(presShellId, viewId, scrollOffset);
}
return NS_OK;

View File

@ -60,7 +60,8 @@ const CONFIG_SEND_REPORT_DEFAULT_YES = 2;
const CONFIG_SEND_REPORT_ALWAYS = 3;
const TIME_TO_BUFFER_MMS_REQUESTS = 30000;
const TIME_TO_RELEASE_MMS_CONNECTION = 30000;
const PREF_TIME_TO_RELEASE_MMS_CONNECTION =
Services.prefs.getIntPref("network.gonk.ms-release-mms-connection");
const PREF_RETRIEVAL_MODE = 'dom.mms.retrieval_mode';
const RETRIEVAL_MODE_MANUAL = "manual";
@ -293,11 +294,17 @@ XPCOMUtils.defineLazyGetter(this, "gMmsConnection", function () {
if (this.refCount <= 0) {
this.refCount = 0;
// The waiting is too small, just skip the timer creation.
if (PREF_TIME_TO_RELEASE_MMS_CONNECTION < 1000) {
this.onDisconnectTimerTimeout();
return;
}
// Set a timer to delay the release of MMS network connection,
// since the MMS requests often come consecutively in a short time.
this.disconnectTimer.
initWithCallback(this.onDisconnectTimerTimeout.bind(this),
TIME_TO_RELEASE_MMS_CONNECTION,
PREF_TIME_TO_RELEASE_MMS_CONNECTION,
Ci.nsITimer.TYPE_ONE_SHOT);
}
},

View File

@ -337,6 +337,7 @@ class MarionetteTestCase(CommonTestCase):
class MarionetteJSTestCase(CommonTestCase):
head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];")
context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];")
timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);")
inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);")
@ -376,6 +377,13 @@ class MarionetteJSTestCase(CommonTestCase):
else:
js += line
if os.path.basename(self.jsFile).startswith('test_'):
head_js = self.head_js_re.search(js);
if head_js:
head_js = head_js.group(3)
head = open(os.path.join(os.path.dirname(self.jsFile), head_js), 'r')
js = head.read() + js;
context = self.context_re.search(js)
if context:
context = context.group(3)