Merge m-c to inbound a=merge

This commit is contained in:
Wes Kocher 2014-10-13 19:02:56 -07:00
commit 329a0340a9
79 changed files with 1126 additions and 581 deletions

View File

@ -104,3 +104,4 @@ cfde3603b0206e119abea76fdd6e134b634348f1 FIREFOX_AURORA_31_BASE
16f3cac5e8fe471e12f76d6a94a477b14e78df7c FIREFOX_AURORA_32_BASE
dc23164ba2a289a8b22902e30990c77d9677c214 FIREFOX_AURORA_33_BASE
c360f3d1c00d73b0c1fb0a2c0da525cb55e58b83 FIREFOX_AURORA_34_BASE
cec1a116c4f9a3e887d52e9a26e8bbec200fe162 FIREFOX_AURORA_35_BASE

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1080922 - Removal of a test manifest that the build system isn't picking up.
Merge day clobber

View File

@ -5,7 +5,7 @@ support-files =
event/**
fixtures/**
loader/**
libs/**
lib/**
modules/**
private-browsing/**
sidebar/**

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
@ -134,7 +134,7 @@
<project name="platform_external_qemu" path="external/qemu" remote="b2g" revision="d259117b4976decbe2f76eeed85218bf0109190f"/>
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="9f28c4faea3b2f01db227b2467b08aeba96d9bec"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/>
<project name="android-sdk" path="sdk" remote="b2g" revision="8b1365af38c9a653df97349ee53a3f5d64fd590a"/>
<project name="darwinstreamingserver" path="system/darwinstreamingserver" remote="b2g" revision="cf85968c7f85e0ec36e72c87ceb4837a943b8af6"/>
</manifest>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="cd88d860656c31c7da7bb310d6a160d0011b0961"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="3a2947df41a480de1457a6dcdbf46ad0af70d8e0">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
@ -151,7 +151,7 @@
<project name="platform/hardware/ril" path="hardware/ril" revision="12b1977cc704b35f2e9db2bb423fa405348bc2f3"/>
<project name="platform/system/bluetooth" path="system/bluetooth" revision="985bf15264d865fe7b9c5b45f61c451cbaafa43d"/>
<project name="platform/system/core" path="system/core" revision="350eac5403124dacb2a5fd9e28ac290a59fc3b8e"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/>
<project name="platform/system/qcom" path="system/qcom" revision="63e3f6f176caad587d42bba4c16b66d953fb23c2"/>
<project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="d8952a42771045fca73ec600e2b42a4c7129d723"/>
<project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="7704e16da545f4207812e593743d6743e1afb9c5"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
@ -145,7 +145,7 @@
<project name="platform/hardware/ril" path="hardware/ril" revision="c4e2ac95907a5519a0e09f01a0d8e27fec101af0"/>
<project name="platform/system/bluetooth" path="system/bluetooth" revision="e1eb226fa3ad3874ea7b63c56a9dc7012d7ff3c2"/>
<project name="platform/system/core" path="system/core" revision="adc485d8755af6a61641d197de7cfef667722580"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/>
<project name="platform/system/qcom" path="system/qcom" revision="1cdab258b15258b7f9657da70e6f06ebd5a2fc25"/>
<project name="platform/vendor/qcom/msm8610" path="device/qcom/msm8610" revision="4ae5df252123591d5b941191790e7abed1bce5a4"/>
<project name="platform/vendor/qcom-opensource/wlan/prima" path="vendor/qcom/opensource/wlan/prima" revision="ce18b47b4a4f93a581d672bbd5cb6d12fe796ca9"/>

View File

@ -4,6 +4,6 @@
"remote": "",
"branch": ""
},
"revision": "69b4d72a6b80008de044e535d9ff785631bd7f2b",
"revision": "291b607f32e6173d8fe225c644cc7397cdf82fa5",
"repo_path": "/integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -15,7 +15,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="562d357b72279a9e35d4af5aeecc8e1ffa2f44f1"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="6ca2008ac50b163d31244ef9f036cb224f4f229b"/>
@ -129,7 +129,7 @@
<project name="device-mako" path="device/lge/mako" remote="b2g" revision="78d17f0c117f0c66dd55ee8d5c5dde8ccc93ecba"/>
<project name="device/generic/armv7-a-neon" path="device/generic/armv7-a-neon" revision="3a9a17613cc685aa232432566ad6cc607eab4ec1"/>
<project name="device/lge/mako-kernel" path="device/lge/mako-kernel" revision="d1729e53d71d711c8fde25eab8728ff2b9b4df0e"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="cf9376f0f59ca72333dd24a54efe887d527da612"/>
<project name="platform_system_nfcd" path="system/nfcd" remote="b2g" revision="85e864c4abc80e08bc82f0ac53c042e0d27839b0"/>
<project name="platform/external/libnfc-nci" path="external/libnfc-nci" revision="7d33aaf740bbf6c7c6e9c34a92b371eda311b66b"/>
<project name="platform/external/wpa_supplicant_8" path="external/wpa_supplicant_8" revision="0e56e450367cd802241b27164a2979188242b95f"/>
<project name="platform/hardware/broadcom/wlan" path="hardware/broadcom/wlan" revision="0e1929fa3aa38bf9d40e9e953d619fab8164c82e"/>

View File

@ -17,7 +17,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="2a536e4df82410178d8440cc710d8f838a95a0b9"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="4f86c631e0465c0e56ccebeb1324fd28be9ea32f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="cc1f362ce43dce92ac786187ff4abf39060094bd"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="891e5069c0ad330d8191bf8c7b879c814258c89f"/>

View File

@ -5,7 +5,7 @@
MOZ_APP_BASENAME=B2G
MOZ_APP_VENDOR=Mozilla
MOZ_APP_VERSION=35.0a1
MOZ_APP_VERSION=36.0a1
MOZ_APP_UA_NAME=Firefox
MOZ_UA_OS_AGNOSTIC=1

View File

@ -1552,7 +1552,7 @@ pref("browser.newtabpage.rows", 3);
pref("browser.newtabpage.columns", 5);
// directory tiles download URL
pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v2/links/fetch");
pref("browser.newtabpage.directory.source", "https://tiles.services.mozilla.com/v2/links/fetch/%LOCALE%");
// endpoint to send newtab click and view pings
pref("browser.newtabpage.directory.ping", "https://tiles.services.mozilla.com/v2/links/");

View File

@ -61,6 +61,10 @@ input[type=button] {
right: auto;
}
#newtab-scrollbox[page-disabled] #newtab-intro-what {
display: none;
}
#newtab-intro-panel {
color: #6a7b86;
font-size: 15px;

View File

@ -391,7 +391,8 @@ loop.conversation = (function(mozL10n) {
if (progressData.state !== "terminated")
return;
if (progressData.reason === "cancel") {
if (progressData.reason === "cancel" ||
progressData.reason === "closed") {
this._abortIncomingCall();
return;
}

View File

@ -391,7 +391,8 @@ loop.conversation = (function(mozL10n) {
if (progressData.state !== "terminated")
return;
if (progressData.reason === "cancel") {
if (progressData.reason === "cancel" ||
progressData.reason === "closed") {
this._abortIncomingCall();
return;
}

View File

@ -23,6 +23,9 @@ body,
background: #fff;
border: 1px solid #E7E7E7;
box-shadow: 0px 2px 0px rgba(0, 0, 0, 0.03);
background-image: url("../shared/img/beta-ribbon.svg#beta-ribbon");
background-size: 5rem 5rem;
background-repeat: no-repeat;
}
.header-box {

View File

@ -283,7 +283,11 @@ loop.webapp = (function($, _, OT, mozL10n) {
},
render: function() {
var callState = mozL10n.get("call_progress_" + this.state.callState + "_description");
var callStateStringEntityName = "call_progress_" + this.state.callState + "_description";
var callState = mozL10n.get(callStateStringEntityName);
document.title = mozL10n.get("standalone_title_with_status",
{clientShortname: mozL10n.get("clientShortname2"),
currentStatus: mozL10n.get(callStateStringEntityName)});
return (
React.DOM.div({className: "container"},
React.DOM.div({className: "container-box"},
@ -519,6 +523,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
},
render: function() {
document.title = mozL10n.get("standalone_title_with_status",
{clientShortname: mozL10n.get("clientShortname2"),
currentStatus: mozL10n.get("status_conversation_ended")});
return (
React.DOM.div({className: "ended-conversation"},
sharedViews.FeedbackView({
@ -539,6 +546,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
var StartConversationView = React.createClass({displayName: 'StartConversationView',
render: function() {
document.title = mozL10n.get("clientShortname2");
return this.transferPropsTo(
InitiateConversationView({
title: mozL10n.get("initiate_call_button_label2"),
@ -549,6 +557,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
var FailedConversationView = React.createClass({displayName: 'FailedConversationView',
render: function() {
document.title = mozL10n.get("standalone_title_with_status",
{clientShortname: mozL10n.get("clientShortname2"),
currentStatus: mozL10n.get("status_error")});
return this.transferPropsTo(
InitiateConversationView({
title: mozL10n.get("call_failed_title"),
@ -636,6 +647,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
return PendingConversationView({websocket: this._websocket});
}
case "connected": {
document.title = mozL10n.get("standalone_title_with_status",
{clientShortname: mozL10n.get("clientShortname2"),
currentStatus: mozL10n.get("status_in_conversation")});
return (
sharedViews.ConversationView({
initiate: true,

View File

@ -283,7 +283,11 @@ loop.webapp = (function($, _, OT, mozL10n) {
},
render: function() {
var callState = mozL10n.get("call_progress_" + this.state.callState + "_description");
var callStateStringEntityName = "call_progress_" + this.state.callState + "_description";
var callState = mozL10n.get(callStateStringEntityName);
document.title = mozL10n.get("standalone_title_with_status",
{clientShortname: mozL10n.get("clientShortname2"),
currentStatus: mozL10n.get(callStateStringEntityName)});
return (
<div className="container">
<div className="container-box">
@ -519,6 +523,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
},
render: function() {
document.title = mozL10n.get("standalone_title_with_status",
{clientShortname: mozL10n.get("clientShortname2"),
currentStatus: mozL10n.get("status_conversation_ended")});
return (
<div className="ended-conversation">
<sharedViews.FeedbackView
@ -539,6 +546,7 @@ loop.webapp = (function($, _, OT, mozL10n) {
var StartConversationView = React.createClass({
render: function() {
document.title = mozL10n.get("clientShortname2");
return this.transferPropsTo(
<InitiateConversationView
title={mozL10n.get("initiate_call_button_label2")}
@ -549,6 +557,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
var FailedConversationView = React.createClass({
render: function() {
document.title = mozL10n.get("standalone_title_with_status",
{clientShortname: mozL10n.get("clientShortname2"),
currentStatus: mozL10n.get("status_error")});
return this.transferPropsTo(
<InitiateConversationView
title={mozL10n.get("call_failed_title")}
@ -636,6 +647,9 @@ loop.webapp = (function($, _, OT, mozL10n) {
return <PendingConversationView websocket={this._websocket} />;
}
case "connected": {
document.title = mozL10n.get("standalone_title_with_status",
{clientShortname: mozL10n.get("clientShortname2"),
currentStatus: mozL10n.get("status_in_conversation")});
return (
<sharedViews.ConversationView
initiate={true}

View File

@ -119,3 +119,12 @@ rooms_room_join_label=Join the conversation
brand_website=https://www.mozilla.org/firefox/
privacy_website=https://www.mozilla.org/privacy/
legal_website=/legal/terms/
## LOCALIZATION_NOTE(standalone_title_with_status): {{clientShortname}} will be
## replaced by the brand name and {{currentStatus}} will be replaced
## by the current call status (Connecting, Ringing, etc.)
standalone_title_with_status={{clientShortname}} — {{currentStatus}}
status_in_conversation=In conversation
status_conversation_ended=Conversation ended
status_error=Something went wrong

View File

@ -406,6 +406,46 @@ describe("loop.conversation", function() {
});
});
describe("progress - terminated - closed", function() {
it("should stop alerting", function(done) {
promise.then(function() {
icView._websocket.trigger("progress", {
state: "terminated",
reason: "closed"
});
sinon.assert.calledOnce(navigator.mozLoop.stopAlerting);
done();
});
});
it("should close the websocket", function(done) {
promise.then(function() {
icView._websocket.trigger("progress", {
state: "terminated",
reason: "closed"
});
sinon.assert.calledOnce(icView._websocket.close);
done();
});
});
it("should close the window", function(done) {
promise.then(function() {
icView._websocket.trigger("progress", {
state: "terminated",
reason: "closed"
});
sandbox.clock.tick(1);
sinon.assert.calledOnce(window.close);
done();
});
});
});
describe("progress - terminated - timeout (previousState = alerting)", function() {
it("should stop alerting", function(done) {
promise.then(function() {

View File

@ -1,45 +0,0 @@
/* 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/. */
"use strict";
this.EXPORTED_SYMBOLS = ["RevivableWindows"];
// List of closed windows that we can revive when closing
// windows in succession until the browser quits.
let closedWindows = [];
/**
* This module keeps track of closed windows that are revivable. On Windows
* and Linux we can revive windows before saving to disk - i.e. moving them
* from state._closedWindows[] to state.windows[] so that they're opened
* automatically on next startup. This feature lets us properly support
* closing windows in succession until the browser quits.
*
* The length of the list is not capped by max_undo_windows unlike
* state._closedWindows[].
*/
this.RevivableWindows = Object.freeze({
// Returns whether there are windows to revive.
get isEmpty() {
return closedWindows.length == 0;
},
// Add a window to the list.
add(winState) {
#ifndef XP_MACOSX
closedWindows.push(winState);
#endif
},
// Get the list of revivable windows.
get() {
return [...closedWindows];
},
// Clear the list of revivable windows.
clear() {
closedWindows.length = 0;
}
});

View File

@ -19,8 +19,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/devtools/Console.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivacyFilter",
"resource:///modules/sessionstore/PrivacyFilter.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RevivableWindows",
"resource:///modules/sessionstore/RevivableWindows.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionStore",
"resource:///modules/sessionstore/SessionStore.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "SessionFile",
@ -207,24 +205,23 @@ let SessionSaverInternal = {
delete state.deferredInitialState;
}
// We want to revive closed windows that have been closed in succession
// without any user action in between closing those. This happens here in
// the SessionSaver because we only want to revive when saving to disk.
// On Mac OS X this list will always be empty.
let windowsToRevive = RevivableWindows.get();
state.windows.unshift(...windowsToRevive);
let revivedWindows = state._closedWindows.splice(0, windowsToRevive.length);
#ifdef DEBUG
// Check that the windows to revive equal the windows
// that we removed from the list of closed windows.
let match = revivedWindows.every((win, idx) => {
return win == windowsToRevive[windowsToRevive.length - 1 - idx];
});
#ifndef XP_MACOSX
// We want to restore closed windows that are marked with _shouldRestore.
// We're doing this here because we want to control this only when saving
// the file.
while (state._closedWindows.length) {
let i = state._closedWindows.length - 1;
if (!match) {
throw new Error("SessionStore: revived windows didn't match closed windows");
if (!state._closedWindows[i]._shouldRestore) {
// We only need to go until _shouldRestore
// is falsy since we're going in reverse.
break;
}
delete state._closedWindows[i]._shouldRestore;
state.windows.unshift(state._closedWindows.pop());
}
#endif DEBUG
#endif
stopWatchFinish("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS");
return this._writeState(state);

View File

@ -107,8 +107,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "GlobalState",
"resource:///modules/sessionstore/GlobalState.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "PrivacyFilter",
"resource:///modules/sessionstore/PrivacyFilter.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RevivableWindows",
"resource:///modules/sessionstore/RevivableWindows.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "RunState",
"resource:///modules/sessionstore/RunState.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager",
@ -703,9 +701,7 @@ let SessionStoreInternal = {
this.saveStateDelayed(win);
break;
}
// Any event handled here indicates a user action.
RevivableWindows.clear();
this._clearRestoringWindows();
},
/**
@ -1017,6 +1013,12 @@ let SessionStoreInternal = {
SessionCookies.update([winData]);
}
#ifndef XP_MACOSX
// Until we decide otherwise elsewhere, this window is part of a series
// of closing windows to quit.
winData._shouldRestore = true;
#endif
// Store the window's close date to figure out when each individual tab
// was closed. This timestamp should allow re-arranging data based on how
// recently something was closed.
@ -1037,8 +1039,9 @@ let SessionStoreInternal = {
// with tabs we deem not worth saving then we might end up with a
// random closed or even a pop-up window re-opened. To prevent that
// we explicitly allow saving an "empty" window state.
let numOpenWindows = Object.keys(this._windows).length;
let isLastWindow = numOpenWindows == 1 && RevivableWindows.isEmpty;
let isLastWindow =
Object.keys(this._windows).length == 1 &&
!this._closedWindows.some(win => win._shouldRestore || false);
if (hasSaveableTabs || isLastWindow) {
// we don't want to save the busy state
@ -1047,10 +1050,6 @@ let SessionStoreInternal = {
this._closedWindows.unshift(winData);
this._capClosedWindows();
}
// Until we decide otherwise elsewhere, this window
// is part of a series of closing windows to quit.
RevivableWindows.add(winData);
}
// clear this window from the list
@ -1156,11 +1155,8 @@ let SessionStoreInternal = {
delete this._windows[ix];
}
}
// also clear all data about closed windows
this._closedWindows = [];
RevivableWindows.clear();
// give the tabbrowsers a chance to clear their histories first
var win = this._getMostRecentBrowserWindow();
if (win) {
@ -1168,6 +1164,8 @@ let SessionStoreInternal = {
} else if (RunState.isRunning) {
SessionSaver.run();
}
this._clearRestoringWindows();
},
/**
@ -1221,12 +1219,11 @@ let SessionStoreInternal = {
}
}
// Purging domain data indicates a user action.
RevivableWindows.clear();
if (RunState.isRunning) {
SessionSaver.run();
}
this._clearRestoringWindows();
},
/**
@ -3349,6 +3346,21 @@ let SessionStoreInternal = {
this._closedWindows.splice(spliceTo, this._closedWindows.length);
},
/**
* Clears the set of windows that are "resurrected" before writing to disk to
* make closing windows one after the other until shutdown work as expected.
*
* This function should only be called when we are sure that there has been
* a user action that indicates the browser is actively being used and all
* windows that have been closed before are not part of a series of closing
* windows.
*/
_clearRestoringWindows: function ssi_clearRestoringWindows() {
for (let i = 0; i < this._closedWindows.length; i++) {
delete this._closedWindows[i]._shouldRestore;
}
},
/**
* Reset state to prepare for a new session state to be restored.
*/

View File

@ -46,7 +46,6 @@ EXTRA_JS_MODULES.sessionstore = [
]
EXTRA_PP_JS_MODULES.sessionstore += [
'RevivableWindows.jsm',
'SessionSaver.jsm',
'SessionStore.jsm',
]

View File

@ -81,7 +81,6 @@ skip-if = buildapp == 'mulet'
[browser_merge_closed_tabs.js]
[browser_pageStyle.js]
[browser_privatetabs.js]
[browser_revive_windows.js]
[browser_scrollPositions.js]
[browser_sessionHistory.js]
skip-if = e10s

View File

@ -1,160 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
const IS_MAC = ("nsILocalFileMac" in Ci);
const URL_PREFIX = "about:mozilla?t=browser_revive_windows&r=";
const PREF_MAX_UNDO = "browser.sessionstore.max_windows_undo";
const URL_MAIN_WINDOW = URL_PREFIX + Math.random();
const URL_ADD_WINDOW1 = URL_PREFIX + Math.random();
const URL_ADD_WINDOW2 = URL_PREFIX + Math.random();
const URL_CLOSED_WINDOW = URL_PREFIX + Math.random();
add_task(function* setup() {
registerCleanupFunction(() => Services.prefs.clearUserPref(PREF_MAX_UNDO));
});
/**
* This test ensure that when closing windows in succession until the browser
* quits we are able to revive more windows than we keep around for the
* "Undo Close Window" feature.
*/
add_task(function* test_revive_windows() {
// We can restore a single window max.
Services.prefs.setIntPref(PREF_MAX_UNDO, 1);
// Clear list of closed windows.
forgetClosedWindows();
let windows = [];
// Create three windows.
for (let i = 0; i < 3; i++) {
let win = yield promiseNewWindow();
windows.push(win);
let tab = win.gBrowser.addTab("about:mozilla");
yield promiseBrowserLoaded(tab.linkedBrowser);
}
// Create a private window.
// This window must not be revived.
{
let win = yield promiseNewWindow({private: true});
windows.push(win);
let tab = win.gBrowser.addTab("about:mozilla");
yield promiseBrowserLoaded(tab.linkedBrowser);
}
// Close all windows.
for (let win of windows) {
yield promiseWindowClosed(win);
}
is(ss.getClosedWindowCount(), 1, "one window restorable");
// Save to disk and read.
let state = JSON.parse(yield promiseRecoveryFileContents());
// Check number of windows.
if (IS_MAC) {
is(state.windows.length, 1, "one open window");
is(state._closedWindows.length, 1, "one closed window");
} else {
is(state.windows.length, 4, "four open windows");
is(state._closedWindows.length, 0, "closed windows");
}
});
/**
* This test ensures that when closing windows one after the other until the
* browser shuts down (on Windows and Linux) we revive closed windows in the
* right order.
*/
add_task(function* test_revive_windows_order() {
// We can restore up to three windows max.
Services.prefs.setIntPref(PREF_MAX_UNDO, 3);
// Clear list of closed windows.
forgetClosedWindows();
let tab = gBrowser.addTab(URL_MAIN_WINDOW);
yield promiseBrowserLoaded(tab.linkedBrowser);
TabState.flush(tab.linkedBrowser);
registerCleanupFunction(() => gBrowser.removeTab(tab));
let win0 = yield promiseNewWindow();
let tab0 = win0.gBrowser.addTab(URL_CLOSED_WINDOW);
yield promiseBrowserLoaded(tab0.linkedBrowser);
yield promiseWindowClosed(win0);
let data = ss.getClosedWindowData();
ok(data.contains(URL_CLOSED_WINDOW), "window is restorable");
let win1 = yield promiseNewWindow();
let tab1 = win1.gBrowser.addTab(URL_ADD_WINDOW1);
yield promiseBrowserLoaded(tab1.linkedBrowser);
let win2 = yield promiseNewWindow();
let tab2 = win2.gBrowser.addTab(URL_ADD_WINDOW2);
yield promiseBrowserLoaded(tab2.linkedBrowser);
// Close both windows so that |win1| will be opened first and would be
// behind |win2| that was closed later.
yield promiseWindowClosed(win1);
yield promiseWindowClosed(win2);
// Repeat the checks once.
for (let i = 0; i < 2; i++) {
info(`checking window data, iteration #${i}`);
let contents = yield promiseRecoveryFileContents();
let {windows, _closedWindows: closedWindows} = JSON.parse(contents);
if (IS_MAC) {
// Check number of windows.
is(windows.length, 1, "one open window");
is(closedWindows.length, 3, "three closed windows");
// Check open window.
ok(JSON.stringify(windows).contains(URL_MAIN_WINDOW),
"open window is correct");
// Check closed windows.
ok(JSON.stringify(closedWindows[0]).contains(URL_ADD_WINDOW2),
"correct first additional window");
ok(JSON.stringify(closedWindows[1]).contains(URL_ADD_WINDOW1),
"correct second additional window");
ok(JSON.stringify(closedWindows[2]).contains(URL_CLOSED_WINDOW),
"correct main window");
} else {
// Check number of windows.
is(windows.length, 3, "three open windows");
is(closedWindows.length, 1, "one closed window");
// Check closed window.
ok(JSON.stringify(closedWindows).contains(URL_CLOSED_WINDOW),
"closed window is correct");
// Check that windows are in the right order.
ok(JSON.stringify(windows[0]).contains(URL_ADD_WINDOW1),
"correct first additional window");
ok(JSON.stringify(windows[1]).contains(URL_ADD_WINDOW2),
"correct second additional window");
ok(JSON.stringify(windows[2]).contains(URL_MAIN_WINDOW),
"correct main window");
}
}
});
function promiseNewWindow(opts = {private: false}) {
return new Promise(resolve => whenNewWindowLoaded(opts, resolve));
}
function forgetClosedWindows() {
while (ss.getClosedWindowCount()) {
ss.forgetClosedWindow(0);
}
}

View File

@ -1 +1 @@
35.0a1
36.0a1

View File

@ -14,6 +14,7 @@ skip-if = true
[browser_layoutview_update-after-navigation.js]
[browser_layoutview_update-after-reload.js]
[browser_layoutview_update-in-iframes.js]
skip-if = true # Bug 1020038 layout-view updates for iframe elements changes
[browser_editablemodel.js]
# [browser_editablemodel_allproperties.js]
# Disabled for too many intermittent failures (bug 1009322)

View File

@ -108,3 +108,8 @@ panic-button.tooltiptext = Forget about some browsing history
web-apps-button.label = Apps
web-apps-button.tooltiptext = Discover Apps
# LOCALIZATION NOTE(devtools-webide-button.label, devtools-webide-button.tooltiptext):
# widget is only visible after WebIDE has been started once (Tools > Web Developers > WebIDE)
devtools-webide-button.label = WebIDE
devtools-webide-button.tooltiptext = Open WebIDE

View File

@ -183,6 +183,9 @@ let DirectoryLinksProvider = {
},
_fetchAndCacheLinks: function DirectoryLinksProvider_fetchAndCacheLinks(uri) {
// Replace with the same display locale used for selecting links data
uri = uri.replace("%LOCALE%", this.locale);
let deferred = Promise.defer();
let xmlHttp = new XMLHttpRequest();
@ -206,14 +209,12 @@ let DirectoryLinksProvider = {
};
try {
xmlHttp.open('POST', uri);
xmlHttp.open("GET", uri);
// Override the type so XHR doesn't complain about not well-formed XML
xmlHttp.overrideMimeType(DIRECTORY_LINKS_TYPE);
// Set the appropriate request type for servers that require correct types
xmlHttp.setRequestHeader("Content-Type", DIRECTORY_LINKS_TYPE);
xmlHttp.send(JSON.stringify({
locale: this.locale,
}));
xmlHttp.send();
} catch (e) {
deferred.reject("Error fetching " + uri);
Cu.reportError(e);

View File

@ -53,11 +53,11 @@ Services.prefs.setBoolPref(kNewtabEnhancedPref, true);
const kHttpHandlerData = {};
kHttpHandlerData[kExamplePath] = {"en-US": [{"url":"http://example.com","title":"RemoteSource"}]};
const expectedBodyObject = {locale: DirectoryLinksProvider.locale};
const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
"nsIBinaryInputStream",
"setInputStream");
let gLastRequestPath;
function getHttpHandler(path) {
let code = 200;
let body = JSON.stringify(kHttpHandlerData[path]);
@ -65,10 +65,7 @@ function getHttpHandler(path) {
code = 204;
}
return function(aRequest, aResponse) {
let bodyStream = new BinaryInputStream(aRequest.bodyInputStream);
let bodyObject = JSON.parse(NetUtil.readInputStreamToString(bodyStream, bodyStream.available()));
isIdentical(bodyObject, expectedBodyObject);
gLastRequestPath = aRequest.path;
aResponse.setStatusLine(null, code);
aResponse.setHeader("Content-Type", "application/json");
aResponse.write(body);
@ -131,7 +128,9 @@ function promiseDirectoryDownloadOnPrefChange(pref, newValue) {
let observer = new LinksChangeObserver();
DirectoryLinksProvider.addObserver(observer);
Services.prefs.setCharPref(pref, newValue);
return observer.deferred.promise;
return observer.deferred.promise.then(() => {
DirectoryLinksProvider.removeObserver(observer);
});
}
return Promise.resolve();
}
@ -296,7 +295,8 @@ add_task(function test_fetchAndCacheLinks_remote() {
yield DirectoryLinksProvider.init();
yield cleanJsonFile();
// this must trigger directory links json download and save it to cache file
yield DirectoryLinksProvider._fetchAndCacheLinks(kExampleURL);
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kExampleURL + "%LOCALE%");
do_check_eq(gLastRequestPath, kExamplePath + "en-US");
let data = yield readJsonFile();
isIdentical(data, kHttpHandlerData[kExamplePath]);
});
@ -336,7 +336,8 @@ add_task(function test_fetchAndCacheLinks_unknownHost() {
add_task(function test_fetchAndCacheLinks_non200Status() {
yield DirectoryLinksProvider.init();
yield cleanJsonFile();
yield DirectoryLinksProvider._fetchAndCacheLinks(kFailURL);
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kFailURL);
do_check_eq(gLastRequestPath, kFailPath);
let data = yield readJsonFile();
isIdentical(data, {});
});
@ -508,6 +509,7 @@ add_task(function test_DirectoryLinksProvider_fetchDirectoryOnPrefChange() {
yield promiseDirectoryDownloadOnPrefChange(kSourceUrlPref, kExampleURL);
// then wait for testObserver to fire and test that json is downloaded
yield testObserver.deferred.promise;
do_check_eq(gLastRequestPath, kExamplePath);
let data = yield readJsonFile();
isIdentical(data, kHttpHandlerData[kExamplePath]);

View File

@ -10,4 +10,4 @@
# hardcoded milestones in the tree from these two files.
#--------------------------------------------------------
35.0a1
36.0a1

View File

@ -950,6 +950,11 @@ MobileConnectionService.prototype = {
} catch (e) {}
},
_broadcastCdmaInfoRecordSystemMessage: function(aMessage) {
// TODO: Bug 1072808, Broadcast System Message with proxy.
gSystemMessenger.broadcastMessage("cdma-info-rec-received", aMessage);
},
/**
* nsIMobileConnectionService interface.
*/
@ -1167,6 +1172,111 @@ MobileConnectionService.prototype = {
aServiceClass);
},
notifyCdmaInfoRecDisplay: function(aClientId, aDisplay) {
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
display: aDisplay
});
},
notifyCdmaInfoRecCalledPartyNumber: function(aClientId, aType, aPlan, aNumber,
aPi, aSi) {
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
calledNumber: {
type: aType,
plan: aPlan,
number: aNumber,
pi: aPi,
si: aSi
}
});
},
notifyCdmaInfoRecCallingPartyNumber: function(aClientId, aType, aPlan, aNumber,
aPi, aSi) {
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
callingNumber: {
type: aType,
plan: aPlan,
number: aNumber,
pi: aPi,
si: aSi
}
});
},
notifyCdmaInfoRecConnectedPartyNumber: function(aClientId, aType, aPlan, aNumber,
aPi, aSi) {
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
connectedNumber: {
type: aType,
plan: aPlan,
number: aNumber,
pi: aPi,
si: aSi
}
});
},
notifyCdmaInfoRecSignal: function(aClientId, aType, aAlertPitch, aSignal){
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
signal: {
type: aType,
alertPitch: aAlertPitch,
signal: aSignal
}
});
},
notifyCdmaInfoRecRedirectingNumber: function(aClientId, aType, aPlan, aNumber,
aPi, aSi, aReason) {
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
redirect: {
type: aType,
plan: aPlan,
number: aNumber,
pi: aPi,
si: aSi,
reason: aReason
}
});
},
notifyCdmaInfoRecLineControl: function(aClientId, aPolarityIncluded, aToggle,
aReverse, aPowerDenial) {
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
lineControl: {
polarityIncluded: aPolarityIncluded,
toggle: aToggle,
reverse: aReverse,
powerDenial: aPowerDenial
}
});
},
notifyCdmaInfoRecClir: function(aClientId, aCause) {
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
clirCause: aCause
});
},
notifyCdmaInfoRecAudioControl: function(aClientId, aUplink, aDownLink) {
this._broadcastCdmaInfoRecordSystemMessage({
clientId: aClientId,
audioControl: {
upLink: aUplink,
downLink: aDownLink
}
});
},
/**
* nsIObserver interface.
*/

View File

@ -9,7 +9,7 @@
"@mozilla.org/mobileconnection/gonkmobileconnectionservice;1"
%}
[scriptable, uuid(b0310517-e7f6-4fa5-a52e-fa6ff35c8fc1)]
[scriptable, uuid(2d574f0e-4a02-11e4-b1b3-cbc14b7608ce)]
interface nsIGonkMobileConnectionService : nsIMobileConnectionService
{
void notifyNetworkInfoChanged(in unsigned long clientId, in jsval networkInfo);
@ -53,4 +53,205 @@ interface nsIGonkMobileConnectionService : nsIMobileConnectionService
in DOMString number,
in unsigned short timeSeconds,
in unsigned short serviceClass);
/**
* Notify Display Info from received Cdma-Info-Record.
* See 3.7.4.1 Display in 3GPP2 C.S0005-F.
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param display
The string to be displayed.
*/
void notifyCdmaInfoRecDisplay(in unsigned long clientId,
in DOMString display);
/**
* Notify Called Party Number from received Cdma-Info-Record.
* See 3.7.4.2 Called Party Number in 3GPP2 C.S0005-F.
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param type
* The type of number. (3-bit binary)
* See Table 2.7.1.3.2.4-2 in 3GPP2 C.S0005-F.
* @param plan
* The numbering plan. (4-bit binary)
* See Table 2.7.1.3.2.4-3 in 3GPP2 C.S0005-F.
* @param number
* The string presentation of the number.
* @param pi (2-bit binary)
* The Presentation indicator of the number.
* See Table 2.7.4.4-1 in 3GPP2 C.S0005-F.
* @param si (2-bit binary)
* The Screening Indicator of the number.
* See Table 2.7.4.4-2 in 3GPP2 C.S0005-F.
*/
void notifyCdmaInfoRecCalledPartyNumber(in unsigned long clientId,
in unsigned short type,
in unsigned short plan,
in DOMString number,
in unsigned short pi,
in unsigned short si);
/**
* Notify Calling Party Number from received Cdma-Info-Record.
* See 3.7.4.3 Calling Party Number in 3GPP2 C.S0005-F.
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param type
* The type of number. (3-bit binary)
* See Table 2.7.1.3.2.4-2 in 3GPP2 C.S0005-F.
* @param plan
* The numbering plan. (4-bit binary)
* See Table 2.7.1.3.2.4-3 in 3GPP2 C.S0005-F.
* @param number
* The string presentation of the number.
* @param pi (2-bit binary)
* The Presentation indicator of the number.
* See Table 2.7.4.4-1 in 3GPP2 C.S0005-F.
* @param si (2-bit binary)
* The Screening Indicator of the number.
* See Table 2.7.4.4-2 in 3GPP2 C.S0005-F.
*/
void notifyCdmaInfoRecCallingPartyNumber(in unsigned long clientId,
in unsigned short type,
in unsigned short plan,
in DOMString number,
in unsigned short pi,
in unsigned short si);
/**
* Notify Connected Party Number from received Cdma-Info-Record.
* See 3.7.4.4 Connected Party Number in 3GPP2 C.S0005-F.
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param type
* The type of number. (3-bit binary)
* See Table 2.7.1.3.2.4-2 in 3GPP2 C.S0005-F.
* @param plan
* The numbering plan. (4-bit binary)
* See Table 2.7.1.3.2.4-3 in 3GPP2 C.S0005-F.
* @param number
* The string presentation of the number.
* @param pi (2-bit binary)
* The Presentation indicator of the number.
* See Table 2.7.4.4-1 in 3GPP2 C.S0005-F.
* @param si (2-bit binary)
* The Screening Indicator of the number.
* See Table 2.7.4.4-2 in 3GPP2 C.S0005-F.
*/
void notifyCdmaInfoRecConnectedPartyNumber(in unsigned long clientId,
in unsigned short type,
in unsigned short plan,
in DOMString number,
in unsigned short pi,
in unsigned short si);
/**
* Notify Signal Info from received Cdma-Info-Record.
* See 3.7.4.5 Signal in 3GPP2 C.S0005-F.
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param type
* The signal type. (2-bit binary)
* See Table 3.7.5.5-1 in 3GPP2 C.S0005-F.
* @param alertPitch
* The pitch of the alerting signal. (2-bit binary)
* See Table 3.7.5.5-2 in 3GPP2 C.S0005-F.
* @param signal
* The signal code. (6-bit binary)
* See Table 3.7.5.5-3, 3.7.5.5-4, 3.7.5.5-5 in 3GPP2 C.S0005-F.
*/
void notifyCdmaInfoRecSignal(in unsigned long clientId,
in unsigned short type,
in unsigned short alertPitch,
in unsigned short signal);
/**
* Notify Redirecting Number from received Cdma-Info-Record.
* See 3.7.4.11 Redirecting Number in 3GPP2 C.S0005-F.
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param type
* The type of number. (3-bit binary)
* See Table 2.7.1.3.2.4-2 in 3GPP2 C.S0005-F.
* @param plan
* The numbering plan. (4-bit binary)
* See Table 2.7.1.3.2.4-3 in 3GPP2 C.S0005-F.
* @param number
* The string presentation of the number.
* @param pi (2-bit binary)
* The Presentation indicator of the number.
* See Table 2.7.4.4-1 in 3GPP2 C.S0005-F.
* @param si (2-bit binary)
* The Screening Indicator of the number.
* See Table 2.7.4.4-2 in 3GPP2 C.S0005-F.
* @param reason (4-bit binary)
* The redirection reason.
* See Table 3.7.5.11-1 in 3GPP2 C.S0005-F.
*/
void notifyCdmaInfoRecRedirectingNumber(in unsigned long clientId,
in unsigned short type,
in unsigned short plan,
in DOMString number,
in unsigned short pi,
in unsigned short si,
in unsigned short reason);
/**
* Notify Line Control from received Cdma-Info-Record.
* See 3.7.4.15 Line Control in 3GPP2 C.S0005-F.
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param polarityIncluded (1-bit)
* Polarity parameter included.
* @param toggle (1-bit)
* Toggle mode.
* @param reverse (1-bit)
* Reverse polarity.
* @param powerDenial (8-bit)
* Power denial timeout.
*/
void notifyCdmaInfoRecLineControl(in unsigned long clientId,
in unsigned short polarityIncluded,
in unsigned short toggle,
in unsigned short reverse,
in unsigned short powerDenial);
/**
* Notify CLIR from received Cdma-Info-Record.
* See 'ANNEX 1 Country-Specific Record Type for Japan' in T53.
* http://www.arib.or.jp/english/html/overview/doc/T53v6_5_pdf/5_ANNEX_v6_5.pdf
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param cause
* Reason code. (8-bit binary)
* See Table A 1.1-1 in T53.
*/
void notifyCdmaInfoRecClir(in unsigned long clientId,
in unsigned short cause);
/**
* Notify Audio Control from received Cdma-Info-Record.
*
* Note: No information from ARIB about Audio Control.
* It seems obsolete according to ANNEX 1 in T53.
* upLink/downLink are 'byte' value according to ril.h.
* Treat them as 'signed short' to preserve the flexibility when needed.
*
* @param clientId
* The ID of radioInterface where this info is notified from.
* @param upLink
* @param downLink
*/
void notifyCdmaInfoRecAudioControl(in unsigned long clientId,
in short upLink,
in short downLink);
};

View File

@ -396,13 +396,6 @@ XPCOMUtils.defineLazyGetter(this, "gMessageManager", function() {
}
},
sendMobileConnectionMessage: function(message, clientId, data) {
this._sendTargetMessage("mobileconnection", message, {
clientId: clientId,
data: data
});
},
sendIccMessage: function(message, clientId, data) {
this._sendTargetMessage("icc", message, {
clientId: clientId,
@ -1163,7 +1156,7 @@ DataConnectionHandler.prototype = {
_compareDataCallOptions: function(dataCall, newDataCall) {
return dataCall.apnProfile.apn == newDataCall.apn &&
dataCall.apnProfile.user == newDataCall.user &&
dataCall.apnProfile.password == newDataCall.password &&
dataCall.apnProfile.password == newDataCall.passwd &&
dataCall.chappap == newDataCall.chappap &&
dataCall.pdptype == newDataCall.pdptype;
},
@ -2091,8 +2084,7 @@ RadioInterface.prototype = {
gMessageManager.sendIccMessage("RIL:StkSessionEnd", this.clientId, null);
break;
case "cdma-info-rec-received":
if (DEBUG) this.debug("cdma-info-rec-received: " + JSON.stringify(message));
gSystemMessenger.broadcastMessage("cdma-info-rec-received", message);
this.handleCdmaInformationRecords(message.records);
break;
default:
throw new Error("Don't know about this message type: " +
@ -2920,6 +2912,99 @@ RadioInterface.prototype = {
hasEtwsInfo ? etwsInfo.popup : false);
},
handleCdmaInformationRecords: function(aRecords) {
if (DEBUG) this.debug("cdma-info-rec-received: " + JSON.stringify(aRecords));
let clientId = this.clientId;
aRecords.forEach(function(aRecord) {
if (aRecord.display) {
gMobileConnectionService
.notifyCdmaInfoRecDisplay(clientId, aRecord.display);
return;
}
if (aRecord.calledNumber) {
gMobileConnectionService
.notifyCdmaInfoRecCalledPartyNumber(clientId,
aRecord.calledNumber.type,
aRecord.calledNumber.plan,
aRecord.calledNumber.number,
aRecord.calledNumber.pi,
aRecord.calledNumber.si);
return;
}
if (aRecord.callingNumber) {
gMobileConnectionService
.notifyCdmaInfoRecCallingPartyNumber(clientId,
aRecord.callingNumber.type,
aRecord.callingNumber.plan,
aRecord.callingNumber.number,
aRecord.callingNumber.pi,
aRecord.callingNumber.si);
return;
}
if (aRecord.connectedNumber) {
gMobileConnectionService
.notifyCdmaInfoRecConnectedPartyNumber(clientId,
aRecord.connectedNumber.type,
aRecord.connectedNumber.plan,
aRecord.connectedNumber.number,
aRecord.connectedNumber.pi,
aRecord.connectedNumber.si);
return;
}
if (aRecord.signal) {
gMobileConnectionService
.notifyCdmaInfoRecSignal(clientId,
aRecord.signal.type,
aRecord.signal.alertPitch,
aRecord.signal.signal);
return;
}
if (aRecord.redirect) {
gMobileConnectionService
.notifyCdmaInfoRecRedirectingNumber(clientId,
aRecord.redirect.type,
aRecord.redirect.plan,
aRecord.redirect.number,
aRecord.redirect.pi,
aRecord.redirect.si,
aRecord.redirect.reason);
return;
}
if (aRecord.lineControl) {
gMobileConnectionService
.notifyCdmaInfoRecLineControl(clientId,
aRecord.lineControl.polarityIncluded,
aRecord.lineControl.toggle,
aRecord.lineControl.reverse,
aRecord.lineControl.powerDenial);
return;
}
if (aRecord.clirCause) {
gMobileConnectionService
.notifyCdmaInfoRecClir(clientId,
aRecord.clirCause);
return;
}
if (aRecord.audioControl) {
gMobileConnectionService
.notifyCdmaInfoRecAudioControl(clientId,
aRecord.audioControl.upLink,
aRecord.audioControl.downLink);
return;
}
});
},
// nsIObserver
observe: function(subject, topic, data) {

View File

@ -6920,9 +6920,10 @@ RilObject.prototype[UNSOLICITED_CDMA_OTA_PROVISION_STATUS] = function UNSOLICITE
status: status});
};
RilObject.prototype[UNSOLICITED_CDMA_INFO_REC] = function UNSOLICITED_CDMA_INFO_REC(length) {
let record = this.context.CdmaPDUHelper.decodeInformationRecord();
record.rilMessageType = "cdma-info-rec-received";
this.sendChromeMessage(record);
this.sendChromeMessage({
rilMessageType: "cdma-info-rec-received",
records: this.context.CdmaPDUHelper.decodeInformationRecord()
});
};
RilObject.prototype[UNSOLICITED_OEM_HOOK_RAW] = null;
RilObject.prototype[UNSOLICITED_RINGBACK_TONE] = null;
@ -9987,11 +9988,13 @@ CdmaPDUHelperObject.prototype = {
*/
decodeInformationRecord: function() {
let Buf = this.context.Buf;
let record = {};
let records = [];
let numOfRecords = Buf.readInt32();
let type;
let record;
for (let i = 0; i < numOfRecords; i++) {
record = {};
type = Buf.readInt32();
switch (type) {
@ -9999,6 +10002,7 @@ CdmaPDUHelperObject.prototype = {
* Every type is encaped by ril, except extended display
*/
case PDU_CDMA_INFO_REC_TYPE_DISPLAY:
case PDU_CDMA_INFO_REC_TYPE_EXTENDED_DISPLAY:
record.display = Buf.readString();
break;
case PDU_CDMA_INFO_REC_TYPE_CALLED_PARTY_NUMBER:
@ -10027,7 +10031,10 @@ CdmaPDUHelperObject.prototype = {
break;
case PDU_CDMA_INFO_REC_TYPE_SIGNAL:
record.signal = {};
record.signal.present = Buf.readInt32();
if (!Buf.readInt32()) { // Non-zero if signal is present.
Buf.seekIncoming(3 * Buf.UINT32_SIZE);
continue;
}
record.signal.type = Buf.readInt32();
record.signal.alertPitch = Buf.readInt32();
record.signal.signal = Buf.readInt32();
@ -10045,40 +10052,11 @@ CdmaPDUHelperObject.prototype = {
record.lineControl = {};
record.lineControl.polarityIncluded = Buf.readInt32();
record.lineControl.toggle = Buf.readInt32();
record.lineControl.recerse = Buf.readInt32();
record.lineControl.reverse = Buf.readInt32();
record.lineControl.powerDenial = Buf.readInt32();
break;
case PDU_CDMA_INFO_REC_TYPE_EXTENDED_DISPLAY:
let length = Buf.readInt32();
/*
* Extended display is still in format defined in
* C.S0005-F v1.0, 3.7.5.16
*/
record.extendedDisplay = {};
let headerByte = Buf.readInt32();
length--;
// Based on spec, headerByte must be 0x80 now
record.extendedDisplay.indicator = (headerByte >> 7);
record.extendedDisplay.type = (headerByte & 0x7F);
record.extendedDisplay.records = [];
while (length > 0) {
let display = {};
display.tag = Buf.readInt32();
length--;
if (display.tag !== INFO_REC_EXTENDED_DISPLAY_BLANK &&
display.tag !== INFO_REC_EXTENDED_DISPLAY_SKIP) {
display.content = Buf.readString();
length -= (display.content.length + 1);
}
record.extendedDisplay.records.push(display);
}
break;
case PDU_CDMA_INFO_REC_TYPE_T53_CLIR:
record.cause = Buf.readInt32();
record.clirCause = Buf.readInt32();
break;
case PDU_CDMA_INFO_REC_TYPE_T53_AUDIO_CONTROL:
record.audioControl = {};
@ -10088,11 +10066,13 @@ CdmaPDUHelperObject.prototype = {
case PDU_CDMA_INFO_REC_TYPE_T53_RELEASE:
// Fall through
default:
throw new Error("UNSOLICITED_CDMA_INFO_REC(), Unsupported information record type " + record.type + "\n");
throw new Error("UNSOLICITED_CDMA_INFO_REC(), Unsupported information record type " + type + "\n");
}
records.push(record);
}
return record;
return records;
}
};

View File

@ -36,6 +36,10 @@ function newWorkerWithParcel(parcelBuf) {
return buf[index++];
};
context.Buf.seekIncoming = function(offset) {
index += offset / context.Buf.UINT32_SIZE;
};
return worker;
}
@ -53,9 +57,9 @@ add_test(function test_display() {
0x6F, 0x00]);
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let record = helper.decodeInformationRecord();
let records = helper.decodeInformationRecord();
do_check_eq(record.display, "Test Info");
do_check_eq(records[0].display, "Test Info");
run_next_test();
});
@ -67,27 +71,19 @@ add_test(function test_extended_display() {
let worker = newWorkerWithParcel([
0x01, // one inforemation record
0x07, // type: extended display
0x0E, // length: 14
0x80, // header byte
0x80, // Blank
0x81, // Skip
0x9B, // Text
0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E,
0x66, 0x6F, 0x00]);
0x12, // length: 18
0x54, 0x65, 0x73, 0x74, 0x20, 0x45, 0x78, 0x74,
0x65, 0x6E, 0x64, 0x65, 0x64, 0x20, 0x49, 0x6E,
0x66, 0x6F, 0x00, 0x00]);
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let record = helper.decodeInformationRecord();
let records = helper.decodeInformationRecord();
do_check_eq(record.extendedDisplay.indicator, 1);
do_check_eq(record.extendedDisplay.type, 0);
do_check_eq(record.extendedDisplay.records.length, 3);
do_check_eq(record.extendedDisplay.records[0].tag, 0x80);
do_check_eq(record.extendedDisplay.records[1].tag, 0x81);
do_check_eq(record.extendedDisplay.records[2].tag, 0x9B);
do_check_eq(record.extendedDisplay.records[2].content, "Test Info");
do_check_eq(records[0].display, "Test Extended Info");
run_next_test();
});
/**
* Verify decoder for mixed type
*/
@ -95,29 +91,144 @@ add_test(function test_mixed() {
let worker = newWorkerWithParcel([
0x02, // two inforemation record
0x00, // type: display
0x09, // length: 9
0x0B, // length: 11
0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
0x6F, 0x00,
0x6F, 0x20, 0x31, 0x00,
0x07, // type: extended display
0x0E, // length: 14
0x80, // header byte
0x80, // Blank
0x81, // Skip
0x9B, // Text
0x09, 0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E,
0x66, 0x6F, 0x00]);
0x0B, // length: 11
0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
0x6F, 0x20, 0x32, 0x00]);
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let record = helper.decodeInformationRecord();
let records = helper.decodeInformationRecord();
do_check_eq(record.display, "Test Info");
do_check_eq(record.extendedDisplay.indicator, 1);
do_check_eq(record.extendedDisplay.type, 0);
do_check_eq(record.extendedDisplay.records.length, 3);
do_check_eq(record.extendedDisplay.records[0].tag, 0x80);
do_check_eq(record.extendedDisplay.records[1].tag, 0x81);
do_check_eq(record.extendedDisplay.records[2].tag, 0x9B);
do_check_eq(record.extendedDisplay.records[2].content, "Test Info");
do_check_eq(records[0].display, "Test Info 1");
do_check_eq(records[1].display, "Test Info 2");
run_next_test();
});
/**
* Verify decoder for multiple types
*/
add_test(function test_multiple() {
let worker = newWorkerWithParcel([
0x02, // two inforemation record
0x00, // type: display
0x0B, // length: 11
0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
0x6F, 0x20, 0x31, 0x00,
0x00, // type: display
0x0B, // length: 11
0x54, 0x65, 0x73, 0x74, 0x20, 0x49, 0x6E, 0x66,
0x6F, 0x20, 0x32, 0x00]);
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let records = helper.decodeInformationRecord();
do_check_eq(records[0].display, "Test Info 1");
do_check_eq(records[1].display, "Test Info 2");
run_next_test();
});
/**
* Verify decoder for Signal Type
*/
add_test(function test_signal() {
let worker = newWorkerWithParcel([
0x01, // one inforemation record
0x04, // type: signal
0x01, // isPresent: non-zero
0x00, // signalType: Tone signal (00)
0x01, // alertPitch: High pitch
0x03]); // signal: Abbreviated intercept (000011)
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let records = helper.decodeInformationRecord();
do_check_eq(records[0].signal.type, 0x00);
do_check_eq(records[0].signal.alertPitch, 0x01);
do_check_eq(records[0].signal.signal, 0x03);
run_next_test();
});
/**
* Verify decoder for Signal Type for Not Presented
*/
add_test(function test_signal_not_present() {
let worker = newWorkerWithParcel([
0x01, // one inforemation record
0x04, // type: signal
0x00, // isPresent: zero
0x00, // signalType: Tone signal (00)
0x01, // alertPitch: High pitch
0x03]); // signal: Abbreviated intercept (000011)
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let records = helper.decodeInformationRecord();
do_check_eq(records.length, 0);
run_next_test();
});
/**
* Verify decoder for Line Control
*/
add_test(function test_line_control() {
let worker = newWorkerWithParcel([
0x01, // one inforemation record
0x06, // type: line control
0x01, // polarity included
0x00, // not toggled
0x01, // reversed
0xFF]); // Power denial timeout: 255 * 5 ms
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let records = helper.decodeInformationRecord();
do_check_eq(records[0].lineControl.polarityIncluded, 1);
do_check_eq(records[0].lineControl.toggle, 0);
do_check_eq(records[0].lineControl.reverse, 1);
do_check_eq(records[0].lineControl.powerDenial, 255);
run_next_test();
});
/**
* Verify decoder for CLIR Cause
*/
add_test(function test_clir() {
let worker = newWorkerWithParcel([
0x01, // one inforemation record
0x08, // type: clir
0x01]); // cause: Rejected by user
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let records = helper.decodeInformationRecord();
do_check_eq(records[0].clirCause, 1);
run_next_test();
});
/**
* Verify decoder for Audio Control
*/
add_test(function test_clir() {
let worker = newWorkerWithParcel([
0x01, // one inforemation record
0x0A, // type: audio control
0x01, // uplink
0xFF]); // downlink
let context = worker.ContextPool._contexts[0];
let helper = context.CdmaPDUHelper;
let records = helper.decodeInformationRecord();
do_check_eq(records[0].audioControl.upLink, 1);
do_check_eq(records[0].audioControl.downLink, 255);
run_next_test();
});

View File

@ -227,13 +227,6 @@ WifiCertService::Start(nsIWifiEventListener* aListener)
{
MOZ_ASSERT(aListener);
nsresult rv = NS_NewThread(getter_AddRefs(mRequestThread));
if (NS_FAILED(rv)) {
NS_WARNING("Certn't create wifi control thread");
Shutdown();
return NS_ERROR_FAILURE;
}
mListener = aListener;
return NS_OK;
@ -243,10 +236,6 @@ NS_IMETHODIMP
WifiCertService::Shutdown()
{
MOZ_ASSERT(NS_IsMainThread());
if (mRequestThread) {
mRequestThread->Shutdown();
mRequestThread = nullptr;
}
mListener = nullptr;

View File

@ -27,7 +27,6 @@ public:
private:
WifiCertService();
~WifiCertService();
nsCOMPtr<nsIThread> mRequestThread;
nsCOMPtr<nsIWifiEventListener> mListener;
};

View File

@ -1859,7 +1859,7 @@ function WifiWorker() {
var pub = new Network(ssid, security, password);
if (net.identity)
pub.identity = dequote(net.identity);
if (net.netId)
if ("netId" in net)
pub.known = true;
if (net.scan_ssid === 1)
pub.hidden = true;

View File

@ -2760,7 +2760,7 @@ public class BrowserApp extends GeckoApp
share.setVisible(shareEnabled);
share.setEnabled(StringUtils.isShareableUrl(url) && shareEnabled);
MenuUtils.safeSetEnabled(aMenu, R.id.apps, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_INSTALL_APPS));
MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_INSTALL_EXTENSIONS));
MenuUtils.safeSetEnabled(aMenu, R.id.addons, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_INSTALL_EXTENSION));
MenuUtils.safeSetEnabled(aMenu, R.id.downloads, RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_DOWNLOADS));
// NOTE: Use MenuUtils.safeSetEnabled because some actions might

View File

@ -81,6 +81,7 @@ import android.location.Location;
import android.location.LocationListener;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.PowerManager;
import android.os.StrictMode;
@ -978,6 +979,12 @@ public abstract class GeckoApp
image = BitmapUtils.decodeByteArray(imgBuffer);
}
if (image != null) {
// Some devices don't have a DCIM folder and the Media.insertImage call will fail.
File dcimDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
if (!dcimDir.mkdirs() && !dcimDir.isDirectory()) {
Toast.makeText((Context) this, R.string.set_image_path_fail, Toast.LENGTH_SHORT).show();
return;
}
String path = Media.insertImage(getContentResolver(),image, null, null);
if (path == null) {
Toast.makeText((Context) this, R.string.set_image_path_fail, Toast.LENGTH_SHORT).show();

View File

@ -55,14 +55,16 @@ public class RestrictedProfiles {
*/
public static enum Restriction {
DISALLOW_DOWNLOADS(1, "no_download_files"),
DISALLOW_INSTALL_EXTENSIONS(2, "no_install_extensions"),
DISALLOW_INSTALL_EXTENSION(2, "no_install_extensions"),
DISALLOW_INSTALL_APPS(3, "no_install_apps"), // UserManager.DISALLOW_INSTALL_APPS
DISALLOW_BROWSE_FILES(4, "no_browse_files"),
DISALLOW_SHARE(5, "no_share"),
DISALLOW_BOOKMARK(6, "no_bookmark"),
DISALLOW_ADD_CONTACTS(7, "no_add_contacts"),
DISALLOW_SET_IMAGE(8, "no_set_image"),
DISALLOW_MODIFY_ACCOUNTS(9, "no_modify_accounts"); // UserManager.DISALLOW_MODIFY_ACCOUNTS
DISALLOW_MODIFY_ACCOUNTS(9, "no_modify_accounts"), // UserManager.DISALLOW_MODIFY_ACCOUNTS
DISALLOW_REMOTE_DEBUGGING(10, "no_remote_debugging"),
DISALLOW_IMPORT_SETTINGS(11, "no_import_settings");
public final int id;
public final String name;

View File

@ -10,7 +10,10 @@ import org.mozilla.gecko.animation.BounceAnimator;
import org.mozilla.gecko.animation.BounceAnimator.Attributes;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.support.v4.view.PagerTabStrip;
import android.util.AttributeSet;
import android.view.View;
@ -37,8 +40,11 @@ class HomePagerTabStrip extends PagerTabStrip {
private static final int BOUNCE4_MS = 100;
private static final int INIT_OFFSET = 100;
private final Paint shadowPaint;
private final int shadowSize;
public HomePagerTabStrip(Context context) {
super(context);
this(context, null);
}
public HomePagerTabStrip(Context context, AttributeSet attrs) {
@ -50,6 +56,13 @@ class HomePagerTabStrip extends PagerTabStrip {
setTabIndicatorColor(color);
final Resources res = getResources();
shadowSize = res.getDimensionPixelSize(R.dimen.tabs_strip_shadow_size);
shadowPaint = new Paint();
shadowPaint.setColor(res.getColor(R.color.url_bar_shadow));
shadowPaint.setStrokeWidth(0.0f);
getViewTreeObserver().addOnPreDrawListener(new PreDrawListener());
}
@ -61,6 +74,14 @@ class HomePagerTabStrip extends PagerTabStrip {
return 0;
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
final int height = getHeight();
canvas.drawRect(0, height - shadowSize, getWidth(), height, shadowPaint);
}
private void animateTitles() {
final View prevTextView = getChildAt(0);
final View nextTextView = getChildAt(getChildCount() - 1);

View File

@ -8,12 +8,31 @@ package org.mozilla.gecko.home;
import org.mozilla.gecko.R;
import org.mozilla.gecko.Tab;
import org.mozilla.gecko.Tabs;
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
import org.mozilla.gecko.home.TwoLinePageRow;
import android.content.Context;
import android.content.res.Resources;
import android.database.Cursor;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ReadingListRow extends LinearLayout {
private final Resources resources;
private final TextView title;
private final TextView excerpt;
private final TextView readTime;
// Average reading speed in words per minute.
private static final int AVERAGE_READING_SPEED = 250;
// Length of average word.
private static final float AVERAGE_WORD_LENGTH = 5.1f;
public class ReadingListRow extends TwoLinePageRow {
public ReadingListRow(Context context) {
this(context, null);
@ -21,22 +40,48 @@ public class ReadingListRow extends TwoLinePageRow {
public ReadingListRow(Context context, AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.reading_list_row_view, this);
setOrientation(LinearLayout.VERTICAL);
resources = context.getResources();
title = (TextView) findViewById(R.id.title);
excerpt = (TextView) findViewById(R.id.excerpt);
readTime = (TextView) findViewById(R.id.read_time);
}
@Override
protected void updateDisplayedUrl() {
String pageUrl = getUrl();
public void updateFromCursor(Cursor cursor) {
if (cursor == null) {
return;
}
boolean isPrivate = Tabs.getInstance().getSelectedTab().isPrivate();
Tab tab = Tabs.getInstance().getFirstReaderTabForUrl(pageUrl, isPrivate);
final int titleIndex = cursor.getColumnIndexOrThrow(ReadingListItems.TITLE);
title.setText(cursor.getString(titleIndex));
if (tab != null) {
setUrl(R.string.switch_to_tab);
setSwitchToTabIcon(R.drawable.ic_url_bar_tab);
final int excerptIndex = cursor.getColumnIndexOrThrow(ReadingListItems.EXCERPT);
excerpt.setText(cursor.getString(excerptIndex));
final int lengthIndex = cursor.getColumnIndexOrThrow(ReadingListItems.LENGTH);
final int minutes = getEstimatedReadTime(cursor.getInt(lengthIndex));
if (minutes <= 60) {
readTime.setText(resources.getString(R.string.reading_list_time_minutes, minutes));
} else {
setUrl(pageUrl);
setSwitchToTabIcon(NO_ICON);
readTime.setText(resources.getString(R.string.reading_list_time_over_an_hour));
}
}
/**
* Calculates the estimated time to read an article based on its length.
*
* @param length of the article (in characters)
* @return estimated time to read the article (in minutes)
*/
private static int getEstimatedReadTime(int length) {
final int minutes = (int) Math.ceil((length / AVERAGE_WORD_LENGTH) / AVERAGE_READING_SPEED);
// Minimum of one minute.
return Math.max(minutes, 1);
}
}

View File

@ -6,7 +6,6 @@
package org.mozilla.gecko.home;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import org.mozilla.gecko.R;
@ -52,10 +51,14 @@ public class RemoteTabsPanel extends HomeFragment {
// A lazily-populated cache of fragments corresponding to the possible
// system account states. We don't want to re-create panels unnecessarily,
// because that can cause flickering. Be aware that null is a valid key; it
// corresponds to "no Account, neither Firefox nor Legacy Sync."
// because that can cause flickering. `null` is not a valid key.
private final Map<Action, Fragment> mFragmentCache = new EnumMap<>(Action.class);
// The fragment that corresponds to the null action -- "no Account,
// neither Firefox nor Legacy Sync."
// Lazily populated.
private Fragment mFallbackFragment;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.home_remote_tabs_panel, container, false);
@ -175,12 +178,20 @@ public class RemoteTabsPanel extends HomeFragment {
private Fragment getFragmentNeeded(Account account) {
final Action actionNeeded = getActionNeeded(account);
// We use containsKey rather than get because null is a valid key.
if (!mFragmentCache.containsKey(actionNeeded)) {
final Fragment fragment = makeFragmentForAction(actionNeeded);
if (actionNeeded == null) {
if (mFallbackFragment == null) {
mFallbackFragment = makeFragmentForAction(null);
}
return mFallbackFragment;
}
Fragment fragment = mFragmentCache.get(actionNeeded);
if (fragment == null) {
fragment = makeFragmentForAction(actionNeeded);
mFragmentCache.put(actionNeeded, fragment);
}
return mFragmentCache.get(actionNeeded);
return fragment;
}
/**

View File

@ -8,8 +8,10 @@ package org.mozilla.gecko.home;
import org.mozilla.gecko.R;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
@ -35,16 +37,35 @@ public class TabMenuStrip extends HorizontalScrollView
private final int titleOffset;
private final TabMenuStripLayout layout;
private final Paint shadowPaint;
private final int shadowSize;
public TabMenuStrip(Context context, AttributeSet attrs) {
super(context, attrs);
// Disable the scroll bar.
setHorizontalScrollBarEnabled(false);
titleOffset = (int) (TITLE_OFFSET_DIPS * getResources().getDisplayMetrics().density);
final Resources res = getResources();
titleOffset = (int) (TITLE_OFFSET_DIPS * res.getDisplayMetrics().density);
layout = new TabMenuStripLayout(context, attrs);
addView(layout, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
shadowSize = res.getDimensionPixelSize(R.dimen.tabs_strip_shadow_size);
shadowPaint = new Paint();
shadowPaint.setColor(res.getColor(R.color.url_bar_shadow));
shadowPaint.setStrokeWidth(0.0f);
}
@Override
public void draw(Canvas canvas) {
super.draw(canvas);
final int height = getHeight();
canvas.drawRect(0, height - shadowSize, getWidth(), height, shadowPaint);
}
@Override

View File

@ -364,6 +364,12 @@ size. -->
<!ENTITY reading_list_failed "Failed to add page to your Reading List">
<!ENTITY reading_list_duplicate "Page already in your Reading List">
<!-- Localization note (reading_list_time_minutes) : This string is used in the "Reading List"
panel on the home page to give the user an estimate of how many minutes it will take to
read an article. The word "minute" should be abbreviated if possible. -->
<!ENTITY reading_list_time_minutes "&formatD;min">
<!ENTITY reading_list_time_over_an_hour "Over an hour">
<!-- Localization note : These strings are used as alternate text for accessibility.
They are not visible in the UI. -->
<!ENTITY page_action_dropmarker_description "Additional Actions">

View File

@ -7,19 +7,31 @@ package org.mozilla.gecko.preferences;
import org.mozilla.gecko.R;
import org.mozilla.gecko.util.ThreadUtils;
import org.mozilla.gecko.RestrictedProfiles;
import org.mozilla.gecko.RestrictedProfiles.Restriction;
import java.util.Set;
import android.app.ProgressDialog;
import android.content.Context;
import android.preference.Preference;
import android.util.AttributeSet;
import android.util.Log;
class AndroidImportPreference extends MultiPrefMultiChoicePreference {
private static final String LOGTAG = "AndroidImport";
public static final String PREF_KEY = "android.not_a_preference.import_android";
private static final String PREF_KEY_PREFIX = "import_android.data.";
private final Context mContext;
public static class Handler implements GeckoPreferences.PrefHandler {
public boolean setupPref(Context context, Preference pref) {
return RestrictedProfiles.isAllowed(Restriction.DISALLOW_IMPORT_SETTINGS);
}
public void onChange(Context context, Preference pref, Object newValue) { }
}
public AndroidImportPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;

View File

@ -19,12 +19,13 @@ public class ClearOnShutdownPref implements GeckoPreferences.PrefHandler {
public static final String PREF = GeckoPreferences.NON_PREF_PREFIX + "history.clear_on_exit";
@Override
public void setupPref(Context context, Preference pref) {
public boolean setupPref(Context context, Preference pref) {
// The pref is initialized asynchronously. Read the pref explicitly
// here to make sure we have the data.
final SharedPreferences prefs = GeckoSharedPrefs.forProfile(context);
final Set<String> clearItems = PrefUtils.getStringSet(prefs, PREF, new HashSet<String>());
((ListCheckboxPreference) pref).setChecked(clearItems.size() > 0);
return true;
}
@Override

View File

@ -700,6 +700,12 @@ OnSharedPreferenceChangeListener
i--;
continue;
} else if (PREFS_DEVTOOLS_REMOTE_ENABLED.equals(key)) {
if (!RestrictedProfiles.isAllowed(RestrictedProfiles.Restriction.DISALLOW_REMOTE_DEBUGGING)) {
preferences.removePreference(pref);
i--;
continue;
}
final Context thisContext = this;
pref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
@ -744,7 +750,11 @@ OnSharedPreferenceChangeListener
continue;
} else if (handlers.containsKey(key)) {
PrefHandler handler = handlers.get(key);
handler.setupPref(this, pref);
if (!handler.setupPref(this, pref)) {
preferences.removePreference(pref);
i--;
continue;
}
}
// Some Preference UI elements are not actually preferences,
@ -1026,13 +1036,16 @@ OnSharedPreferenceChangeListener
}
public interface PrefHandler {
public void setupPref(Context context, Preference pref);
// Allows the pref to do any initialization it needs. Return false to have the pref removed
// from the prefs screen entirely.
public boolean setupPref(Context context, Preference pref);
public void onChange(Context context, Preference pref, Object newValue);
}
@SuppressWarnings("serial")
private final Map<String, PrefHandler> handlers = new HashMap<String, PrefHandler>() {{
put(ClearOnShutdownPref.PREF, new ClearOnShutdownPref());
put(AndroidImportPreference.PREF_KEY, new AndroidImportPreference.Handler());
}};
@Override

View File

@ -14,7 +14,7 @@
android:background="@android:color/white">
<org.mozilla.gecko.home.TabMenuStrip android:layout_width="match_parent"
android:layout_height="32dip"
android:layout_height="@dimen/tabs_strip_height"
android:background="@color/background_light"
android:layout_gravity="top"
gecko:strip="@drawable/home_tab_menu_strip"/>

View File

@ -14,7 +14,7 @@
android:background="@android:color/white">
<org.mozilla.gecko.home.HomePagerTabStrip android:layout_width="match_parent"
android:layout_height="40dip"
android:layout_height="@dimen/tabs_strip_height"
android:layout_gravity="top"
android:gravity="center_vertical"
android:background="@color/background_light"

View File

@ -16,5 +16,5 @@
<org.mozilla.gecko.home.HomeListView android:id="@+id/list"
style="@style/Widget.ReadingListView"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
android:layout_height="match_parent"/>
</LinearLayout>

View File

@ -6,5 +6,5 @@
<org.mozilla.gecko.home.ReadingListRow xmlns:android="http://schemas.android.com/apk/res/android"
style="@style/Widget.BookmarkItemView"
android:layout_width="match_parent"
android:layout_height="@dimen/page_row_height"
android:minHeight="@dimen/page_row_height"/>
android:layout_height="wrap_content"
android:padding="10dp"/>

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/title"
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="1"
style="@style/Widget.ReadingListRow.Title" />
<TextView
android:id="@+id/read_time"
android:layout_width="wrap_content"
android:layout_height="match_parent"
style="@style/Widget.ReadingListRow.ReadTime" />
</LinearLayout>
<TextView
android:id="@+id/excerpt"
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.ReadingListRow.Description" />
</merge>

View File

@ -71,9 +71,4 @@
<item name="android:layout_gravity">center</item>
</style>
<style name="Widget.Home.HomeList">
<item name="topDivider">true</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
</style>
</resources>

View File

@ -17,6 +17,12 @@
<item name="android:fontFamily">sans-serif-light</item>
</style>
<style name="Widget.ReadingListRow.ReadTime">
<item name="android:textStyle">italic</item>
<item name="android:textColor">#FF9400</item>
<item name="android:fontFamily">sans-serif-condensed</item>
</style>
<style name="OnboardStartTextAppearance.Subtext">
<item name="android:textSize">18sp</item>
<item name="android:fontFamily">sans-serif-light</item>

View File

@ -19,11 +19,6 @@
<item name="android:verticalSpacing">20dp</item>
</style>
<style name="Widget.Home.HomeList">
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>
<!-- Tabs panel -->
<style name="TabsPanelFrame.RemoteTabs" parent="TabsPanelFrameBase">
<item name="android:paddingLeft">0dp</item>

View File

@ -16,11 +16,6 @@
<item name="android:layout_height">48dip</item>
</style>
<style name="Widget.Home.HomeList">
<item name="android:scrollbarStyle">outsideOverlay</item>
<item name="topDivider">true</item>
</style>
<!-- Tabs panel -->
<style name="TabsPanelFrame.RemoteTabs" parent="TabsPanelFrameBase">
<item name="android:paddingLeft">212dp</item>

View File

@ -105,8 +105,10 @@
<dimen name="tabs_panel_list_padding">16dip</dimen>
<dimen name="tabs_list_divider_height">2dp</dimen>
<dimen name="tabs_sidebar_width">200dp</dimen>
<dimen name="tabs_strip_height">40dp</dimen>
<dimen name="tabs_strip_button_width">100dp</dimen>
<dimen name="tabs_strip_button_padding">18dp</dimen>
<dimen name="tabs_strip_shadow_size">1dp</dimen>
<dimen name="tabs_tray_horizontal_height">156dp</dimen>
<dimen name="text_selection_handle_width">47dp</dimen>
<dimen name="text_selection_handle_height">58dp</dimen>

View File

@ -63,10 +63,6 @@
</style>
<style name="Widget.Home.HomeList">
<item name="android:paddingTop">0dip</item>
<item name="android:paddingRight">0dip</item>
<item name="android:paddingLeft">0dip</item>
<item name="topDivider">true</item>
<item name="android:scrollbarStyle">outsideOverlay</item>
</style>
@ -131,6 +127,25 @@
<item name="android:ellipsize">middle</item>
</style>
<style name="Widget.ReadingListRow" />
<style name="Widget.ReadingListRow.Title">
<item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemTitle</item>
<item name="android:maxLines">2</item>
<item name="android:ellipsize">end</item>
</style>
<style name="Widget.ReadingListRow.Description">
<item name="android:textAppearance">@style/TextAppearance.Widget.Home.ItemDescription</item>
<item name="android:maxLines">4</item>
<item name="android:ellipsize">end</item>
</style>
<style name="Widget.ReadingListRow.ReadTime">
<item name="android:textStyle">italic</item>
<item name="android:textColor">@color/text_color_highlight</item>
</style>
<style name="Widget.BookmarkFolderView" parent="Widget.TwoLinePageRow.Title">
<item name="android:singleLine">true</item>
<item name="android:ellipsize">none</item>
@ -229,7 +244,7 @@
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">32dp</item>
<item name="android:textAppearance">@style/TextAppearance.Widget.Home.Header</item>
<item name="android:background">#fff5f7f9</item>
<item name="android:background">@color/background_light</item>
<item name="android:focusable">false</item>
<item name="android:gravity">center|left</item>
<item name="android:paddingLeft">10dip</item>

View File

@ -298,6 +298,8 @@
<string name="reading_list_added">&reading_list_added;</string>
<string name="reading_list_failed">&reading_list_failed;</string>
<string name="reading_list_duplicate">&reading_list_duplicate;</string>
<string name="reading_list_time_minutes">&reading_list_time_minutes;</string>
<string name="reading_list_time_over_an_hour">&reading_list_time_over_an_hour;</string>
<string name="page_action_dropmarker_description">&page_action_dropmarker_description;</string>

View File

@ -537,7 +537,7 @@ var Addons = {
// Go back if we're in the detail view of the add-on that was uninstalled.
let detailItem = document.querySelector("#addons-details > .addon-item");
if (detailItem.addon == aAddon) {
if (detailItem.addon.id == aAddon.id) {
history.back();
}
},

View File

@ -465,7 +465,7 @@ var BrowserApp = {
if (this._startupStatus)
this.onAppUpdated();
if (!ParentalControls.isAllowed(ParentalControls.INSTALL_EXTENSIONS)) {
if (!ParentalControls.isAllowed(ParentalControls.INSTALL_EXTENSION)) {
// Disable extension installs
Services.prefs.setIntPref("extensions.enabledScopes", 1);
Services.prefs.setIntPref("extensions.autoDisableScopes", 1);

View File

@ -5,7 +5,7 @@
MOZ_APP_BASENAME=Fennec
MOZ_APP_VENDOR=Mozilla
MOZ_APP_VERSION=35.0a1
MOZ_APP_VERSION=36.0a1
MOZ_APP_UA_NAME=Firefox
MOZ_BRANDING_DIRECTORY=mobile/android/branding/unofficial

View File

@ -102,8 +102,13 @@ public class SearchWidget extends AppWidgetProvider {
// Utility to create the view for this widget and attach any event listeners to it
private void addView(final AppWidgetManager manager, final Context context, final int id, final Bundle options) {
final int category = options.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
final boolean isKeyguard = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
final boolean isKeyguard;
if (options != null) {
final int category = options.getInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY, -1);
isKeyguard = category == AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
} else {
isKeyguard = false;
}
final RemoteViews views;
if (isKeyguard) {

View File

@ -47,8 +47,6 @@ extern PRLogModuleInfo* gRtspLog;
#undef LOG
#define LOG(args) PR_LOG(gRtspLog, PR_LOG_DEBUG, args)
const unsigned long kCommandDelayMs = 200;
namespace mozilla {
namespace net {
@ -59,10 +57,7 @@ NS_IMPL_ISUPPORTS(RtspController,
nsIStreamingProtocolController)
RtspController::RtspController(nsIChannel *channel)
: mState(INIT),
mTimerLock("RtspController.mTimerLock"),
mPlayTimer(nullptr),
mPauseTimer(nullptr)
: mState(INIT)
{
LOG(("RtspController::RtspController()"));
}
@ -99,26 +94,7 @@ RtspController::Play(void)
return NS_ERROR_NOT_CONNECTED;
}
MutexAutoLock lock(mTimerLock);
// Cancel the pause timer if it is active because successive pause-play in a
// short duration is unnecessary but could impair playback smoothing.
if (mPauseTimer) {
mPauseTimer->Cancel();
mPauseTimer = nullptr;
}
// Start a timer to delay the play operation for a short duration.
if (!mPlayTimer) {
mPlayTimer = do_CreateInstance("@mozilla.org/timer;1");
if (!mPlayTimer) {
return NS_ERROR_NOT_INITIALIZED;
}
mPlayTimer->InitWithFuncCallback(
RtspController::PlayTimerCallback,
this, kCommandDelayMs,
nsITimer::TYPE_ONE_SHOT);
}
mRtspSource->play();
return NS_OK;
}
@ -135,26 +111,7 @@ RtspController::Pause(void)
return NS_ERROR_NOT_CONNECTED;
}
MutexAutoLock lock(mTimerLock);
// Cancel the play timer if it is active because successive play-pause in a
// short duration is unnecessary but could impair playback smoothing.
if (mPlayTimer) {
mPlayTimer->Cancel();
mPlayTimer = nullptr;
}
// Start a timer to delay the pause operation for a short duration.
if (!mPauseTimer) {
mPauseTimer = do_CreateInstance("@mozilla.org/timer;1");
if (!mPauseTimer) {
return NS_ERROR_NOT_INITIALIZED;
}
mPauseTimer->InitWithFuncCallback(
RtspController::PauseTimerCallback,
this, kCommandDelayMs,
nsITimer::TYPE_ONE_SHOT);
}
mRtspSource->pause();
return NS_OK;
}
@ -360,19 +317,6 @@ RtspController::OnDisconnected(uint8_t index,
LOG(("RtspController::OnDisconnected() for track %d reason = 0x%x", index, reason));
mState = DISCONNECTED;
// Ensure play and pause timer are stopped.
{
MutexAutoLock lock(mTimerLock);
if (mPlayTimer) {
mPlayTimer->Cancel();
mPlayTimer = nullptr;
}
if (mPauseTimer) {
mPauseTimer->Cancel();
mPauseTimer = nullptr;
}
}
if (mListener) {
nsRefPtr<SendOnDisconnectedTask> task =
new SendOnDisconnectedTask(mListener, index, reason);
@ -436,40 +380,5 @@ RtspController::PlaybackEnded()
return NS_OK;
}
//-----------------------------------------------------------------------------
// RtspController static member methods
//-----------------------------------------------------------------------------
//static
void RtspController::PlayTimerCallback(nsITimer *aTimer, void *aClosure)
{
MOZ_ASSERT(aTimer);
MOZ_ASSERT(aClosure);
RtspController *self = static_cast<RtspController*>(aClosure);
MOZ_ASSERT(self->mRtspSource.get());
MutexAutoLock lock(self->mTimerLock);
if (self->mPlayTimer) {
self->mRtspSource->play();
self->mPlayTimer = nullptr;
}
}
//static
void RtspController::PauseTimerCallback(nsITimer *aTimer, void *aClosure)
{
MOZ_ASSERT(aTimer);
MOZ_ASSERT(aClosure);
RtspController *self = static_cast<RtspController*>(aClosure);
MOZ_ASSERT(self->mRtspSource.get());
MutexAutoLock lock(self->mTimerLock);
if (self->mPauseTimer) {
self->mRtspSource->pause();
self->mPauseTimer = nullptr;
}
}
} // namespace mozilla::net
} // namespace mozilla

View File

@ -7,12 +7,10 @@
#ifndef RtspController_h
#define RtspController_h
#include "mozilla/Mutex.h"
#include "nsIStreamingProtocolController.h"
#include "nsIChannel.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "nsITimer.h"
#include "RTSPSource.h"
namespace mozilla {
@ -29,10 +27,6 @@ public:
RtspController(nsIChannel *channel);
~RtspController();
// These callbacks will be called when mPlayTimer/mPauseTimer fires.
static void PlayTimerCallback(nsITimer *aTimer, void *aClosure);
static void PauseTimerCallback(nsITimer *aTimer, void *aClosure);
private:
enum State {
INIT,
@ -53,13 +47,6 @@ private:
State mState;
// Rtsp Streaming source.
android::sp<android::RTSPSource> mRtspSource;
// This lock protects mPlayTimer and mPauseTimer.
Mutex mTimerLock;
// Timers to delay the play and pause operations.
// They are used for optimization and avoid sending unnecessary requests to
// the server.
nsCOMPtr<nsITimer> mPlayTimer;
nsCOMPtr<nsITimer> mPauseTimer;
};
}

View File

@ -21,6 +21,8 @@ PRLogModuleInfo* gRtspChildLog = nullptr;
#define LOG(args) PR_LOG(gRtspChildLog, PR_LOG_DEBUG, args)
const uint32_t kRtspTotalTracks = 2;
const unsigned long kRtspCommandDelayMs = 200;
using namespace mozilla::ipc;
namespace mozilla {
@ -64,6 +66,9 @@ RtspControllerChild::RtspControllerChild(nsIChannel *channel)
, mChannel(channel)
, mTotalTracks(0)
, mSuspendCount(0)
, mTimerLock("RtspControllerChild.mTimerLock")
, mPlayTimer(nullptr)
, mPauseTimer(nullptr)
{
#if defined(PR_LOGGING)
if (!gRtspChildLog)
@ -108,6 +113,20 @@ RtspControllerChild::DisallowIPC()
mIPCAllowed = false;
}
void
RtspControllerChild::StopPlayAndPauseTimer()
{
MutexAutoLock lock(mTimerLock);
if (mPlayTimer) {
mPlayTimer->Cancel();
mPlayTimer = nullptr;
}
if (mPauseTimer) {
mPauseTimer->Cancel();
mPauseTimer = nullptr;
}
}
//-----------------------------------------------------------------------------
// RtspControllerChild::PRtspControllerChild
//-----------------------------------------------------------------------------
@ -174,6 +193,7 @@ RtspControllerChild::RecvOnDisconnected(
const uint8_t& index,
const nsresult& reason)
{
StopPlayAndPauseTimer();
DisallowIPC();
LOG(("RtspControllerChild::RecvOnDisconnected for track %d reason = 0x%x", index, reason));
if (mListener) {
@ -186,6 +206,7 @@ RtspControllerChild::RecvOnDisconnected(
bool
RtspControllerChild::RecvAsyncOpenFailed(const nsresult& reason)
{
StopPlayAndPauseTimer();
DisallowIPC();
LOG(("RtspControllerChild::RecvAsyncOpenFailed reason = 0x%x", reason));
if (mListener) {
@ -234,8 +255,6 @@ enum IPCEvent
SendPlayEvent,
SendPauseEvent,
SendSeekEvent,
SendResumeEvent,
SendSuspendEvent,
SendStopEvent,
SendPlaybackEndedEvent
};
@ -275,10 +294,6 @@ public:
rv = mController->SendPause();
} else if (mEvent == SendSeekEvent) {
rv = mController->SendSeek(mSeekTime);
} else if (mEvent == SendResumeEvent) {
rv = mController->SendResume();
} else if (mEvent == SendSuspendEvent) {
rv = mController->SendSuspend();
} else if (mEvent == SendStopEvent) {
rv = mController->SendStop();
} else if (mEvent == SendPlaybackEndedEvent) {
@ -305,14 +320,30 @@ RtspControllerChild::Play(void)
{
LOG(("RtspControllerChild::Play()"));
if (NS_IsMainThread()) {
if (!OKToSendIPC() || !SendPlay()) {
return NS_ERROR_FAILURE;
MutexAutoLock lock(mTimerLock);
// Cancel the pause timer if it is active because successive pause-play in a
// short duration is unncessary but could impair playback smoothing.
if (mPauseTimer) {
mPauseTimer->Cancel();
mPauseTimer = nullptr;
}
// Start a timer to delay the play operation for a short duration.
if (!mPlayTimer) {
mPlayTimer = do_CreateInstance("@mozilla.org/timer;1");
if (!mPlayTimer) {
return NS_ERROR_NOT_INITIALIZED;
}
} else {
nsresult rv = NS_DispatchToMainThread(
new SendIPCEvent(this, SendPlayEvent));
NS_ENSURE_SUCCESS(rv, rv);
// We have to dispatch the timer callback to the main thread because the
// decoder thread is a thread from nsIThreadPool and cannot be the timer
// target. Furthermore, IPC send functions should only be called from the
// main thread.
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
mPlayTimer->SetTarget(mainThread);
mPlayTimer->InitWithFuncCallback(
RtspControllerChild::PlayTimerCallback,
this, kRtspCommandDelayMs,
nsITimer::TYPE_ONE_SHOT);
}
return NS_OK;
@ -323,14 +354,29 @@ RtspControllerChild::Pause(void)
{
LOG(("RtspControllerChild::Pause()"));
if (NS_IsMainThread()) {
if (!OKToSendIPC() || !SendPause()) {
return NS_ERROR_FAILURE;
MutexAutoLock lock(mTimerLock);
// Cancel the play timer if it is active because successive play-pause in a
// shrot duration is unnecessary but could impair playback smoothing.
if (mPlayTimer) {
mPlayTimer->Cancel();
mPlayTimer = nullptr;
}
// Start a timer to delay the pause operation for a short duration.
if (!mPauseTimer) {
mPauseTimer = do_CreateInstance("@mozilla.org/timer;1");
if (!mPauseTimer) {
return NS_ERROR_NOT_INITIALIZED;
}
} else {
nsresult rv = NS_DispatchToMainThread(
new SendIPCEvent(this, SendPauseEvent));
NS_ENSURE_SUCCESS(rv, rv);
// We have to dispatch the timer callback to the main thread because the
// decoder thread is a thread from nsIThreadPool and cannot be the timer
// target.
nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
mPauseTimer->SetTarget(mainThread);
mPauseTimer->InitWithFuncCallback(
RtspControllerChild::PauseTimerCallback,
this, kRtspCommandDelayMs,
nsITimer::TYPE_ONE_SHOT);
}
return NS_OK;
@ -343,15 +389,7 @@ RtspControllerChild::Resume(void)
NS_ENSURE_TRUE(mSuspendCount > 0, NS_ERROR_UNEXPECTED);
if (!--mSuspendCount) {
if (NS_IsMainThread()) {
if (!OKToSendIPC() || !SendResume()) {
return NS_ERROR_FAILURE;
}
} else {
nsresult rv = NS_DispatchToMainThread(
new SendIPCEvent(this, SendResumeEvent));
NS_ENSURE_SUCCESS(rv, rv);
}
return Play();
}
return NS_OK;
@ -363,15 +401,7 @@ RtspControllerChild::Suspend(void)
LOG(("RtspControllerChild::Suspend()"));
if (!mSuspendCount++) {
if (NS_IsMainThread()) {
if (!OKToSendIPC() || !SendSuspend()) {
return NS_ERROR_FAILURE;
}
} else {
nsresult rv = NS_DispatchToMainThread(
new SendIPCEvent(this, SendSuspendEvent));
NS_ENSURE_SUCCESS(rv, rv);
}
return Pause();
}
return NS_OK;
@ -399,6 +429,7 @@ NS_IMETHODIMP
RtspControllerChild::Stop()
{
LOG(("RtspControllerChild::Stop()"));
StopPlayAndPauseTimer();
if (NS_IsMainThread()) {
if (!OKToSendIPC() || !SendStop()) {
@ -542,5 +573,44 @@ RtspControllerChild::AsyncOpen(nsIStreamingProtocolListener *aListener)
return NS_OK;
}
//-----------------------------------------------------------------------------
// RtspControllerChild static member methods
//-----------------------------------------------------------------------------
//static
void
RtspControllerChild::PlayTimerCallback(nsITimer *aTimer, void *aClosure)
{
MOZ_ASSERT(aTimer);
MOZ_ASSERT(aClosure);
MOZ_ASSERT(NS_IsMainThread());
RtspControllerChild *self = static_cast<RtspControllerChild*>(aClosure);
MutexAutoLock lock(self->mTimerLock);
if (!self->mPlayTimer || !self->OKToSendIPC()) {
return;
}
self->SendPlay();
self->mPlayTimer = nullptr;
}
//static
void
RtspControllerChild::PauseTimerCallback(nsITimer *aTimer, void *aClosure)
{
MOZ_ASSERT(aTimer);
MOZ_ASSERT(aClosure);
MOZ_ASSERT(NS_IsMainThread());
RtspControllerChild *self = static_cast<RtspControllerChild*>(aClosure);
MutexAutoLock lock(self->mTimerLock);
if (!self->mPauseTimer || !self->OKToSendIPC()) {
return;
}
self->SendPause();
self->mPauseTimer = nullptr;
}
} // namespace net
} // namespace mozilla

View File

@ -14,6 +14,8 @@
#include "nsString.h"
#include "nsTArray.h"
#include "mozilla/net/RtspChannelChild.h"
#include "mozilla/Mutex.h"
#include "nsITimer.h"
namespace mozilla {
namespace net {
@ -52,6 +54,10 @@ class RtspControllerChild : public nsIStreamingProtocolController
void AllowIPC();
void DisallowIPC();
// These callbacks will be called when mPlayTimer/mPauseTimer fires.
static void PlayTimerCallback(nsITimer *aTimer, void *aClosure);
static void PauseTimerCallback(nsITimer *aTimer, void *aClosure);
private:
bool mIPCOpen;
// The intention of this variable is just to avoid any IPC message to be sent
@ -73,6 +79,16 @@ class RtspControllerChild : public nsIStreamingProtocolController
uint32_t mSuspendCount;
// Detach channel-controller relationship.
void ReleaseChannel();
// This lock protects mPlayTimer and mPauseTimer.
Mutex mTimerLock;
// Timers to delay the play and pause operations.
// They are used for optimization and to avoid sending unnecessary requests to
// the server.
nsCOMPtr<nsITimer> mPlayTimer;
nsCOMPtr<nsITimer> mPauseTimer;
// Timers should be stopped if we are going to terminate, such as when
// receiving Stop command or OnDisconnected event.
void StopPlayAndPauseTimer();
};
} // namespace net
} // namespace mozilla

View File

@ -3,7 +3,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# Definitions used by constants.js.
weave_version := 1.37.0
weave_version := 1.38.0
weave_id := {340c2bbc-ce74-4362-90b5-7c26312808ef}
# Preprocess files.

View File

@ -11,7 +11,7 @@ interface nsIFile;
interface nsIInterfaceRequestor;
interface nsIArray;
[scriptable, uuid(4bde6754-406a-45d1-b18e-dc685adc1db4)]
[scriptable, uuid(e7bcc22c-e9fc-4e7d-88b9-7482399b322d)]
interface nsIParentalControlsService : nsISupports
{
/**
@ -26,6 +26,8 @@ interface nsIParentalControlsService : nsISupports
const short ADD_CONTACT = 7; // Add contacts to the system database
const short SET_IMAGE = 8; // Setting images as wall paper
const short MODIFY_ACCOUNTS = 9; // Modifying system accounts
const short REMOTE_DEBUGGING = 10; // Remote debugging
const short IMPORT_SETTINGS = 11; // Importing settings from other apps
/**
* @returns true if the current user account has parental controls

View File

@ -21,7 +21,7 @@ namespace mozilla {
*/
struct Module
{
static const unsigned int kVersion = 35;
static const unsigned int kVersion = 36;
struct CIDEntry;