mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge latest green inbound changeset and mozilla-central
This commit is contained in:
commit
2a2f5c9d13
@ -4,7 +4,7 @@
|
||||
|
||||
#filter substitution
|
||||
|
||||
pref("toolkit.defaultChromeURI", "chrome://browser/content/shell.html");
|
||||
pref("toolkit.defaultChromeURI", "chrome://browser/content/shell.xul");
|
||||
pref("browser.chromeURL", "chrome://browser/content/");
|
||||
|
||||
// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
|
||||
|
@ -11,7 +11,7 @@ window.addEventListener('ContentStart', function() {
|
||||
let shell = document.getElementById('shell');
|
||||
|
||||
// The <browser> element inside it
|
||||
let browser = document.getElementById('systemapp');
|
||||
let browser = document.getElementById('homescreen');
|
||||
|
||||
// Figure out the native resolution of the screen
|
||||
let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
|
@ -1,33 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<!-- 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/. -->
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml"
|
||||
id="shell"
|
||||
windowtype="navigator:browser"
|
||||
#ifdef ANDROID
|
||||
sizemode="fullscreen"
|
||||
#endif
|
||||
style="background: black; overflow: hidden; width:100%; height:100%; padding: 0px !important"
|
||||
onunload="shell.stop();">
|
||||
|
||||
<head>
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://browser/content/settings.js"> </script>
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://browser/content/shell.js"> </script>
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
<!-- this script handles the screen argument for desktop builds -->
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://browser/content/screen.js"> </script>
|
||||
<!-- this script handles the "runapp" argument for desktop builds -->
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://browser/content/runapp.js"> </script>
|
||||
#endif
|
||||
</head>
|
||||
<body id="container" style="margin: 0px; width:100%; height:100%;">
|
||||
<!-- The html:iframe containing the UI is created here. -->
|
||||
</body>
|
||||
</html>
|
@ -6,9 +6,6 @@
|
||||
|
||||
Cu.import('resource://gre/modules/ContactService.jsm');
|
||||
Cu.import('resource://gre/modules/SettingsChangeNotifier.jsm');
|
||||
#ifdef MOZ_B2G_FM
|
||||
Cu.import('resource://gre/modules/DOMFMRadioParent.jsm');
|
||||
#endif
|
||||
Cu.import('resource://gre/modules/AlarmService.jsm');
|
||||
Cu.import('resource://gre/modules/ActivitiesService.jsm');
|
||||
Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
|
||||
@ -186,7 +183,7 @@ var shell = {
|
||||
|
||||
get contentBrowser() {
|
||||
delete this.contentBrowser;
|
||||
return this.contentBrowser = document.getElementById('systemapp');
|
||||
return this.contentBrowser = document.getElementById('homescreen');
|
||||
},
|
||||
|
||||
get homeURL() {
|
||||
@ -269,25 +266,25 @@ var shell = {
|
||||
}
|
||||
|
||||
let manifestURL = this.manifestURL;
|
||||
// <html:iframe id="systemapp"
|
||||
// <html:iframe id="homescreen"
|
||||
// mozbrowser="true" allowfullscreen="true"
|
||||
// style="overflow: hidden; height: 100%; width: 100%; border: none;"
|
||||
// style="overflow: hidden; -moz-box-flex: 1; border: none;"
|
||||
// src="data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;'>"/>
|
||||
let systemAppFrame =
|
||||
let browserFrame =
|
||||
document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe');
|
||||
systemAppFrame.setAttribute('id', 'systemapp');
|
||||
systemAppFrame.setAttribute('mozbrowser', 'true');
|
||||
systemAppFrame.setAttribute('mozapp', manifestURL);
|
||||
systemAppFrame.setAttribute('allowfullscreen', 'true');
|
||||
systemAppFrame.setAttribute('style', "overflow: hidden; height: 100%; width: 100%; border: none;");
|
||||
systemAppFrame.setAttribute('src', "data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;");
|
||||
document.getElementById('container').appendChild(systemAppFrame);
|
||||
browserFrame.setAttribute('id', 'homescreen');
|
||||
browserFrame.setAttribute('mozbrowser', 'true');
|
||||
browserFrame.setAttribute('mozapp', manifestURL);
|
||||
browserFrame.setAttribute('allowfullscreen', 'true');
|
||||
browserFrame.setAttribute('style', "overflow: hidden; -moz-box-flex: 1; border: none;");
|
||||
browserFrame.setAttribute('src', "data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;");
|
||||
document.getElementById('shell').appendChild(browserFrame);
|
||||
|
||||
systemAppFrame.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
|
||||
.createInstance(Ci.nsISHistory);
|
||||
browserFrame.contentWindow
|
||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebNavigation)
|
||||
.sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
|
||||
.createInstance(Ci.nsISHistory);
|
||||
|
||||
// Capture all key events so we can filter out hardware buttons
|
||||
// And send them to Gaia via mozChromeEvents.
|
||||
|
26
b2g/chrome/content/shell.xul
Normal file
26
b2g/chrome/content/shell.xul
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.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/. -->
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
id="shell"
|
||||
windowtype="navigator:browser"
|
||||
#ifdef ANDROID
|
||||
sizemode="fullscreen"
|
||||
#endif
|
||||
style="background: black; overflow: hidden; width:320px; height:480px"
|
||||
onunload="shell.stop();">
|
||||
|
||||
<script type="application/javascript" src="chrome://browser/content/settings.js"/>
|
||||
<script type="application/javascript" src="chrome://browser/content/shell.js"/>
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
<!-- this script handles the screen argument for desktop builds -->
|
||||
<script type="application/javascript" src="chrome://browser/content/screen.js"/>
|
||||
<!-- this script handles the "runapp" argument for desktop builds -->
|
||||
<script type="application/javascript" src="chrome://browser/content/runapp.js"/>
|
||||
#endif
|
||||
<!-- The html:iframe containing the UI is created here. -->
|
||||
</window>
|
@ -12,7 +12,7 @@ chrome.jar:
|
||||
* content/dbg-browser-actors.js (content/dbg-browser-actors.js)
|
||||
content/forms.js (content/forms.js)
|
||||
* content/settings.js (content/settings.js)
|
||||
* content/shell.html (content/shell.html)
|
||||
* content/shell.xul (content/shell.xul)
|
||||
* content/shell.js (content/shell.js)
|
||||
#ifndef ANDROID
|
||||
content/screen.js (content/screen.js)
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "f2d88904536ccd68a3981a7feb17e56b2132838c",
|
||||
"revision": "752ced5b3cc3208f79806eccf8d8768910f17f2b",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -172,9 +172,6 @@
|
||||
@BINPATH@/components/dom_cellbroadcast.xpt
|
||||
@BINPATH@/components/dom_wappush.xpt
|
||||
#endif
|
||||
#ifdef MOZ_B2G_FM
|
||||
@BINPATH@/components/dom_fm.xpt
|
||||
#endif
|
||||
#ifdef MOZ_B2G_BT
|
||||
@BINPATH@/components/dom_bluetooth.xpt
|
||||
#endif
|
||||
@ -475,10 +472,6 @@
|
||||
@BINPATH@/components/NetworkInterfaceListService.manifest
|
||||
@BINPATH@/components/NetworkInterfaceListService.js
|
||||
#endif
|
||||
#ifdef MOZ_B2G_FM
|
||||
@BINPATH@/components/DOMFMRadioChild.js
|
||||
@BINPATH@/components/DOMFMRadio.manifest
|
||||
#endif
|
||||
#ifdef MOZ_ENABLE_DBUS
|
||||
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
|
||||
#endif
|
||||
|
56
browser/base/content/aboutTabCrashed.xhtml
Normal file
56
browser/base/content/aboutTabCrashed.xhtml
Normal file
@ -0,0 +1,56 @@
|
||||
<?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/. -->
|
||||
|
||||
<!DOCTYPE html [
|
||||
<!ENTITY % htmlDTD
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"DTD/xhtml1-strict.dtd">
|
||||
%htmlDTD;
|
||||
<!ENTITY % globalDTD
|
||||
SYSTEM "chrome://global/locale/global.dtd">
|
||||
%globalDTD;
|
||||
<!ENTITY % browserDTD
|
||||
SYSTEM "chrome://browser/locale/browser.dtd">
|
||||
%browserDTD;
|
||||
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<link rel="stylesheet" type="text/css" media="all"
|
||||
href="chrome://browser/skin/aboutTabCrashed.css"/>
|
||||
</head>
|
||||
|
||||
<body dir="&locale.dir;">
|
||||
<div id="error-box">
|
||||
<p id="main-error-msg">&tabCrashed.header;</p>
|
||||
<p id="helper-error-msg">&tabCrashed.message;</p>
|
||||
</div>
|
||||
|
||||
<div id="button-box">
|
||||
<button id="tryAgain">&tabCrashed.tryAgain;</button>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<script type="text/javascript;version=1.8"><![CDATA[
|
||||
function parseQueryString() {
|
||||
let url = document.documentURI;
|
||||
let queryString = url.replace(/^about:tabcrashed?e=tabcrashed/, "");
|
||||
|
||||
let urlMatch = queryString.match(/u=([^&]+)/);
|
||||
let url = urlMatch && urlMatch[1] ? decodeURIComponent(urlMatch[1]) : "";
|
||||
|
||||
let titleMatch = queryString.match(/d=([^&]*)/);
|
||||
title = titleMatch && titleMatch[1] ? decodeURIComponent(titleMatch[1]) : "";
|
||||
|
||||
return [url, title];
|
||||
}
|
||||
|
||||
let [url, title] = parseQueryString();
|
||||
document.title = title;
|
||||
document.getElementById("tryAgain").setAttribute("url", url);
|
||||
]]></script>
|
||||
</html>
|
@ -2341,6 +2341,9 @@ let BrowserOnClick = {
|
||||
ownerDoc.documentURI.toLowerCase() == "about:newtab") {
|
||||
this.onE10sAboutNewTab(aEvent, ownerDoc);
|
||||
}
|
||||
else if (ownerDoc.documentURI.startsWith("about:tabcrashed")) {
|
||||
this.onAboutTabCrashed(aEvent, ownerDoc);
|
||||
}
|
||||
},
|
||||
|
||||
onAboutCertError: function BrowserOnClick_onAboutCertError(aTargetElm, aOwnerDoc) {
|
||||
@ -2473,6 +2476,22 @@ let BrowserOnClick = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* The about:tabcrashed can't do window.reload() because that
|
||||
* would reload the page but not use a remote browser.
|
||||
*/
|
||||
onAboutTabCrashed: function(aEvent, aOwnerDoc) {
|
||||
let isTopFrame = (aOwnerDoc.defaultView.parent === aOwnerDoc.defaultView);
|
||||
if (!isTopFrame) {
|
||||
return;
|
||||
}
|
||||
|
||||
let button = aEvent.originalTarget;
|
||||
if (button.id == "tryAgain") {
|
||||
openUILinkIn(button.getAttribute("url"), "current");
|
||||
}
|
||||
},
|
||||
|
||||
ignoreWarningButton: function BrowserOnClick_ignoreWarningButton(aIsMalware) {
|
||||
// Allow users to override and continue through to the site,
|
||||
// but add a notify bar as a reminder, so that they don't lose
|
||||
@ -2582,6 +2601,16 @@ function getWebNavigation()
|
||||
}
|
||||
|
||||
function BrowserReloadWithFlags(reloadFlags) {
|
||||
let url = gBrowser.currentURI.spec;
|
||||
if (gBrowser._updateBrowserRemoteness(gBrowser.selectedBrowser,
|
||||
gBrowser._shouldBrowserBeRemote(url))) {
|
||||
// If the remoteness has changed, the new browser doesn't have any
|
||||
// information of what was loaded before, so we need to load the previous
|
||||
// URL again.
|
||||
gBrowser.loadURIWithFlags(url, reloadFlags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* First, we'll try to use the session history object to reload so
|
||||
* that framesets are handled properly. If we're in a special
|
||||
* window (such as view-source) that has no session history, fall
|
||||
|
@ -1317,7 +1317,7 @@
|
||||
<![CDATA[
|
||||
let isRemote = aBrowser.getAttribute("remote") == "true";
|
||||
if (isRemote == aRemote)
|
||||
return;
|
||||
return false;
|
||||
|
||||
// Unhook our progress listener.
|
||||
let tab = this._getTabForBrowser(aBrowser);
|
||||
@ -1338,6 +1338,8 @@
|
||||
tab.setAttribute("remote", "true");
|
||||
else
|
||||
tab.removeAttribute("remote");
|
||||
|
||||
return true;
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
@ -3118,6 +3120,22 @@
|
||||
tab.setAttribute("titlechanged", "true");
|
||||
]]>
|
||||
</handler>
|
||||
<handler event="oop-browser-crashed">
|
||||
<![CDATA[
|
||||
if (!event.isTrusted)
|
||||
return;
|
||||
|
||||
let browser = event.originalTarget;
|
||||
let title = browser.contentTitle;
|
||||
let uri = browser.currentURI;
|
||||
|
||||
this._updateBrowserRemoteness(browser, false);
|
||||
|
||||
browser.setAttribute("crashedPageTitle", title);
|
||||
browser.docShell.displayLoadError(Cr.NS_ERROR_CONTENT_CRASHED, uri, null);
|
||||
browser.removeAttribute("crashedPageTitle");
|
||||
]]>
|
||||
</handler>
|
||||
</handlers>
|
||||
</binding>
|
||||
|
||||
|
@ -55,6 +55,7 @@ browser.jar:
|
||||
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
|
||||
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
|
||||
content/browser/aboutSocialError.xhtml (content/aboutSocialError.xhtml)
|
||||
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
|
||||
* content/browser/browser.css (content/browser.css)
|
||||
* content/browser/browser.js (content/browser.js)
|
||||
* content/browser/browser.xul (content/browser.xul)
|
||||
|
@ -44,6 +44,10 @@ static RedirEntry kRedirMap[] = {
|
||||
{ "socialerror", "chrome://browser/content/aboutSocialError.xhtml",
|
||||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
|
||||
{ "tabcrashed", "chrome://browser/content/aboutTabCrashed.xhtml",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
|
||||
{ "feeds", "chrome://browser/content/feeds/subscribe.xhtml",
|
||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||
nsIAboutModule::ALLOW_SCRIPT |
|
||||
|
@ -90,6 +90,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
||||
#endif
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "socialerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "tabcrashed", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "feeds", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "rights", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||
|
@ -668,6 +668,10 @@ just addresses the organization to follow, e.g. "This site is run by " -->
|
||||
<!ENTITY pluginActivateAlways.label "Allow and Remember">
|
||||
<!ENTITY pluginBlockNow.label "Block Plugin">
|
||||
|
||||
<!ENTITY tabCrashed.header "Tab crashed">
|
||||
<!ENTITY tabCrashed.message "Well, this is embarrassing. We tried to display this Web page, but it's not responding.">
|
||||
<!ENTITY tabCrashed.tryAgain "Try Again">
|
||||
|
||||
<!-- LOCALIZATION NOTE: the following strings are unused in Australis, they're
|
||||
kept here to avoid warnings from l10n tools like compare-locales on
|
||||
l10n-central. They will be definitely removed when Australis is ready
|
||||
|
98
browser/themes/linux/aboutTabCrashed.css
Normal file
98
browser/themes/linux/aboutTabCrashed.css
Normal file
@ -0,0 +1,98 @@
|
||||
body {
|
||||
background-color: rgb(241, 244, 248);
|
||||
margin-top: 2em;
|
||||
font: message-box;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
#error-box {
|
||||
background: url('chrome://global/skin/icons/information-24.png') no-repeat left 4px;
|
||||
-moz-padding-start: 30px;
|
||||
}
|
||||
|
||||
#error-box:-moz-locale-dir(rtl) {
|
||||
background-position: right 4px;
|
||||
}
|
||||
|
||||
#main-error-msg {
|
||||
color: #4b4b4b;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
#button-box {
|
||||
text-align: center;
|
||||
width: 75%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media all and (min-width: 300px) {
|
||||
#error-box {
|
||||
max-width: 50%;
|
||||
margin: 0 auto;
|
||||
background-image: url('chrome://global/skin/icons/information-32.png');
|
||||
min-height: 36px;
|
||||
-moz-padding-start: 38px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: auto !important;
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 780px) {
|
||||
#error-box {
|
||||
max-width: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
font: message-box;
|
||||
font-size: 0.6875em;
|
||||
-moz-appearance: none;
|
||||
-moz-user-select: none;
|
||||
width: 100%;
|
||||
margin: 2px 0;
|
||||
padding: 2px 6px;
|
||||
line-height: 1.2;
|
||||
background-color: hsla(210,30%,95%,.1);
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
background-clip: padding-box;
|
||||
border: 1px solid hsla(210,15%,25%,.4);
|
||||
border-color: hsla(210,15%,25%,.3) hsla(210,15%,25%,.35) hsla(210,15%,25%,.4);
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.1);
|
||||
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: hsla(210,30%,95%,.8);
|
||||
border-color: hsla(210,15%,25%,.45) hsla(210,15%,25%,.5) hsla(210,15%,25%,.55);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.1),
|
||||
0 0 3px hsla(210,15%,25%,.1);
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
button:hover:active {
|
||||
background-color: hsla(210,15%,25%,.2);
|
||||
box-shadow: 0 1px 1px hsla(210,15%,25%,.2) inset,
|
||||
0 0 2px hsla(210,15%,25%,.4) inset;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 10ms;
|
||||
transition-timing-function: linear;
|
||||
}
|
@ -18,6 +18,7 @@ browser.jar:
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
#endif
|
||||
skin/classic/browser/aboutTabCrashed.css
|
||||
skin/classic/browser/actionicon-tab.png
|
||||
* skin/classic/browser/browser.css
|
||||
skin/classic/browser/click-to-play-warning-stripes.png
|
||||
|
98
browser/themes/osx/aboutTabCrashed.css
Normal file
98
browser/themes/osx/aboutTabCrashed.css
Normal file
@ -0,0 +1,98 @@
|
||||
body {
|
||||
background-color: rgb(241, 244, 248);
|
||||
margin-top: 2em;
|
||||
font: message-box;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
#error-box {
|
||||
background: url('chrome://global/skin/icons/information-24.png') no-repeat left 4px;
|
||||
-moz-padding-start: 30px;
|
||||
}
|
||||
|
||||
#error-box:-moz-locale-dir(rtl) {
|
||||
background-position: right 4px;
|
||||
}
|
||||
|
||||
#main-error-msg {
|
||||
color: #4b4b4b;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
#button-box {
|
||||
text-align: center;
|
||||
width: 75%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media all and (min-width: 300px) {
|
||||
#error-box {
|
||||
max-width: 50%;
|
||||
margin: 0 auto;
|
||||
background-image: url('chrome://global/skin/icons/information-32.png');
|
||||
min-height: 36px;
|
||||
-moz-padding-start: 38px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: auto !important;
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 780px) {
|
||||
#error-box {
|
||||
max-width: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
font: message-box;
|
||||
font-size: 0.6875em;
|
||||
-moz-appearance: none;
|
||||
-moz-user-select: none;
|
||||
width: 100%;
|
||||
margin: 2px 0;
|
||||
padding: 2px 6px;
|
||||
line-height: 1.2;
|
||||
background-color: hsla(210,30%,95%,.1);
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
background-clip: padding-box;
|
||||
border: 1px solid hsla(210,15%,25%,.4);
|
||||
border-color: hsla(210,15%,25%,.3) hsla(210,15%,25%,.35) hsla(210,15%,25%,.4);
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.1);
|
||||
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: hsla(210,30%,95%,.8);
|
||||
border-color: hsla(210,15%,25%,.45) hsla(210,15%,25%,.5) hsla(210,15%,25%,.55);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.1),
|
||||
0 0 3px hsla(210,15%,25%,.1);
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
button:hover:active {
|
||||
background-color: hsla(210,15%,25%,.2);
|
||||
box-shadow: 0 1px 1px hsla(210,15%,25%,.2) inset,
|
||||
0 0 2px hsla(210,15%,25%,.4) inset;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 10ms;
|
||||
transition-timing-function: linear;
|
||||
}
|
@ -17,6 +17,7 @@ browser.jar:
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
#endif
|
||||
skin/classic/browser/aboutTabCrashed.css
|
||||
skin/classic/browser/actionicon-tab.png
|
||||
skin/classic/browser/actionicon-tab@2x.png
|
||||
* skin/classic/browser/browser.css (browser.css)
|
||||
|
98
browser/themes/windows/aboutTabCrashed.css
Normal file
98
browser/themes/windows/aboutTabCrashed.css
Normal file
@ -0,0 +1,98 @@
|
||||
body {
|
||||
background-color: rgb(241, 244, 248);
|
||||
margin-top: 2em;
|
||||
font: message-box;
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: .8em;
|
||||
}
|
||||
|
||||
#error-box {
|
||||
background: url('chrome://global/skin/icons/information-24.png') no-repeat left 4px;
|
||||
-moz-padding-start: 30px;
|
||||
}
|
||||
|
||||
#error-box:-moz-locale-dir(rtl) {
|
||||
background-position: right 4px;
|
||||
}
|
||||
|
||||
#main-error-msg {
|
||||
color: #4b4b4b;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
|
||||
#button-box {
|
||||
text-align: center;
|
||||
width: 75%;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@media all and (min-width: 300px) {
|
||||
#error-box {
|
||||
max-width: 50%;
|
||||
margin: 0 auto;
|
||||
background-image: url('chrome://global/skin/icons/information-32.png');
|
||||
min-height: 36px;
|
||||
-moz-padding-start: 38px;
|
||||
}
|
||||
|
||||
button {
|
||||
width: auto !important;
|
||||
min-width: 150px;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and (min-width: 780px) {
|
||||
#error-box {
|
||||
max-width: 30%;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
font: message-box;
|
||||
font-size: 0.6875em;
|
||||
-moz-appearance: none;
|
||||
-moz-user-select: none;
|
||||
width: 100%;
|
||||
margin: 2px 0;
|
||||
padding: 2px 6px;
|
||||
line-height: 1.2;
|
||||
background-color: hsla(210,30%,95%,.1);
|
||||
background-image: linear-gradient(hsla(0,0%,100%,.6), hsla(0,0%,100%,.1));
|
||||
background-clip: padding-box;
|
||||
border: 1px solid hsla(210,15%,25%,.4);
|
||||
border-color: hsla(210,15%,25%,.3) hsla(210,15%,25%,.35) hsla(210,15%,25%,.4);
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.1);
|
||||
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background-color: hsla(210,30%,95%,.8);
|
||||
border-color: hsla(210,15%,25%,.45) hsla(210,15%,25%,.5) hsla(210,15%,25%,.55);
|
||||
box-shadow: 0 1px 0 hsla(0,0%,100%,.3) inset,
|
||||
0 0 0 1px hsla(0,0%,100%,.3) inset,
|
||||
0 1px 0 hsla(0,0%,100%,.1),
|
||||
0 0 3px hsla(210,15%,25%,.1);
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 150ms;
|
||||
transition-timing-function: ease;
|
||||
}
|
||||
|
||||
button:hover:active {
|
||||
background-color: hsla(210,15%,25%,.2);
|
||||
box-shadow: 0 1px 1px hsla(210,15%,25%,.2) inset,
|
||||
0 0 2px hsla(210,15%,25%,.4) inset;
|
||||
transition-property: background-color, border-color, box-shadow;
|
||||
transition-duration: 10ms;
|
||||
transition-timing-function: linear;
|
||||
}
|
@ -20,6 +20,7 @@ browser.jar:
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/browser/aboutSyncTabs.css
|
||||
#endif
|
||||
skin/classic/browser/aboutTabCrashed.css
|
||||
skin/classic/browser/actionicon-tab.png
|
||||
skin/classic/browser/appmenu-icons.png
|
||||
skin/classic/browser/appmenu-dropmarker.png
|
||||
@ -282,6 +283,7 @@ browser.jar:
|
||||
#ifdef MOZ_SERVICES_SYNC
|
||||
skin/classic/aero/browser/aboutSyncTabs.css
|
||||
#endif
|
||||
skin/classic/aero/browser/aboutTabCrashed.css
|
||||
skin/classic/aero/browser/actionicon-tab.png
|
||||
skin/classic/aero/browser/appmenu-dropmarker.png
|
||||
skin/classic/aero/browser/appmenu-icons.png
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "mozilla/TimeStamp.h"
|
||||
#include "nsContentListDeclarations.h"
|
||||
#include "nsMathUtils.h"
|
||||
#include "Units.h"
|
||||
|
||||
class imgICache;
|
||||
class imgIContainer;
|
||||
@ -1508,8 +1509,7 @@ public:
|
||||
* will return viewport information that specifies default information.
|
||||
*/
|
||||
static nsViewportInfo GetViewportInfo(nsIDocument* aDocument,
|
||||
uint32_t aDisplayWidth,
|
||||
uint32_t aDisplayHeight);
|
||||
const mozilla::ScreenIntSize& aDisplaySize);
|
||||
|
||||
// Call EnterMicroTask when you're entering JS execution.
|
||||
// Usually the best way to do this is to use nsAutoMicroTask.
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include "nsPropertyTable.h" // for member
|
||||
#include "nsTHashtable.h" // for member
|
||||
#include "mozilla/dom/DocumentBinding.h"
|
||||
#include "Units.h"
|
||||
|
||||
class imgIRequest;
|
||||
class nsAString;
|
||||
@ -622,8 +623,7 @@ public:
|
||||
*/
|
||||
Element* GetRootElement() const;
|
||||
|
||||
virtual nsViewportInfo GetViewportInfo(uint32_t aDisplayWidth,
|
||||
uint32_t aDisplayHeight) = 0;
|
||||
virtual nsViewportInfo GetViewportInfo(const mozilla::ScreenIntSize& aDisplaySize) = 0;
|
||||
|
||||
/**
|
||||
* True iff this doc will ignore manual character encoding overrides.
|
||||
|
@ -7,16 +7,15 @@
|
||||
|
||||
#include <stdint.h>
|
||||
#include "nscore.h"
|
||||
#include "Units.h"
|
||||
|
||||
/**
|
||||
* Default values for the nsViewportInfo class.
|
||||
*/
|
||||
static const double kViewportMinScale = 0.0;
|
||||
static const double kViewportMaxScale = 10.0;
|
||||
static const uint32_t kViewportMinWidth = 200;
|
||||
static const uint32_t kViewportMaxWidth = 10000;
|
||||
static const uint32_t kViewportMinHeight = 223;
|
||||
static const uint32_t kViewportMaxHeight = 10000;
|
||||
static const mozilla::LayoutDeviceToScreenScale kViewportMinScale(0.0f);
|
||||
static const mozilla::LayoutDeviceToScreenScale kViewportMaxScale(10.0f);
|
||||
static const mozilla::CSSIntSize kViewportMinSize(200, 223);
|
||||
static const mozilla::CSSIntSize kViewportMaxSize(10000, 10000);
|
||||
static const int32_t kViewportDefaultScreenWidth = 980;
|
||||
|
||||
/**
|
||||
@ -26,43 +25,40 @@ static const int32_t kViewportDefaultScreenWidth = 980;
|
||||
class MOZ_STACK_CLASS nsViewportInfo
|
||||
{
|
||||
public:
|
||||
nsViewportInfo(uint32_t aDisplayWidth, uint32_t aDisplayHeight) :
|
||||
nsViewportInfo(const mozilla::ScreenIntSize& aDisplaySize) :
|
||||
mDefaultZoom(1.0),
|
||||
mMinZoom(kViewportMinScale),
|
||||
mMaxZoom(kViewportMaxScale),
|
||||
mWidth(aDisplayWidth),
|
||||
mHeight(aDisplayHeight),
|
||||
mAutoSize(true),
|
||||
mAllowZoom(true)
|
||||
{
|
||||
mSize = mozilla::gfx::RoundedToInt(mozilla::ScreenSize(aDisplaySize) / mDefaultZoom);
|
||||
mozilla::CSSToLayoutDeviceScale pixelRatio(1.0f);
|
||||
mMinZoom = pixelRatio * kViewportMinScale;
|
||||
mMaxZoom = pixelRatio * kViewportMaxScale;
|
||||
ConstrainViewportValues();
|
||||
}
|
||||
|
||||
nsViewportInfo(double aDefaultZoom,
|
||||
double aMinZoom,
|
||||
double aMaxZoom,
|
||||
uint32_t aWidth,
|
||||
uint32_t aHeight,
|
||||
nsViewportInfo(const mozilla::CSSToScreenScale& aDefaultZoom,
|
||||
const mozilla::CSSToScreenScale& aMinZoom,
|
||||
const mozilla::CSSToScreenScale& aMaxZoom,
|
||||
const mozilla::CSSIntSize& aSize,
|
||||
bool aAutoSize,
|
||||
bool aAllowZoom) :
|
||||
mDefaultZoom(aDefaultZoom),
|
||||
mMinZoom(aMinZoom),
|
||||
mMaxZoom(aMaxZoom),
|
||||
mWidth(aWidth),
|
||||
mHeight(aHeight),
|
||||
mSize(aSize),
|
||||
mAutoSize(aAutoSize),
|
||||
mAllowZoom(aAllowZoom)
|
||||
{
|
||||
ConstrainViewportValues();
|
||||
}
|
||||
|
||||
double GetDefaultZoom() { return mDefaultZoom; }
|
||||
void SetDefaultZoom(const double aDefaultZoom);
|
||||
double GetMinZoom() { return mMinZoom; }
|
||||
double GetMaxZoom() { return mMaxZoom; }
|
||||
mozilla::CSSToScreenScale GetDefaultZoom() { return mDefaultZoom; }
|
||||
void SetDefaultZoom(const mozilla::CSSToScreenScale& aDefaultZoom);
|
||||
mozilla::CSSToScreenScale GetMinZoom() { return mMinZoom; }
|
||||
mozilla::CSSToScreenScale GetMaxZoom() { return mMaxZoom; }
|
||||
|
||||
uint32_t GetWidth() { return mWidth; }
|
||||
uint32_t GetHeight() { return mHeight; }
|
||||
mozilla::CSSIntSize GetSize() { return mSize; }
|
||||
|
||||
bool IsAutoSizeEnabled() { return mAutoSize; }
|
||||
bool IsZoomAllowed() { return mAllowZoom; }
|
||||
@ -78,21 +74,16 @@ class MOZ_STACK_CLASS nsViewportInfo
|
||||
|
||||
// Default zoom indicates the level at which the display is 'zoomed in'
|
||||
// initially for the user, upon loading of the page.
|
||||
double mDefaultZoom;
|
||||
mozilla::CSSToScreenScale mDefaultZoom;
|
||||
|
||||
// The minimum zoom level permitted by the page.
|
||||
double mMinZoom;
|
||||
mozilla::CSSToScreenScale mMinZoom;
|
||||
|
||||
// The maximum zoom level permitted by the page.
|
||||
double mMaxZoom;
|
||||
mozilla::CSSToScreenScale mMaxZoom;
|
||||
|
||||
// The width of the viewport, specified by the <meta name="viewport"> tag,
|
||||
// in CSS pixels.
|
||||
uint32_t mWidth;
|
||||
|
||||
// The height of the viewport, specified by the <meta name="viewport"> tag,
|
||||
// in CSS pixels.
|
||||
uint32_t mHeight;
|
||||
// The size of the viewport, specified by the <meta name="viewport"> tag.
|
||||
mozilla::CSSIntSize mSize;
|
||||
|
||||
// Whether or not we should automatically size the viewport to the device's
|
||||
// width. This is true if the document has been optimized for mobile, and
|
||||
|
@ -4875,10 +4875,9 @@ static void ProcessViewportToken(nsIDocument *aDocument,
|
||||
/* static */
|
||||
nsViewportInfo
|
||||
nsContentUtils::GetViewportInfo(nsIDocument *aDocument,
|
||||
uint32_t aDisplayWidth,
|
||||
uint32_t aDisplayHeight)
|
||||
const ScreenIntSize& aDisplaySize)
|
||||
{
|
||||
return aDocument->GetViewportInfo(aDisplayWidth, aDisplayHeight);
|
||||
return aDocument->GetViewportInfo(aDisplaySize);
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -6782,12 +6782,11 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
|
||||
}
|
||||
|
||||
nsViewportInfo
|
||||
nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
||||
uint32_t aDisplayHeight)
|
||||
nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||
{
|
||||
switch (mViewportType) {
|
||||
case DisplayWidthHeight:
|
||||
return nsViewportInfo(aDisplayWidth, aDisplayHeight);
|
||||
return nsViewportInfo(aDisplaySize);
|
||||
case Unknown:
|
||||
{
|
||||
nsAutoString viewport;
|
||||
@ -6807,8 +6806,7 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
||||
{
|
||||
// We're making an assumption that the docType can't change here
|
||||
mViewportType = DisplayWidthHeight;
|
||||
nsViewportInfo ret(aDisplayWidth, aDisplayHeight);
|
||||
return ret;
|
||||
return nsViewportInfo(aDisplaySize);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6817,8 +6815,7 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
||||
GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
|
||||
if (handheldFriendly.EqualsLiteral("true")) {
|
||||
mViewportType = DisplayWidthHeight;
|
||||
nsViewportInfo ret(aDisplayWidth, aDisplayHeight);
|
||||
return ret;
|
||||
return nsViewportInfo(aDisplaySize);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6826,14 +6823,14 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
||||
GetHeaderData(nsGkAtoms::viewport_minimum_scale, minScaleStr);
|
||||
|
||||
nsresult errorCode;
|
||||
mScaleMinFloat = minScaleStr.ToFloat(&errorCode);
|
||||
mScaleMinFloat = LayoutDeviceToScreenScale(minScaleStr.ToFloat(&errorCode));
|
||||
|
||||
if (NS_FAILED(errorCode)) {
|
||||
mScaleMinFloat = kViewportMinScale;
|
||||
}
|
||||
|
||||
mScaleMinFloat = std::min((double)mScaleMinFloat, kViewportMaxScale);
|
||||
mScaleMinFloat = std::max((double)mScaleMinFloat, kViewportMinScale);
|
||||
mScaleMinFloat = mozilla::clamped(
|
||||
mScaleMinFloat, kViewportMinScale, kViewportMaxScale);
|
||||
|
||||
nsAutoString maxScaleStr;
|
||||
GetHeaderData(nsGkAtoms::viewport_maximum_scale, maxScaleStr);
|
||||
@ -6841,20 +6838,20 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
||||
// We define a special error code variable for the scale and max scale,
|
||||
// because they are used later (see the width calculations).
|
||||
nsresult scaleMaxErrorCode;
|
||||
mScaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
|
||||
mScaleMaxFloat = LayoutDeviceToScreenScale(maxScaleStr.ToFloat(&scaleMaxErrorCode));
|
||||
|
||||
if (NS_FAILED(scaleMaxErrorCode)) {
|
||||
mScaleMaxFloat = kViewportMaxScale;
|
||||
}
|
||||
|
||||
mScaleMaxFloat = std::min((double)mScaleMaxFloat, kViewportMaxScale);
|
||||
mScaleMaxFloat = std::max((double)mScaleMaxFloat, kViewportMinScale);
|
||||
mScaleMaxFloat = mozilla::clamped(
|
||||
mScaleMaxFloat, kViewportMinScale, kViewportMaxScale);
|
||||
|
||||
nsAutoString scaleStr;
|
||||
GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
|
||||
|
||||
nsresult scaleErrorCode;
|
||||
mScaleFloat = scaleStr.ToFloat(&scaleErrorCode);
|
||||
mScaleFloat = LayoutDeviceToScreenScale(scaleStr.ToFloat(&scaleErrorCode));
|
||||
|
||||
nsAutoString widthStr, heightStr;
|
||||
|
||||
@ -6869,20 +6866,19 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
||||
|
||||
if (widthStr.IsEmpty() &&
|
||||
(heightStr.EqualsLiteral("device-height") ||
|
||||
(mScaleFloat /* not adjusted for pixel ratio */ == 1.0)))
|
||||
(mScaleFloat.scale == 1.0)))
|
||||
{
|
||||
mAutoSize = true;
|
||||
}
|
||||
|
||||
nsresult widthErrorCode, heightErrorCode;
|
||||
mViewportWidth = widthStr.ToInteger(&widthErrorCode);
|
||||
mViewportHeight = heightStr.ToInteger(&heightErrorCode);
|
||||
mViewportSize.width = widthStr.ToInteger(&widthErrorCode);
|
||||
mViewportSize.height = heightStr.ToInteger(&heightErrorCode);
|
||||
|
||||
// If width or height has not been set to a valid number by this point,
|
||||
// fall back to a default value.
|
||||
mValidWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && mViewportWidth > 0);
|
||||
mValidHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && mViewportHeight > 0);
|
||||
|
||||
mValidWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && mViewportSize.width > 0);
|
||||
mValidHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && mViewportSize.height > 0);
|
||||
|
||||
mAllowZoom = true;
|
||||
nsAutoString userScalable;
|
||||
@ -6903,63 +6899,62 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
||||
}
|
||||
case Specified:
|
||||
default:
|
||||
uint32_t width = mViewportWidth, height = mViewportHeight;
|
||||
CSSIntSize size = mViewportSize;
|
||||
|
||||
if (!mValidWidth) {
|
||||
if (mValidHeight && aDisplayWidth > 0 && aDisplayHeight > 0) {
|
||||
width = uint32_t((height * aDisplayWidth) / aDisplayHeight);
|
||||
if (mValidHeight && !aDisplaySize.IsEmpty()) {
|
||||
size.width = int32_t(size.height * aDisplaySize.width / aDisplaySize.height);
|
||||
} else {
|
||||
width = Preferences::GetInt("browser.viewport.desktopWidth",
|
||||
kViewportDefaultScreenWidth);
|
||||
size.width = Preferences::GetInt("browser.viewport.desktopWidth",
|
||||
kViewportDefaultScreenWidth);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mValidHeight) {
|
||||
if (aDisplayWidth > 0 && aDisplayHeight > 0) {
|
||||
height = uint32_t((width * aDisplayHeight) / aDisplayWidth);
|
||||
if (!aDisplaySize.IsEmpty()) {
|
||||
size.height = int32_t(size.width * aDisplaySize.height / aDisplaySize.width);
|
||||
} else {
|
||||
height = width;
|
||||
size.height = size.width;
|
||||
}
|
||||
}
|
||||
// Now convert the scale into device pixels per CSS pixel.
|
||||
nsIWidget *widget = nsContentUtils::WidgetForDocument(this);
|
||||
double pixelRatio = widget ? widget->GetDefaultScale() : 1.0;
|
||||
float scaleFloat = mScaleFloat * pixelRatio;
|
||||
float scaleMinFloat= mScaleMinFloat * pixelRatio;
|
||||
float scaleMaxFloat = mScaleMaxFloat * pixelRatio;
|
||||
CSSToLayoutDeviceScale pixelRatio(widget ? widget->GetDefaultScale() : 1.0f);
|
||||
CSSToScreenScale scaleFloat = mScaleFloat * pixelRatio;
|
||||
CSSToScreenScale scaleMinFloat = mScaleMinFloat * pixelRatio;
|
||||
CSSToScreenScale scaleMaxFloat = mScaleMaxFloat * pixelRatio;
|
||||
|
||||
if (mAutoSize) {
|
||||
// aDisplayWidth and aDisplayHeight are in device pixels; convert them to
|
||||
// CSS pixels for the viewport size.
|
||||
width = aDisplayWidth / pixelRatio;
|
||||
height = aDisplayHeight / pixelRatio;
|
||||
// aDisplaySize is in screen pixels; convert them to CSS pixels for the viewport size.
|
||||
CSSToScreenScale defaultPixelScale = pixelRatio * LayoutDeviceToScreenScale(1.0f);
|
||||
size = mozilla::gfx::RoundedToInt(ScreenSize(aDisplaySize) / defaultPixelScale);
|
||||
}
|
||||
|
||||
width = std::min(width, kViewportMaxWidth);
|
||||
width = std::max(width, kViewportMinWidth);
|
||||
size.width = clamped(size.width, kViewportMinSize.width, kViewportMaxSize.width);
|
||||
|
||||
// Also recalculate the default zoom, if it wasn't specified in the metadata,
|
||||
// and the width is specified.
|
||||
if (mScaleStrEmpty && !mWidthStrEmpty) {
|
||||
scaleFloat = std::max(scaleFloat, float(aDisplayWidth) / float(width));
|
||||
CSSToScreenScale defaultScale(float(aDisplaySize.width) / float(size.width));
|
||||
scaleFloat = (scaleFloat > defaultScale) ? scaleFloat : defaultScale;
|
||||
}
|
||||
|
||||
height = std::min(height, kViewportMaxHeight);
|
||||
height = std::max(height, kViewportMinHeight);
|
||||
size.height = clamped(size.height, kViewportMinSize.height, kViewportMaxSize.height);
|
||||
|
||||
// We need to perform a conversion, but only if the initial or maximum
|
||||
// scale were set explicitly by the user.
|
||||
if (mValidScaleFloat) {
|
||||
width = std::max(width, (uint32_t)(aDisplayWidth / scaleFloat));
|
||||
height = std::max(height, (uint32_t)(aDisplayHeight / scaleFloat));
|
||||
CSSIntSize displaySize = RoundedToInt(ScreenSize(aDisplaySize) / scaleFloat);
|
||||
size.width = std::max(size.width, displaySize.width);
|
||||
size.height = std::max(size.height, displaySize.height);
|
||||
} else if (mValidMaxScale) {
|
||||
width = std::max(width, (uint32_t)(aDisplayWidth / scaleMaxFloat));
|
||||
height = std::max(height, (uint32_t)(aDisplayHeight / scaleMaxFloat));
|
||||
CSSIntSize displaySize = RoundedToInt(ScreenSize(aDisplaySize) / scaleMaxFloat);
|
||||
size.width = std::max(size.width, displaySize.width);
|
||||
size.height = std::max(size.height, displaySize.height);
|
||||
}
|
||||
|
||||
nsViewportInfo ret(scaleFloat, scaleMinFloat, scaleMaxFloat, width, height,
|
||||
mAutoSize, mAllowZoom);
|
||||
return ret;
|
||||
return nsViewportInfo(scaleFloat, scaleMinFloat, scaleMaxFloat, size,
|
||||
mAutoSize, mAllowZoom);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -753,9 +753,7 @@ public:
|
||||
nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
|
||||
nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
|
||||
|
||||
virtual nsViewportInfo GetViewportInfo(uint32_t aDisplayWidth,
|
||||
uint32_t aDisplayHeight) MOZ_OVERRIDE;
|
||||
|
||||
virtual nsViewportInfo GetViewportInfo(const mozilla::ScreenIntSize& aDisplaySize) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsRadioGroupStruct* GetRadioGroupInternal(const nsAString& aName) const;
|
||||
@ -1412,9 +1410,12 @@ private:
|
||||
// These member variables cache information about the viewport so we don't have to
|
||||
// recalculate it each time.
|
||||
bool mValidWidth, mValidHeight;
|
||||
float mScaleMinFloat, mScaleMaxFloat, mScaleFloat, mPixelRatio;
|
||||
mozilla::LayoutDeviceToScreenScale mScaleMinFloat;
|
||||
mozilla::LayoutDeviceToScreenScale mScaleMaxFloat;
|
||||
mozilla::LayoutDeviceToScreenScale mScaleFloat;
|
||||
mozilla::CSSToLayoutDeviceScale mPixelRatio;
|
||||
bool mAutoSize, mAllowZoom, mValidScaleFloat, mValidMaxScale, mScaleStrEmpty, mWidthStrEmpty;
|
||||
uint32_t mViewportWidth, mViewportHeight;
|
||||
mozilla::CSSIntSize mViewportSize;
|
||||
|
||||
nsrefcnt mStackRefCnt;
|
||||
bool mNeedsReleaseAfterStackRefCntRelease;
|
||||
|
@ -638,6 +638,7 @@ GK_ATOM(onalerting, "onalerting")
|
||||
GK_ATOM(onanimationend, "onanimationend")
|
||||
GK_ATOM(onanimationiteration, "onanimationiteration")
|
||||
GK_ATOM(onanimationstart, "onanimationstart")
|
||||
GK_ATOM(onantennaavailablechange, "onantennaavailablechange")
|
||||
GK_ATOM(onAppCommand, "onAppCommand")
|
||||
GK_ATOM(onaudioprocess, "onaudioprocess")
|
||||
GK_ATOM(onbeforecopy, "onbeforecopy")
|
||||
@ -709,6 +710,7 @@ GK_ATOM(onemergencycbmodechange, "onemergencycbmodechange")
|
||||
GK_ATOM(onerror, "onerror")
|
||||
GK_ATOM(onfailed, "onfailed")
|
||||
GK_ATOM(onfocus, "onfocus")
|
||||
GK_ATOM(onfrequencychange, "onfrequencychange")
|
||||
GK_ATOM(onget, "onget")
|
||||
GK_ATOM(ongroupchange, "ongroupchange")
|
||||
GK_ATOM(onhashchange, "onhashchange")
|
||||
@ -771,6 +773,7 @@ GK_ATOM(onremoteheld, "onremoteheld")
|
||||
GK_ATOM(onremoteresumed, "onremoteresumed")
|
||||
GK_ATOM(onretrieving, "onretrieving")
|
||||
GK_ATOM(onRequest, "onRequest")
|
||||
GK_ATOM(onrequestmediaplaystatus, "onrequestmediaplaystatus")
|
||||
GK_ATOM(onreset, "onreset")
|
||||
GK_ATOM(onresuming, "onresuming")
|
||||
GK_ATOM(onMozBeforeResize, "onMozBeforeResize")
|
||||
@ -785,8 +788,6 @@ GK_ATOM(onshow, "onshow")
|
||||
GK_ATOM(onstatechange, "onstatechange")
|
||||
GK_ATOM(onstatuschanged, "onstatuschanged")
|
||||
GK_ATOM(onstkcommand, "onstkcommand")
|
||||
GK_ATOM(onantennastatechange, "onantennastatechange")
|
||||
GK_ATOM(onseekcomplete, "onseekcomplete")
|
||||
GK_ATOM(onstksessionend, "onstksessionend")
|
||||
GK_ATOM(onsubmit, "onsubmit")
|
||||
GK_ATOM(onsuccess, "onsuccess")
|
||||
|
@ -6,10 +6,12 @@
|
||||
#include "mozilla/Assertions.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
void
|
||||
nsViewportInfo::SetDefaultZoom(const double aDefaultZoom)
|
||||
nsViewportInfo::SetDefaultZoom(const CSSToScreenScale& aDefaultZoom)
|
||||
{
|
||||
MOZ_ASSERT(aDefaultZoom >= 0.0f);
|
||||
MOZ_ASSERT(aDefaultZoom.scale >= 0.0f);
|
||||
mDefaultZoom = aDefaultZoom;
|
||||
}
|
||||
|
||||
@ -20,6 +22,6 @@ nsViewportInfo::ConstrainViewportValues()
|
||||
// dev.w3.org/csswg/css-device-adapt section 6.2
|
||||
mMaxZoom = std::max(mMinZoom, mMaxZoom);
|
||||
|
||||
mDefaultZoom = std::min(mDefaultZoom, mMaxZoom);
|
||||
mDefaultZoom = std::max(mDefaultZoom, mMinZoom);
|
||||
mDefaultZoom = mDefaultZoom < mMaxZoom ? mDefaultZoom : mMaxZoom;
|
||||
mDefaultZoom = mDefaultZoom > mMinZoom ? mDefaultZoom : mMinZoom;
|
||||
}
|
||||
|
@ -3962,7 +3962,7 @@ bool
|
||||
nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
|
||||
{
|
||||
if (mIsPrintingOrPP && aDisplayErrorDialog) {
|
||||
DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr);
|
||||
DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
return mIsPrintingOrPP;
|
||||
@ -4118,7 +4118,7 @@ nsDocShell::LoadURI(const PRUnichar * aURI,
|
||||
// what happens
|
||||
|
||||
if (NS_ERROR_MALFORMED_URI == rv) {
|
||||
DisplayLoadError(rv, uri, aURI);
|
||||
DisplayLoadError(rv, uri, aURI, nullptr);
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv) || !uri)
|
||||
@ -4333,6 +4333,15 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
||||
bucketId);
|
||||
|
||||
cssClass.AssignLiteral("blacklist");
|
||||
} else if (NS_ERROR_CONTENT_CRASHED == aError) {
|
||||
errorPage.AssignLiteral("tabcrashed");
|
||||
error.AssignLiteral("tabcrashed");
|
||||
|
||||
nsCOMPtr<EventTarget> handler = mChromeEventHandler;
|
||||
if (handler) {
|
||||
nsCOMPtr<Element> element = do_QueryInterface(handler);
|
||||
element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Errors requiring simple formatting
|
||||
|
@ -509,9 +509,6 @@ protected:
|
||||
nsresult EnsureTransferableHookData();
|
||||
NS_IMETHOD EnsureFind();
|
||||
nsresult RefreshURIFromQueue();
|
||||
NS_IMETHOD DisplayLoadError(nsresult aError, nsIURI *aURI,
|
||||
const PRUnichar *aURL,
|
||||
nsIChannel* aFailedChannel = nullptr);
|
||||
NS_IMETHOD LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
|
||||
const char *aErrorPage,
|
||||
const PRUnichar *aErrorType,
|
||||
|
@ -42,7 +42,7 @@ interface nsIVariant;
|
||||
interface nsIPrivacyTransitionObserver;
|
||||
interface nsIReflowObserver;
|
||||
|
||||
[scriptable, builtinclass, uuid(4bb2261b-4c13-44a4-ace3-fc2eec17cc34)]
|
||||
[scriptable, builtinclass, uuid(62f1b40d-1d15-4640-95dc-20caae775bd1)]
|
||||
interface nsIDocShell : nsIDocShellTreeItem
|
||||
{
|
||||
/**
|
||||
@ -411,6 +411,22 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
/* attribute to access whether error pages are enabled */
|
||||
attribute boolean useErrorPages;
|
||||
|
||||
/**
|
||||
* Display a load error in a frame while keeping that frame's currentURI
|
||||
* pointing correctly to the page where the error ocurred, rather than to
|
||||
* the error document page. You must provide either the aURI or aURL parameter.
|
||||
*
|
||||
* @param aError The error code to be displayed
|
||||
* @param aURI nsIURI of the page where the error happened
|
||||
* @param aURL wstring of the page where the error happened
|
||||
* @param aFailedChannel The channel related to this error
|
||||
*/
|
||||
void displayLoadError(in nsresult aError,
|
||||
in nsIURI aURI,
|
||||
in wstring aURL,
|
||||
[optional] in nsIChannel aFailedChannel);
|
||||
|
||||
|
||||
/**
|
||||
* Keeps track of the previous SHTransaction index and the current
|
||||
* SHTransaction index at the time that the doc shell begins to load.
|
||||
|
@ -65,6 +65,10 @@
|
||||
#include "AudioChannelManager.h"
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
#include "mozilla/dom/FMRadio.h"
|
||||
#endif
|
||||
|
||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||
#include "nsJSUtils.h"
|
||||
|
||||
@ -195,6 +199,13 @@ Navigator::Invalidate()
|
||||
mBatteryManager = nullptr;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
if (mFMRadio) {
|
||||
mFMRadio->Shutdown();
|
||||
mFMRadio = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mPowerManager) {
|
||||
mPowerManager->Shutdown();
|
||||
mPowerManager = nullptr;
|
||||
@ -1044,6 +1055,34 @@ Navigator::GetMozNotification(ErrorResult& aRv)
|
||||
return mNotification;
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
|
||||
using mozilla::dom::FMRadio;
|
||||
|
||||
FMRadio*
|
||||
Navigator::GetMozFMRadio(ErrorResult& aRv)
|
||||
{
|
||||
if (!mFMRadio) {
|
||||
if (!mWindow) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(mWindow->GetDocShell(), nullptr);
|
||||
|
||||
mFMRadio = new FMRadio();
|
||||
mFMRadio->Init(mWindow);
|
||||
}
|
||||
|
||||
return mFMRadio;
|
||||
}
|
||||
|
||||
#endif // MOZ_B2G_FM
|
||||
|
||||
//*****************************************************************************
|
||||
// Navigator::nsINavigatorBattery
|
||||
//*****************************************************************************
|
||||
|
||||
battery::BatteryManager*
|
||||
Navigator::GetBattery(ErrorResult& aRv)
|
||||
{
|
||||
@ -1710,6 +1749,16 @@ Navigator::HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
}
|
||||
#endif // MOZ_B2G_BT
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
|
||||
return win && CheckPermission(win, "fmradio");
|
||||
}
|
||||
#endif // MOZ_B2G_FM
|
||||
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
/* static */
|
||||
bool
|
||||
|
@ -51,6 +51,10 @@ namespace battery {
|
||||
class BatteryManager;
|
||||
} // namespace battery
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
class FMRadio;
|
||||
#endif
|
||||
|
||||
class DesktopNotificationCenter;
|
||||
class MobileMessageManager;
|
||||
class MozIdleObserver;
|
||||
@ -230,6 +234,9 @@ public:
|
||||
#ifdef MOZ_GAMEPAD
|
||||
void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
|
||||
#endif // MOZ_GAMEPAD
|
||||
#ifdef MOZ_B2G_FM
|
||||
FMRadio* GetMozFMRadio(ErrorResult& aRv);
|
||||
#endif
|
||||
#ifdef MOZ_B2G_BT
|
||||
bluetooth::BluetoothManager* GetMozBluetooth(ErrorResult& aRv);
|
||||
#endif // MOZ_B2G_BT
|
||||
@ -283,6 +290,9 @@ public:
|
||||
#ifdef MOZ_B2G_BT
|
||||
static bool HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_B2G_BT
|
||||
#ifdef MOZ_B2G_FM
|
||||
static bool HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_B2G_FM
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
@ -314,6 +324,9 @@ private:
|
||||
nsRefPtr<Geolocation> mGeolocation;
|
||||
nsRefPtr<DesktopNotificationCenter> mNotification;
|
||||
nsRefPtr<battery::BatteryManager> mBatteryManager;
|
||||
#ifdef MOZ_B2G_FM
|
||||
nsRefPtr<FMRadio> mFMRadio;
|
||||
#endif
|
||||
nsRefPtr<power::PowerManager> mPowerManager;
|
||||
nsRefPtr<MobileMessageManager> mMobileMessageManager;
|
||||
#ifdef MOZ_B2G_RIL
|
||||
|
@ -537,11 +537,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
NS_DEFINE_CLASSINFO_DATA(FMRadio, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
@ -1399,13 +1394,6 @@ nsDOMClassInfo::Init()
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
DOM_CLASSINFO_MAP_BEGIN(FMRadio, nsIFMRadio)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIFMRadio)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
|
||||
|
@ -130,10 +130,6 @@ DOMCI_CLASS(MediaQueryList)
|
||||
DOMCI_CLASS(MozIccManager)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
DOMCI_CLASS(FMRadio)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_BT
|
||||
DOMCI_CLASS(BluetoothDevice)
|
||||
#endif
|
||||
|
@ -281,13 +281,13 @@ nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth,
|
||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||
NS_ENSURE_STATE(doc);
|
||||
|
||||
nsViewportInfo info = nsContentUtils::GetViewportInfo(doc, aDisplayWidth, aDisplayHeight);
|
||||
*aDefaultZoom = info.GetDefaultZoom();
|
||||
nsViewportInfo info = nsContentUtils::GetViewportInfo(doc, ScreenIntSize(aDisplayWidth, aDisplayHeight));
|
||||
*aDefaultZoom = info.GetDefaultZoom().scale;
|
||||
*aAllowZoom = info.IsZoomAllowed();
|
||||
*aMinZoom = info.GetMinZoom();
|
||||
*aMaxZoom = info.GetMaxZoom();
|
||||
*aWidth = info.GetWidth();
|
||||
*aHeight = info.GetHeight();
|
||||
*aMinZoom = info.GetMinZoom().scale;
|
||||
*aMaxZoom = info.GetMaxZoom().scale;
|
||||
*aWidth = info.GetSize().width;
|
||||
*aHeight = info.GetSize().height;
|
||||
*aAutoSize = info.IsAutoSizeEnabled();
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -345,6 +345,15 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
|
||||
e->InitBluetoothStatusChangedEvent(aData.name(), false, false,
|
||||
address, status);
|
||||
DispatchTrustedEvent(event);
|
||||
} else if (aData.name().EqualsLiteral(REQUEST_MEDIA_PLAYSTATUS_ID)) {
|
||||
nsCOMPtr<nsIDOMEvent> event;
|
||||
nsresult rv = NS_NewDOMEvent(getter_AddRefs(event), this, nullptr, nullptr);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
rv = event->InitEvent(aData.name(), false, false);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
|
||||
DispatchTrustedEvent(event);
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
nsCString warningMsg;
|
||||
|
@ -144,6 +144,7 @@ public:
|
||||
IMPL_EVENT_HANDLER(a2dpstatuschanged);
|
||||
IMPL_EVENT_HANDLER(hfpstatuschanged);
|
||||
IMPL_EVENT_HANDLER(pairedstatuschanged);
|
||||
IMPL_EVENT_HANDLER(requestmediaplaystatus);
|
||||
IMPL_EVENT_HANDLER(scostatuschanged);
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
|
@ -62,18 +62,24 @@ extern bool gBluetoothDebugFlag;
|
||||
|
||||
/**
|
||||
* When the connection status of a Bluetooth profile is changed, we'll
|
||||
* distribute one of the following events.
|
||||
* dispatch one of the following events.
|
||||
*/
|
||||
#define A2DP_STATUS_CHANGED_ID "a2dpstatuschanged"
|
||||
#define HFP_STATUS_CHANGED_ID "hfpstatuschanged"
|
||||
#define SCO_STATUS_CHANGED_ID "scostatuschanged"
|
||||
|
||||
/**
|
||||
* When the pair status of a Bluetooth device is changed, we'll distribute an
|
||||
* When the pair status of a Bluetooth device is changed, we'll dispatch an
|
||||
* event.
|
||||
*/
|
||||
#define PAIRED_STATUS_CHANGED_ID "pairedstatuschanged"
|
||||
|
||||
/**
|
||||
* When receiving a query about current play status from remote device, we'll
|
||||
* dispatch an event.
|
||||
*/
|
||||
#define REQUEST_MEDIA_PLAYSTATUS_ID "requestmediaplaystatus"
|
||||
|
||||
// Bluetooth address format: xx:xx:xx:xx:xx:xx (or xx_xx_xx_xx_xx_xx)
|
||||
#define BLUETOOTH_ADDRESS_LENGTH 17
|
||||
#define BLUETOOTH_ADDRESS_NONE "00:00:00:00:00:00"
|
||||
|
@ -178,11 +178,21 @@ static nsTArray<uint32_t> sAuthorizedServiceClass;
|
||||
static nsString sAdapterPath;
|
||||
static Atomic<int32_t> sIsPairing(0);
|
||||
static int sConnectedDeviceCount = 0;
|
||||
static Monitor sStopBluetoothMonitor("BluetoothService.sStopBluetoothMonitor");
|
||||
static StaticAutoPtr<Monitor> sStopBluetoothMonitor;
|
||||
|
||||
typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
|
||||
typedef bool (*FilterFunc)(const BluetoothValue&);
|
||||
|
||||
BluetoothDBusService::BluetoothDBusService()
|
||||
{
|
||||
sStopBluetoothMonitor = new Monitor("BluetoothService.sStopBluetoothMonitor");
|
||||
}
|
||||
|
||||
BluetoothDBusService::~BluetoothDBusService()
|
||||
{
|
||||
sStopBluetoothMonitor = nullptr;
|
||||
}
|
||||
|
||||
static bool
|
||||
GetConnectedDevicesFilter(const BluetoothValue& aValue)
|
||||
{
|
||||
@ -1298,10 +1308,10 @@ private:
|
||||
nsString mAdapterPath;
|
||||
};
|
||||
|
||||
class SendPlayStatusTask : public nsRunnable
|
||||
class RequestPlayStatusTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SendPlayStatusTask()
|
||||
RequestPlayStatusTask()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
}
|
||||
@ -1310,15 +1320,14 @@ public:
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
||||
NS_ENSURE_TRUE(a2dp, NS_ERROR_FAILURE);
|
||||
BluetoothSignal signal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
|
||||
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||
InfallibleTArray<BluetoothNamedValue>());
|
||||
|
||||
BluetoothService* bs = BluetoothService::Get();
|
||||
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||
bs->DistributeSignal(signal);
|
||||
|
||||
bs->UpdatePlayStatus(a2dp->GetDuration(),
|
||||
a2dp->GetPosition(),
|
||||
a2dp->GetPlayStatus());
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
@ -1494,15 +1503,13 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
|
||||
signal.value() = parameters;
|
||||
NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
|
||||
} else if (property.name().EqualsLiteral("Connected")) {
|
||||
MonitorAutoLock lock(sStopBluetoothMonitor);
|
||||
MonitorAutoLock lock(*sStopBluetoothMonitor);
|
||||
|
||||
if (property.value().get_bool()) {
|
||||
++sConnectedDeviceCount;
|
||||
} else {
|
||||
MOZ_ASSERT(sConnectedDeviceCount > 0);
|
||||
|
||||
--sConnectedDeviceCount;
|
||||
if (sConnectedDeviceCount == 0) {
|
||||
if (--sConnectedDeviceCount == 0) {
|
||||
lock.Notify();
|
||||
}
|
||||
}
|
||||
@ -1533,7 +1540,7 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
|
||||
sSinkProperties,
|
||||
ArrayLength(sSinkProperties));
|
||||
} else if (dbus_message_is_signal(aMsg, DBUS_CTL_IFACE, "GetPlayStatus")) {
|
||||
NS_DispatchToMainThread(new SendPlayStatusTask());
|
||||
NS_DispatchToMainThread(new RequestPlayStatusTask());
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
} else if (dbus_message_is_signal(aMsg, DBUS_CTL_IFACE, "PropertyChanged")) {
|
||||
ParsePropertyChange(aMsg,
|
||||
@ -1697,7 +1704,7 @@ BluetoothDBusService::StopInternal()
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
|
||||
{
|
||||
MonitorAutoLock lock(sStopBluetoothMonitor);
|
||||
MonitorAutoLock lock(*sStopBluetoothMonitor);
|
||||
if (sConnectedDeviceCount > 0) {
|
||||
lock.Wait(PR_SecondsToInterval(TIMEOUT_FORCE_TO_DISABLE_BT));
|
||||
}
|
||||
@ -2656,55 +2663,6 @@ BluetoothDBusService::IsConnected(const uint16_t aProfileId)
|
||||
return profile->IsConnected();
|
||||
}
|
||||
|
||||
class ConnectBluetoothSocketRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ConnectBluetoothSocketRunnable(BluetoothReplyRunnable* aRunnable,
|
||||
UnixSocketConsumer* aConsumer,
|
||||
const nsAString& aObjectPath,
|
||||
const nsAString& aServiceUUID,
|
||||
BluetoothSocketType aType,
|
||||
bool aAuth,
|
||||
bool aEncrypt,
|
||||
int aChannel)
|
||||
: mRunnable(dont_AddRef(aRunnable))
|
||||
, mConsumer(aConsumer)
|
||||
, mObjectPath(aObjectPath)
|
||||
, mServiceUUID(aServiceUUID)
|
||||
, mType(aType)
|
||||
, mAuth(aAuth)
|
||||
, mEncrypt(aEncrypt)
|
||||
, mChannel(aChannel)
|
||||
{
|
||||
}
|
||||
|
||||
nsresult
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsString address = GetAddressFromObjectPath(mObjectPath);
|
||||
BluetoothUnixSocketConnector* c =
|
||||
new BluetoothUnixSocketConnector(mType, mChannel, mAuth, mEncrypt);
|
||||
if (!mConsumer->ConnectSocket(c, NS_ConvertUTF16toUTF8(address).get())) {
|
||||
NS_NAMED_LITERAL_STRING(errorStr, "SocketConnectionError");
|
||||
DispatchBluetoothReply(mRunnable, BluetoothValue(), errorStr);
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothReplyRunnable> mRunnable;
|
||||
nsRefPtr<UnixSocketConsumer> mConsumer;
|
||||
nsString mObjectPath;
|
||||
nsString mServiceUUID;
|
||||
BluetoothSocketType mType;
|
||||
bool mAuth;
|
||||
bool mEncrypt;
|
||||
int mChannel;
|
||||
};
|
||||
|
||||
class OnUpdateSdpRecordsRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
|
@ -162,6 +162,9 @@ public:
|
||||
SendInputMessage(const nsAString& aDeviceAddresses,
|
||||
const nsAString& aMessage,
|
||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||
protected:
|
||||
BluetoothDBusService();
|
||||
~BluetoothDBusService();
|
||||
|
||||
private:
|
||||
/**
|
||||
@ -196,7 +199,6 @@ private:
|
||||
void UpdateNotification(ControlEventId aEventId, uint64_t aData);
|
||||
|
||||
void DisconnectAllAcls(const nsAString& aAdapterPath);
|
||||
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
@ -48,7 +48,7 @@ endif
|
||||
|
||||
ifdef MOZ_B2G_FM
|
||||
DOM_SRCDIRS += \
|
||||
dom/fm \
|
||||
dom/fmradio \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
# DOMFMRadio.js
|
||||
component {901f8a83-03a6-4be9-bb8f-35387d3849da} DOMFMRadioChild.js
|
||||
contract @mozilla.org/domfmradio;1 {901f8a83-03a6-4be9-bb8f-35387d3849da}
|
||||
category JavaScript-navigator-property mozFMRadio @mozilla.org/domfmradio;1
|
@ -1,423 +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"
|
||||
let DEBUG = 0;
|
||||
if (DEBUG)
|
||||
debug = function (s) { dump("-*- DOMFMRadioChild: " + s + "\n"); };
|
||||
else
|
||||
debug = function (s) { };
|
||||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/DOMRequestHelper.jsm");
|
||||
|
||||
const DOMFMMANAGER_CONTRACTID = "@mozilla.org/domfmradio;1";
|
||||
const DOMFMMANAGER_CID = Components.ID("{901f8a83-03a6-4be9-bb8f-35387d3849da}");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(Services, "DOMRequest", function() {
|
||||
return Cc["@mozilla.org/dom/dom-request-service;1"]
|
||||
.getService(Ci.nsIDOMRequestService);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "cpmm",
|
||||
"@mozilla.org/childprocessmessagemanager;1",
|
||||
"nsISyncMessageSender");
|
||||
|
||||
function DOMFMRadioChild() { }
|
||||
|
||||
DOMFMRadioChild.prototype = {
|
||||
__proto__: DOMRequestIpcHelper.prototype,
|
||||
|
||||
classID: DOMFMMANAGER_CID,
|
||||
classInfo: XPCOMUtils.generateCI({
|
||||
classID: DOMFMMANAGER_CID,
|
||||
contractID: DOMFMMANAGER_CONTRACTID,
|
||||
classDescription: "DOMFMRadio",
|
||||
interfaces: [Ci.nsIDOMFMRadio],
|
||||
flags: Ci.nsIClassInfo.DOM_OBJECT
|
||||
}),
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMFMRadio,
|
||||
Ci.nsIDOMGlobalPropertyInitializer,
|
||||
Ci.nsISupportsWeakReference]),
|
||||
|
||||
// nsIDOMGlobalPropertyInitializer implementation
|
||||
init: function(aWindow) {
|
||||
let secMan = Cc["@mozilla.org/scriptsecuritymanager;1"]
|
||||
.getService(Ci.nsIScriptSecurityManager);
|
||||
|
||||
let perm = Services.perms.testExactPermissionFromPrincipal(aWindow.document.nodePrincipal, "fmradio");
|
||||
this._hasPrivileges = perm == Ci.nsIPermissionManager.ALLOW_ACTION;
|
||||
|
||||
if (!this._hasPrivileges) {
|
||||
Cu.reportError("NO FMRADIO PERMISSION FOR: " + aWindow.document.nodePrincipal.origin + "\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
const messages = ["DOMFMRadio:enable:Return:OK",
|
||||
"DOMFMRadio:enable:Return:NO",
|
||||
"DOMFMRadio:disable:Return:OK",
|
||||
"DOMFMRadio:disable:Return:NO",
|
||||
"DOMFMRadio:setFrequency:Return:OK",
|
||||
"DOMFMRadio:setFrequency:Return:NO",
|
||||
"DOMFMRadio:seekUp:Return:OK",
|
||||
"DOMFMRadio:seekUp:Return:NO",
|
||||
"DOMFMRadio:seekDown:Return:OK",
|
||||
"DOMFMRadio:seekDown:Return:NO",
|
||||
"DOMFMRadio:cancelSeek:Return:OK",
|
||||
"DOMFMRadio:cancelSeek:Return:NO",
|
||||
"DOMFMRadio:frequencyChange",
|
||||
"DOMFMRadio:powerStateChange",
|
||||
"DOMFMRadio:antennaChange"];
|
||||
this.initDOMRequestHelper(aWindow, messages);
|
||||
|
||||
let els = Cc["@mozilla.org/eventlistenerservice;1"]
|
||||
.getService(Ci.nsIEventListenerService);
|
||||
|
||||
els.addSystemEventListener(aWindow, "visibilitychange",
|
||||
this._updateVisibility.bind(this),
|
||||
/* useCapture = */ true);
|
||||
|
||||
this._visibility = aWindow.document.visibilityState;
|
||||
// Unlike the |enabled| getter, this is true if *this* DOM window
|
||||
// has successfully enabled the FM radio more recently than
|
||||
// disabling it.
|
||||
this._haveEnabledRadio = false;
|
||||
},
|
||||
|
||||
// Called from DOMRequestIpcHelper
|
||||
uninit: function() {
|
||||
this._onFrequencyChange = null;
|
||||
this._onAntennaChange = null;
|
||||
this._onDisabled = null;
|
||||
this._onEnabled = null;
|
||||
},
|
||||
|
||||
_createEvent: function(name) {
|
||||
return new this._window.Event(name);
|
||||
},
|
||||
|
||||
_sendMessageForRequest: function(name, data, request) {
|
||||
let id = this.getRequestId(request);
|
||||
cpmm.sendAsyncMessage(name, {
|
||||
data: data,
|
||||
rid: id,
|
||||
mid: this._id
|
||||
});
|
||||
},
|
||||
|
||||
_fireFrequencyChangeEvent: function() {
|
||||
let e = this._createEvent("frequencychange");
|
||||
if (this._onFrequencyChange) {
|
||||
this._onFrequencyChange.handleEvent(e);
|
||||
}
|
||||
this.dispatchEvent(e);
|
||||
},
|
||||
|
||||
_firePowerStateChangeEvent: function() {
|
||||
let _enabled = this.enabled;
|
||||
debug("Current power state: " + _enabled);
|
||||
if (_enabled) {
|
||||
let e = this._createEvent("enabled");
|
||||
if (this._onEnabled) {
|
||||
this._onEnabled.handleEvent(e);
|
||||
}
|
||||
this.dispatchEvent(e);
|
||||
} else {
|
||||
let e = this._createEvent("disabled");
|
||||
if (this._onDisabled) {
|
||||
this._onDisabled.handleEvent(e);
|
||||
}
|
||||
this.dispatchEvent(e);
|
||||
}
|
||||
},
|
||||
|
||||
_fireAntennaAvailableChangeEvent: function() {
|
||||
let e = this._createEvent("antennaavailablechange");
|
||||
if (this._onAntennaChange) {
|
||||
this._onAntennaChange.handleEvent(e);
|
||||
}
|
||||
this.dispatchEvent(e);
|
||||
},
|
||||
|
||||
_updateVisibility: function(evt) {
|
||||
this._visibility = evt.target.visibilityState;
|
||||
// Only notify visibility state when we "own" the radio stream.
|
||||
if (this._haveEnabledRadio) {
|
||||
this._notifyVisibility();
|
||||
}
|
||||
},
|
||||
|
||||
_notifyVisibility: function() {
|
||||
cpmm.sendAsyncMessage("DOMFMRadio:updateVisibility", this._visibility);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
let msg = aMessage.json;
|
||||
if (msg.mid && msg.mid != this._id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let request;
|
||||
switch (aMessage.name) {
|
||||
case "DOMFMRadio:enable:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:enable:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request, "Failed to turn on the FM radio");
|
||||
break;
|
||||
case "DOMFMRadio:disable:Return:OK":
|
||||
this._haveEnabledRadio = false;
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:disable:Return:NO":
|
||||
// If disabling the radio failed, but the hardware is still
|
||||
// on, this DOM window is still responsible for the continued
|
||||
// playback.
|
||||
this._haveEnabledRadio = this.enabled;
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request,
|
||||
"Failed to turn off the FM radio");
|
||||
break;
|
||||
case "DOMFMRadio:setFrequency:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:setFrequency:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request,
|
||||
"Failed to set the FM radio frequency");
|
||||
break;
|
||||
case "DOMFMRadio:seekUp:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:seekUp:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request, "FM radio seek-up failed");
|
||||
break;
|
||||
case "DOMFMRadio:seekDown:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:seekDown:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request, "FM radio seek-down failed");
|
||||
break;
|
||||
case "DOMFMRadio:cancelSeek:Return:OK":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireSuccess(request, null);
|
||||
break;
|
||||
case "DOMFMRadio:cancelSeek:Return:NO":
|
||||
request = this.takeRequest(msg.rid);
|
||||
if (!request) {
|
||||
return;
|
||||
}
|
||||
Services.DOMRequest.fireError(request, "Failed to cancel seek");
|
||||
break;
|
||||
case "DOMFMRadio:powerStateChange":
|
||||
this._firePowerStateChangeEvent();
|
||||
break;
|
||||
case "DOMFMRadio:frequencyChange":
|
||||
this._fireFrequencyChangeEvent();
|
||||
break;
|
||||
case "DOMFMRadio:antennaChange":
|
||||
this._fireAntennaAvailableChangeEvent();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_call: function(name, arg) {
|
||||
var request = this.createRequest();
|
||||
this._sendMessageForRequest("DOMFMRadio:" + name, arg, request);
|
||||
return request;
|
||||
},
|
||||
|
||||
// nsIDOMFMRadio
|
||||
get enabled() {
|
||||
return cpmm.sendSyncMessage("DOMFMRadio:getPowerState")[0];
|
||||
},
|
||||
|
||||
get antennaAvailable() {
|
||||
return cpmm.sendSyncMessage("DOMFMRadio:getAntennaState")[0];
|
||||
},
|
||||
|
||||
get frequency() {
|
||||
return cpmm.sendSyncMessage("DOMFMRadio:getFrequency")[0];
|
||||
},
|
||||
|
||||
get frequencyUpperBound() {
|
||||
let range = cpmm.sendSyncMessage("DOMFMRadio:getCurrentBand")[0];
|
||||
return range.upper;
|
||||
},
|
||||
|
||||
get frequencyLowerBound() {
|
||||
let range = cpmm.sendSyncMessage("DOMFMRadio:getCurrentBand")[0];
|
||||
return range.lower;
|
||||
},
|
||||
|
||||
get channelWidth() {
|
||||
let range = cpmm.sendSyncMessage("DOMFMRadio:getCurrentBand")[0];
|
||||
return range.channelWidth;
|
||||
},
|
||||
|
||||
set onantennaavailablechange(callback) {
|
||||
this._onAntennaChange = callback;
|
||||
},
|
||||
|
||||
set onenabled(callback) {
|
||||
this._onEnabled = callback;
|
||||
},
|
||||
|
||||
set ondisabled(callback) {
|
||||
this._onDisabled = callback;
|
||||
},
|
||||
|
||||
set onfrequencychange(callback) {
|
||||
this._onFrequencyChange = callback;
|
||||
},
|
||||
|
||||
disable: function nsIDOMFMRadio_disable() {
|
||||
return this._call("disable", null);
|
||||
},
|
||||
|
||||
enable: function nsIDOMFMRadio_enable(frequency) {
|
||||
// FMRadio::Enable() needs the most recent visibility state
|
||||
// synchronously.
|
||||
this._haveEnabledRadio = true;
|
||||
this._notifyVisibility();
|
||||
return this._call("enable", frequency);
|
||||
},
|
||||
|
||||
setFrequency: function nsIDOMFMRadio_setFreq(frequency) {
|
||||
return this._call("setFrequency", frequency);
|
||||
},
|
||||
|
||||
seekDown: function nsIDOMFMRadio_seekDown() {
|
||||
return this._call("seekDown", null);
|
||||
},
|
||||
|
||||
seekUp: function nsIDOMFMRadio_seekUp() {
|
||||
return this._call("seekUp", null);
|
||||
},
|
||||
|
||||
cancelSeek: function nsIDOMFMRadio_cancelSeek() {
|
||||
return this._call("cancelSeek", null);
|
||||
},
|
||||
|
||||
// These are fake implementations, will be replaced by using
|
||||
// nsJSDOMEventTargetHelper, see bug 731746
|
||||
addEventListener: function(type, listener, useCapture) {
|
||||
if (!this._eventListenersByType) {
|
||||
this._eventListenersByType = {};
|
||||
}
|
||||
|
||||
if (!listener) {
|
||||
return;
|
||||
}
|
||||
|
||||
var listeners = this._eventListenersByType[type];
|
||||
if (!listeners) {
|
||||
listeners = this._eventListenersByType[type] = [];
|
||||
}
|
||||
|
||||
useCapture = !!useCapture;
|
||||
for (let i = 0, len = listeners.length; i < len; i++) {
|
||||
let l = listeners[i];
|
||||
if (l && l.listener === listener && l.useCapture === useCapture) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
listeners.push({
|
||||
listener: listener,
|
||||
useCapture: useCapture
|
||||
});
|
||||
},
|
||||
|
||||
removeEventListener: function(type, listener, useCapture) {
|
||||
if (!this._eventListenersByType) {
|
||||
return;
|
||||
}
|
||||
|
||||
useCapture = !!useCapture;
|
||||
|
||||
var listeners = this._eventListenersByType[type];
|
||||
if (listeners) {
|
||||
for (let i = 0, len = listeners.length; i < len; i++) {
|
||||
let l = listeners[i];
|
||||
if (l && l.listener === listener && l.useCapture === useCapture) {
|
||||
listeners.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
dispatchEvent: function(evt) {
|
||||
if (!this._eventListenersByType) {
|
||||
return;
|
||||
}
|
||||
|
||||
let type = evt.type;
|
||||
var listeners = this._eventListenersByType[type];
|
||||
if (listeners) {
|
||||
for (let i = 0, len = listeners.length; i < len; i++) {
|
||||
let listener = listeners[i].listener;
|
||||
|
||||
try {
|
||||
if (typeof listener == "function") {
|
||||
listener.call(this, evt);
|
||||
} else if (listener && listener.handleEvent &&
|
||||
typeof listener.handleEvent == "function") {
|
||||
listener.handleEvent(evt);
|
||||
}
|
||||
} catch (e) {
|
||||
debug("Exception is caught: " + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DOMFMRadioChild]);
|
||||
|
@ -1,472 +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"
|
||||
|
||||
let DEBUG = 0;
|
||||
if (DEBUG)
|
||||
debug = function(s) { dump("-*- DOMFMRadioParent component: " + s + "\n"); };
|
||||
else
|
||||
debug = function(s) {};
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
const MOZ_SETTINGS_CHANGED_OBSERVER_TOPIC = "mozsettings-changed";
|
||||
const PROFILE_BEFORE_CHANGE_OBSERVER_TOPIC = "profile-before-change";
|
||||
|
||||
const BAND_87500_108000_kHz = 1;
|
||||
const BAND_76000_108000_kHz = 2;
|
||||
const BAND_76000_90000_kHz = 3;
|
||||
|
||||
const FM_BANDS = { };
|
||||
FM_BANDS[BAND_76000_90000_kHz] = {
|
||||
lower: 76000,
|
||||
upper: 90000
|
||||
};
|
||||
|
||||
FM_BANDS[BAND_87500_108000_kHz] = {
|
||||
lower: 87500,
|
||||
upper: 108000
|
||||
};
|
||||
|
||||
FM_BANDS[BAND_76000_108000_kHz] = {
|
||||
lower: 76000,
|
||||
upper: 108000
|
||||
};
|
||||
|
||||
const BAND_SETTING_KEY = "fmRadio.band";
|
||||
const CHANNEL_WIDTH_SETTING_KEY = "fmRadio.channelWidth";
|
||||
|
||||
// Hal types
|
||||
const CHANNEL_WIDTH_200KHZ = 200;
|
||||
const CHANNEL_WIDTH_100KHZ = 100;
|
||||
const CHANNEL_WIDTH_50KHZ = 50;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "ppmm",
|
||||
"@mozilla.org/parentprocessmessagemanager;1",
|
||||
"nsIMessageListenerManager");
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "FMRadio", function() {
|
||||
return Cc["@mozilla.org/fmradio;1"].getService(Ci.nsIFMRadio);
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyServiceGetter(this, "gSettingsService",
|
||||
"@mozilla.org/settingsService;1",
|
||||
"nsISettingsService");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["DOMFMRadioParent"];
|
||||
|
||||
this.DOMFMRadioParent = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver,
|
||||
Ci.nsISettingsServiceCallback]),
|
||||
|
||||
_initialized: false,
|
||||
|
||||
/* Indicates if the FM radio is currently enabled */
|
||||
_isEnabled: false,
|
||||
|
||||
/* Indicates if the FM radio is currently being enabled */
|
||||
_enabling: false,
|
||||
|
||||
/* Current frequency in KHz */
|
||||
_currentFrequency: 0,
|
||||
|
||||
/* Current band setting */
|
||||
_currentBand: BAND_87500_108000_kHz,
|
||||
|
||||
/* Current channel width */
|
||||
_currentWidth: CHANNEL_WIDTH_100KHZ,
|
||||
|
||||
/* Indicates if the antenna is currently available */
|
||||
_antennaAvailable: true,
|
||||
|
||||
_seeking: false,
|
||||
|
||||
_seekingCallback: null,
|
||||
|
||||
init: function() {
|
||||
if (this._initialized === true) {
|
||||
return;
|
||||
}
|
||||
this._initialized = true;
|
||||
|
||||
this._messages = ["DOMFMRadio:enable", "DOMFMRadio:disable",
|
||||
"DOMFMRadio:setFrequency", "DOMFMRadio:getCurrentBand",
|
||||
"DOMFMRadio:getPowerState", "DOMFMRadio:getFrequency",
|
||||
"DOMFMRadio:getAntennaState",
|
||||
"DOMFMRadio:seekUp", "DOMFMRadio:seekDown",
|
||||
"DOMFMRadio:cancelSeek",
|
||||
"DOMFMRadio:updateVisibility",
|
||||
];
|
||||
this._messages.forEach(function(msgName) {
|
||||
ppmm.addMessageListener(msgName, this);
|
||||
}.bind(this));
|
||||
|
||||
Services.obs.addObserver(this, PROFILE_BEFORE_CHANGE_OBSERVER_TOPIC, false);
|
||||
Services.obs.addObserver(this, MOZ_SETTINGS_CHANGED_OBSERVER_TOPIC, false);
|
||||
|
||||
this._updatePowerState();
|
||||
|
||||
// Get the band setting and channel width setting
|
||||
let lock = gSettingsService.createLock();
|
||||
lock.get(BAND_SETTING_KEY, this);
|
||||
lock.get(CHANNEL_WIDTH_SETTING_KEY, this);
|
||||
|
||||
this._updateAntennaState();
|
||||
|
||||
let self = this;
|
||||
FMRadio.onantennastatechange = function onantennachange() {
|
||||
self._updateAntennaState();
|
||||
};
|
||||
|
||||
debug("Initialized");
|
||||
},
|
||||
|
||||
// nsISettingsServiceCallback
|
||||
handle: function(aName, aResult) {
|
||||
if (aName == BAND_SETTING_KEY) {
|
||||
this._updateBand(aResult);
|
||||
} else if (aName == CHANNEL_WIDTH_SETTING_KEY) {
|
||||
this._updateChannelWidth(aResult);
|
||||
}
|
||||
},
|
||||
|
||||
handleError: function(aErrorMessage) {
|
||||
this._updateBand(BAND_87500_108000_kHz);
|
||||
this._updateChannelWidth(CHANNEL_WIDTH_100KHZ);
|
||||
},
|
||||
|
||||
_updateAntennaState: function() {
|
||||
let antennaState = FMRadio.isAntennaAvailable;
|
||||
|
||||
if (antennaState != this._antennaAvailable) {
|
||||
this._antennaAvailable = antennaState;
|
||||
ppmm.broadcastAsyncMessage("DOMFMRadio:antennaChange", { });
|
||||
}
|
||||
},
|
||||
|
||||
_updateBand: function(band) {
|
||||
switch (parseInt(band)) {
|
||||
case BAND_87500_108000_kHz:
|
||||
case BAND_76000_108000_kHz:
|
||||
case BAND_76000_90000_kHz:
|
||||
this._currentBand = band;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_updateChannelWidth: function(channelWidth) {
|
||||
switch (parseInt(channelWidth)) {
|
||||
case CHANNEL_WIDTH_50KHZ:
|
||||
case CHANNEL_WIDTH_100KHZ:
|
||||
case CHANNEL_WIDTH_200KHZ:
|
||||
this._currentWidth = channelWidth;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update and cache the current frequency.
|
||||
* Send frequency change message if the frequency is changed.
|
||||
* The returned boolean value indicates if the frequency is changed.
|
||||
*/
|
||||
_updateFrequency: function() {
|
||||
let frequency = FMRadio.frequency;
|
||||
|
||||
if (frequency != this._currentFrequency) {
|
||||
this._currentFrequency = frequency;
|
||||
ppmm.broadcastAsyncMessage("DOMFMRadio:frequencyChange", { });
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
/**
|
||||
* Update and cache the power state of the FM radio.
|
||||
* Send message if the power state is changed.
|
||||
*/
|
||||
_updatePowerState: function() {
|
||||
let enabled = FMRadio.enabled;
|
||||
|
||||
if (this._isEnabled != enabled) {
|
||||
this._isEnabled = enabled;
|
||||
ppmm.broadcastAsyncMessage("DOMFMRadio:powerStateChange", { });
|
||||
|
||||
// If the FM radio is enabled, update the current frequency immediately,
|
||||
if (enabled) {
|
||||
this._updateFrequency();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_onSeekComplete: function(success) {
|
||||
if (this._seeking) {
|
||||
this._seeking = false;
|
||||
|
||||
if (this._seekingCallback) {
|
||||
this._seekingCallback(success);
|
||||
this._seekingCallback = null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
* Seek the next channel with given direction.
|
||||
* Only one seek action is allowed at once.
|
||||
*/
|
||||
_seekStation: function(direction, aMessage) {
|
||||
let msg = aMessage.json || { };
|
||||
let messageName = aMessage.name + ":Return";
|
||||
|
||||
// If the FM radio is disabled, do not execute the seek action.
|
||||
if(!this._isEnabled) {
|
||||
this._sendMessage(messageName, false, null, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
function callback(success) {
|
||||
debug("Seek completed.");
|
||||
if (!success) {
|
||||
self._sendMessage(messageName, false, null, msg);
|
||||
} else {
|
||||
// Make sure the FM app will get the right frequency.
|
||||
self._updateFrequency();
|
||||
self._sendMessage(messageName, true, null, msg);
|
||||
}
|
||||
}
|
||||
|
||||
if (this._seeking) {
|
||||
// Pass a boolean value to the callback which indicates that
|
||||
// the seek action failed.
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this._seekingCallback = callback;
|
||||
this._seeking = true;
|
||||
|
||||
let self = this;
|
||||
FMRadio.seek(direction);
|
||||
FMRadio.addEventListener("seekcomplete", function FM_onSeekComplete() {
|
||||
FMRadio.removeEventListener("seekcomplete", FM_onSeekComplete);
|
||||
self._onSeekComplete(true);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Round the frequency to match the range of frequency and the channel width.
|
||||
* If the given frequency is out of range, return null.
|
||||
* For example:
|
||||
* - lower: 87.5MHz, upper: 108MHz, channel width: 0.2MHz
|
||||
* 87600 is rounded to 87700
|
||||
* 87580 is rounded to 87500
|
||||
* 109000 is not rounded, null will be returned
|
||||
*/
|
||||
_roundFrequency: function(frequencyInKHz) {
|
||||
if (frequencyInKHz < FM_BANDS[this._currentBand].lower ||
|
||||
frequencyInKHz > FM_BANDS[this._currentBand].upper) {
|
||||
return null;
|
||||
}
|
||||
|
||||
let partToBeRounded = frequencyInKHz - FM_BANDS[this._currentBand].lower;
|
||||
let roundedPart = Math.round(partToBeRounded / this._currentWidth) *
|
||||
this._currentWidth;
|
||||
return FM_BANDS[this._currentBand].lower + roundedPart;
|
||||
},
|
||||
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case PROFILE_BEFORE_CHANGE_OBSERVER_TOPIC:
|
||||
this._messages.forEach(function(msgName) {
|
||||
ppmm.removeMessageListener(msgName, this);
|
||||
}.bind(this));
|
||||
|
||||
Services.obs.removeObserver(this, PROFILE_BEFORE_CHANGE_OBSERVER_TOPIC);
|
||||
Services.obs.removeObserver(this, MOZ_SETTINGS_CHANGED_OBSERVER_TOPIC);
|
||||
|
||||
ppmm = null;
|
||||
this._messages = null;
|
||||
break;
|
||||
case MOZ_SETTINGS_CHANGED_OBSERVER_TOPIC:
|
||||
let setting = JSON.parse(aData);
|
||||
this.handleMozSettingsChanged(setting);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_sendMessage: function(message, success, data, msg) {
|
||||
msg.manager.sendAsyncMessage(message + (success ? ":OK" : ":NO"), {
|
||||
data: data,
|
||||
rid: msg.rid,
|
||||
mid: msg.mid
|
||||
});
|
||||
},
|
||||
|
||||
handleMozSettingsChanged: function(settings) {
|
||||
switch (settings.key) {
|
||||
case BAND_SETTING_KEY:
|
||||
this._updateBand(settings.value);
|
||||
break;
|
||||
case CHANNEL_WIDTH_SETTING_KEY:
|
||||
this._updateChannelWidth(settings.value);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
_enableFMRadio: function(msg) {
|
||||
let frequencyInKHz = this._roundFrequency(msg.data * 1000);
|
||||
|
||||
// If the FM radio is already enabled or it is currently being enabled
|
||||
// or the given frequency is out of range, return false.
|
||||
if (this._isEnabled || this._enabling || !frequencyInKHz) {
|
||||
this._sendMessage("DOMFMRadio:enable:Return", false, null, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
this._enabling = true;
|
||||
let self = this;
|
||||
|
||||
FMRadio.addEventListener("enabled", function on_enabled() {
|
||||
dump("Perf:FMRadio:Enable " + (Date.now()- timeStart) + " ms.\n");
|
||||
self._enabling = false;
|
||||
|
||||
FMRadio.removeEventListener("enabled", on_enabled);
|
||||
|
||||
// To make sure the FM app will get right frequency after the FM
|
||||
// radio is enabled, we have to set the frequency first.
|
||||
FMRadio.setFrequency(frequencyInKHz);
|
||||
|
||||
// Update the current frequency without sending 'frequencyChange'
|
||||
// msg, to make sure the FM app will get the right frequency when the
|
||||
// 'enabled' event is fired.
|
||||
self._currentFrequency = FMRadio.frequency;
|
||||
|
||||
self._updatePowerState();
|
||||
self._sendMessage("DOMFMRadio:enable:Return", true, null, msg);
|
||||
|
||||
// The frequency is changed from 'null' to some number, so we should
|
||||
// send the 'frequencyChange' message manually.
|
||||
ppmm.broadcastAsyncMessage("DOMFMRadio:frequencyChange", { });
|
||||
});
|
||||
|
||||
let timeStart = Date.now();
|
||||
|
||||
FMRadio.enable({
|
||||
lowerLimit: FM_BANDS[self._currentBand].lower,
|
||||
upperLimit: FM_BANDS[self._currentBand].upper,
|
||||
channelWidth: self._currentWidth // 100KHz by default
|
||||
});
|
||||
},
|
||||
|
||||
_disableFMRadio: function(msg) {
|
||||
// If the FM radio is already disabled, return false.
|
||||
if (!this._isEnabled) {
|
||||
this._sendMessage("DOMFMRadio:disable:Return", false, null, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
let self = this;
|
||||
FMRadio.addEventListener("disabled", function on_disabled() {
|
||||
debug("FM Radio is disabled!");
|
||||
FMRadio.removeEventListener("disabled", on_disabled);
|
||||
|
||||
self._updatePowerState();
|
||||
self._sendMessage("DOMFMRadio:disable:Return", true, null, msg);
|
||||
|
||||
// If the FM Radio is currently seeking, no fail-to-seek or similar
|
||||
// event will be fired, execute the seek callback manually.
|
||||
self._onSeekComplete(false);
|
||||
});
|
||||
|
||||
FMRadio.disable();
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
let msg = aMessage.json || {};
|
||||
msg.manager = aMessage.target;
|
||||
|
||||
let ret = 0;
|
||||
let self = this;
|
||||
|
||||
if (!aMessage.target.assertPermission("fmradio")) {
|
||||
Cu.reportError("FMRadio message " + aMessage.name +
|
||||
" from a content process with no 'fmradio' privileges.");
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (aMessage.name) {
|
||||
case "DOMFMRadio:enable":
|
||||
self._enableFMRadio(msg);
|
||||
break;
|
||||
case "DOMFMRadio:disable":
|
||||
self._disableFMRadio(msg);
|
||||
break;
|
||||
case "DOMFMRadio:setFrequency":
|
||||
let frequencyInKHz = self._roundFrequency(msg.data * 1000);
|
||||
|
||||
// If the FM radio is disabled or the given frequency is out of range,
|
||||
// skip to set frequency and send back the False message immediately.
|
||||
if (!self._isEnabled || !frequencyInKHz) {
|
||||
self._sendMessage("DOMFMRadio:setFrequency:Return", false, null, msg);
|
||||
} else {
|
||||
FMRadio.setFrequency(frequencyInKHz);
|
||||
self._sendMessage("DOMFMRadio:setFrequency:Return", true, null, msg);
|
||||
this._updateFrequency();
|
||||
}
|
||||
break;
|
||||
case "DOMFMRadio:getCurrentBand":
|
||||
// this message is sync
|
||||
return {
|
||||
lower: FM_BANDS[self._currentBand].lower / 1000, // in MHz
|
||||
upper: FM_BANDS[self._currentBand].upper / 1000, // in MHz
|
||||
channelWidth: self._currentWidth / 1000 // in MHz
|
||||
};
|
||||
case "DOMFMRadio:getPowerState":
|
||||
// this message is sync
|
||||
return self._isEnabled;
|
||||
case "DOMFMRadio:getFrequency":
|
||||
// this message is sync
|
||||
return self._isEnabled ? this._currentFrequency / 1000 : null; // in MHz
|
||||
case "DOMFMRadio:getAntennaState":
|
||||
// this message is sync
|
||||
return self._antennaAvailable;
|
||||
case "DOMFMRadio:seekUp":
|
||||
self._seekStation(Ci.nsIFMRadio.SEEK_DIRECTION_UP, aMessage);
|
||||
break;
|
||||
case "DOMFMRadio:seekDown":
|
||||
self._seekStation(Ci.nsIFMRadio.SEEK_DIRECTION_DOWN, aMessage);
|
||||
break;
|
||||
case "DOMFMRadio:cancelSeek":
|
||||
// If the FM radio is disabled, or the FM radio is not currently
|
||||
// seeking, do not execute the cancel seek action.
|
||||
if (!self._isEnabled || !self._seeking) {
|
||||
self._sendMessage("DOMFMRadio:cancelSeek:Return", false, null, msg);
|
||||
} else {
|
||||
FMRadio.cancelSeek();
|
||||
// No fail-to-seek or similar event will be fired from the hal part,
|
||||
// so execute the seek callback here manually.
|
||||
this._onSeekComplete(false);
|
||||
// The FM radio will stop at one frequency without any event, so we need to
|
||||
// update the current frequency, make sure the FM app will get the right frequency.
|
||||
this._updateFrequency();
|
||||
self._sendMessage("DOMFMRadio:cancelSeek:Return", true, null, msg);
|
||||
}
|
||||
break;
|
||||
case "DOMFMRadio:updateVisibility":
|
||||
FMRadio.updateVisible(msg == 'visible');
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
DOMFMRadioParent.init();
|
||||
|
@ -1,264 +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/. */
|
||||
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "nsIAudioManager.h"
|
||||
#include "FMRadio.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsFMRadioSettings.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
#undef LOG
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <android/log.h>
|
||||
#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "FMRadio" , ## args)
|
||||
#else
|
||||
#define LOG(args...)
|
||||
#endif
|
||||
|
||||
// The pref indicates if the device has an internal antenna.
|
||||
// If the pref is true, the antanna will be always available.
|
||||
#define DOM_FM_ANTENNA_INTERNAL_PREF "dom.fm.antenna.internal"
|
||||
|
||||
#define RADIO_SEEK_COMPLETE_EVENT_NAME NS_LITERAL_STRING("seekcomplete")
|
||||
#define RADIO_DISABLED_EVENT_NAME NS_LITERAL_STRING("disabled")
|
||||
#define RADIO_ENABLED_EVENT_NAME NS_LITERAL_STRING("enabled")
|
||||
#define ANTENNA_STATE_CHANGED_EVENT_NAME NS_LITERAL_STRING("antennastatechange")
|
||||
|
||||
#define NS_AUDIOMANAGER_CONTRACTID "@mozilla.org/telephony/audiomanager;1"
|
||||
|
||||
using namespace mozilla::dom::fm;
|
||||
using namespace mozilla::hal;
|
||||
using mozilla::Preferences;
|
||||
|
||||
FMRadio::FMRadio()
|
||||
: mHeadphoneState(SWITCH_STATE_OFF)
|
||||
, mHasInternalAntenna(false)
|
||||
, mHidden(true)
|
||||
{
|
||||
LOG("FMRadio is initialized.");
|
||||
|
||||
mHasInternalAntenna = Preferences::GetBool(DOM_FM_ANTENNA_INTERNAL_PREF,
|
||||
/* default = */ false);
|
||||
if (mHasInternalAntenna) {
|
||||
LOG("We have an internal antenna.");
|
||||
} else {
|
||||
RegisterSwitchObserver(SWITCH_HEADPHONES, this);
|
||||
mHeadphoneState = GetCurrentSwitchState(SWITCH_HEADPHONES);
|
||||
}
|
||||
|
||||
RegisterFMRadioObserver(this);
|
||||
}
|
||||
|
||||
FMRadio::~FMRadio()
|
||||
{
|
||||
UnregisterFMRadioObserver(this);
|
||||
if (!mHasInternalAntenna) {
|
||||
UnregisterSwitchObserver(SWITCH_HEADPHONES, this);
|
||||
}
|
||||
}
|
||||
|
||||
DOMCI_DATA(FMRadio, FMRadio)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(FMRadio)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFMRadio)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(FMRadio)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(FMRadio, seekcomplete)
|
||||
NS_IMPL_EVENT_HANDLER(FMRadio, disabled)
|
||||
NS_IMPL_EVENT_HANDLER(FMRadio, enabled)
|
||||
NS_IMPL_EVENT_HANDLER(FMRadio, antennastatechange)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FMRadio, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(FMRadio, nsDOMEventTargetHelper)
|
||||
|
||||
/* readonly attribute boolean isAntennaAvailable; */
|
||||
NS_IMETHODIMP FMRadio::GetIsAntennaAvailable(bool *aIsAvailable)
|
||||
{
|
||||
if (mHasInternalAntenna) {
|
||||
*aIsAvailable = true;
|
||||
} else {
|
||||
*aIsAvailable = mHeadphoneState != SWITCH_STATE_OFF;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute long frequency; */
|
||||
NS_IMETHODIMP FMRadio::GetFrequency(int32_t *aFrequency)
|
||||
{
|
||||
*aFrequency = GetFMRadioFrequency();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* readonly attribute blean enabled; */
|
||||
NS_IMETHODIMP FMRadio::GetEnabled(bool *aEnabled)
|
||||
{
|
||||
*aEnabled = IsFMRadioOn();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void enable (in nsIFMRadioSettings settings); */
|
||||
NS_IMETHODIMP FMRadio::Enable(nsIFMRadioSettings *settings)
|
||||
{
|
||||
hal::FMRadioSettings info;
|
||||
|
||||
int32_t upperLimit, lowerLimit, channelWidth;
|
||||
|
||||
if (!mAudioChannelAgent) {
|
||||
nsresult rv;
|
||||
mAudioChannelAgent = do_CreateInstance("@mozilla.org/audiochannelagent;1", &rv);
|
||||
if (!mAudioChannelAgent) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
mAudioChannelAgent->Init(AUDIO_CHANNEL_CONTENT, this);
|
||||
}
|
||||
|
||||
bool canPlay;
|
||||
mAudioChannelAgent->SetVisibilityState(!mHidden);
|
||||
mAudioChannelAgent->StartPlaying(&canPlay);
|
||||
|
||||
settings->GetUpperLimit(&upperLimit);
|
||||
settings->GetLowerLimit(&lowerLimit);
|
||||
settings->GetChannelWidth(&channelWidth);
|
||||
|
||||
info.upperLimit() = upperLimit;
|
||||
info.lowerLimit() = lowerLimit;
|
||||
info.spaceType() = channelWidth;
|
||||
|
||||
EnableFMRadio(info);
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(audioManager, NS_OK);
|
||||
|
||||
audioManager->SetFmRadioAudioEnabled(true);
|
||||
// We enable the hardware, but mute the audio stream, in order to
|
||||
// simplify state handling. This is simpler but worse for battery
|
||||
// life; followup is bug 820282.
|
||||
// Note: To adjust FM volume is only available after setting up
|
||||
// routing patch.
|
||||
CanPlayChanged(canPlay);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void disableRadio (); */
|
||||
NS_IMETHODIMP FMRadio::Disable()
|
||||
{
|
||||
// Fix Bug 796733.
|
||||
// DisableFMRadio should be called before SetFmRadioAudioEnabled to prevent
|
||||
// the annoying beep sound.
|
||||
DisableFMRadio();
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(audioManager, NS_OK);
|
||||
|
||||
audioManager->SetFmRadioAudioEnabled(false);
|
||||
|
||||
if (mAudioChannelAgent) {
|
||||
mAudioChannelAgent->StopPlaying();
|
||||
mAudioChannelAgent = nullptr;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void cancelSeek */
|
||||
NS_IMETHODIMP FMRadio::CancelSeek()
|
||||
{
|
||||
CancelFMRadioSeek();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void seek (in long direction); */
|
||||
NS_IMETHODIMP FMRadio::Seek(int32_t direction)
|
||||
{
|
||||
if (direction == (int)FM_RADIO_SEEK_DIRECTION_UP) {
|
||||
FMRadioSeek(FM_RADIO_SEEK_DIRECTION_UP);
|
||||
} else {
|
||||
FMRadioSeek(FM_RADIO_SEEK_DIRECTION_DOWN);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* nsIFMRadioSettings getSettings (); */
|
||||
NS_IMETHODIMP FMRadio::GetSettings(nsIFMRadioSettings * *_retval)
|
||||
{
|
||||
hal::FMRadioSettings settings;
|
||||
GetFMRadioSettings(&settings);
|
||||
|
||||
nsCOMPtr<nsIFMRadioSettings> radioSettings(new nsFMRadioSettings(
|
||||
settings.upperLimit(),
|
||||
settings.lowerLimit(),
|
||||
settings.spaceType()));
|
||||
radioSettings.forget(_retval);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* void setFrequency (in long frequency); */
|
||||
NS_IMETHODIMP FMRadio::SetFrequency(int32_t frequency)
|
||||
{
|
||||
SetFMRadioFrequency(frequency);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP FMRadio::UpdateVisible(bool aVisible)
|
||||
{
|
||||
mHidden = !aVisible;
|
||||
if (mAudioChannelAgent) {
|
||||
mAudioChannelAgent->SetVisibilityState(!mHidden);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void FMRadio::Notify(const SwitchEvent& aEvent)
|
||||
{
|
||||
if (mHeadphoneState != aEvent.status()) {
|
||||
LOG("Antenna state is changed!");
|
||||
mHeadphoneState = aEvent.status();
|
||||
DispatchTrustedEvent(ANTENNA_STATE_CHANGED_EVENT_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
void FMRadio::Notify(const FMRadioOperationInformation& info)
|
||||
{
|
||||
switch (info.operation())
|
||||
{
|
||||
case FM_RADIO_OPERATION_ENABLE:
|
||||
DispatchTrustedEvent(RADIO_ENABLED_EVENT_NAME);
|
||||
break;
|
||||
case FM_RADIO_OPERATION_DISABLE:
|
||||
DispatchTrustedEvent(RADIO_DISABLED_EVENT_NAME);
|
||||
break;
|
||||
case FM_RADIO_OPERATION_SEEK:
|
||||
DispatchTrustedEvent(RADIO_SEEK_COMPLETE_EVENT_NAME);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
/* void canPlayChanged (in boolean canPlay); */
|
||||
NS_IMETHODIMP FMRadio::CanPlayChanged(bool canPlay)
|
||||
{
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
NS_ENSURE_TRUE(audioManager, NS_OK);
|
||||
|
||||
bool AudioEnabled;
|
||||
audioManager->GetFmRadioAudioEnabled(&AudioEnabled);
|
||||
if (AudioEnabled == canPlay) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* mute fm first, it should be better to stop&resume fm */
|
||||
audioManager->SetFmRadioAudioEnabled(canPlay);
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_fm_radio_h__
|
||||
#define mozilla_dom_fm_radio_h__
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsIFMRadio.h"
|
||||
#include "AudioChannelService.h"
|
||||
|
||||
#define NS_FMRADIO_CONTRACTID "@mozilla.org/fmradio;1"
|
||||
// 9cb91834-78a9-4029-b644-7806173c5e2d
|
||||
#define NS_FMRADIO_CID {0x9cb91834, 0x78a9, 0x4029, \
|
||||
{0xb6, 0x44, 0x78, 0x06, 0x17, 0x3c, 0x5e, 0x2d}}
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace fm {
|
||||
|
||||
/* Header file */
|
||||
class FMRadio : public nsDOMEventTargetHelper
|
||||
, public nsIFMRadio
|
||||
, public hal::FMRadioObserver
|
||||
, public hal::SwitchObserver
|
||||
, public nsIAudioChannelAgentCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIFMRADIO
|
||||
NS_DECL_NSIAUDIOCHANNELAGENTCALLBACK
|
||||
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
FMRadio();
|
||||
virtual void Notify(const hal::FMRadioOperationInformation& info);
|
||||
virtual void Notify(const hal::SwitchEvent& aEvent);
|
||||
|
||||
private:
|
||||
~FMRadio();
|
||||
|
||||
nsCOMPtr<nsIAudioChannelAgent> mAudioChannelAgent;
|
||||
hal::SwitchState mHeadphoneState;
|
||||
bool mHasInternalAntenna;
|
||||
bool mHidden;
|
||||
};
|
||||
|
||||
} // namespace fm
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
#endif
|
||||
|
@ -1,61 +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/. */
|
||||
|
||||
#include "nsFMRadioSettings.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS1(nsFMRadioSettings, nsIFMRadioSettings)
|
||||
|
||||
nsFMRadioSettings::nsFMRadioSettings(int32_t aUpperLimit,
|
||||
int32_t aLowerLimit,
|
||||
int32_t aChannelWidth)
|
||||
{
|
||||
mUpperLimit = aUpperLimit;
|
||||
mLowerLimit = aLowerLimit;
|
||||
mChannelWidth = aChannelWidth;
|
||||
}
|
||||
|
||||
nsFMRadioSettings::~nsFMRadioSettings()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/* attribute long upperLimit; */
|
||||
NS_IMETHODIMP nsFMRadioSettings::GetUpperLimit(int32_t *aUpperLimit)
|
||||
{
|
||||
*aUpperLimit = mUpperLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFMRadioSettings::SetUpperLimit(int32_t aUpperLimit)
|
||||
{
|
||||
mUpperLimit = aUpperLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute long lowerLimit; */
|
||||
NS_IMETHODIMP nsFMRadioSettings::GetLowerLimit(int32_t *aLowerLimit)
|
||||
{
|
||||
*aLowerLimit = mLowerLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFMRadioSettings::SetLowerLimit(int32_t aLowerLimit)
|
||||
{
|
||||
mLowerLimit = aLowerLimit;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/* attribute long spaceType; */
|
||||
NS_IMETHODIMP nsFMRadioSettings::GetChannelWidth(int32_t *aChannelWidth)
|
||||
{
|
||||
*aChannelWidth = mChannelWidth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsFMRadioSettings::SetChannelWidth(int32_t aChannelWidth)
|
||||
{
|
||||
mChannelWidth = aChannelWidth;
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=40: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_fm_radio_settings_h__
|
||||
#define mozilla_dom_fm_radio_settings_h__
|
||||
|
||||
#include "nsIFMRadio.h"
|
||||
|
||||
class nsFMRadioSettings : public nsIFMRadioSettings
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIFMRADIOSETTINGS
|
||||
|
||||
nsFMRadioSettings(int32_t aUpperLimit, int32_t aLowerLimit, int32_t aChannelWidth);
|
||||
private:
|
||||
~nsFMRadioSettings();
|
||||
int32_t mUpperLimit;
|
||||
int32_t mLowerLimit;
|
||||
int32_t mChannelWidth;
|
||||
};
|
||||
#endif
|
||||
|
@ -1,122 +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/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMDOMRequest.idl"
|
||||
|
||||
[scriptable, uuid(1d0443f3-ac30-4f9e-a070-002bb20ce1e6)]
|
||||
interface nsIDOMFMRadio : nsISupports {
|
||||
/* Indicates if the FM radio is enabled. */
|
||||
readonly attribute boolean enabled;
|
||||
|
||||
/* Indicates if the antenna is plugged and available. */
|
||||
readonly attribute boolean antennaAvailable;
|
||||
|
||||
/**
|
||||
* Current frequency in MHz.
|
||||
* The value will be null if the FM radio is disabled.
|
||||
*/
|
||||
readonly attribute jsval frequency;
|
||||
|
||||
/* The upper bound of frequency in MHz. */
|
||||
readonly attribute double frequencyUpperBound;
|
||||
|
||||
/* The lower bound of frequency in MHz. */
|
||||
readonly attribute double frequencyLowerBound;
|
||||
|
||||
/**
|
||||
* The channel width of the ranges of frequency, in MHz.
|
||||
* Usually, the value is one of:
|
||||
* - 0.05 MHz
|
||||
* - 0.1 MHz
|
||||
* - 0.2 MHz
|
||||
*/
|
||||
readonly attribute double channelWidth;
|
||||
|
||||
/* Fired when the FM radio is enabled. */
|
||||
attribute nsIDOMEventListener onenabled;
|
||||
|
||||
/* Fired when the FM radio is disabled. */
|
||||
attribute nsIDOMEventListener ondisabled;
|
||||
|
||||
/**
|
||||
* Fired when the antenna becomes available or unavailable, i.e., fired when
|
||||
* the antennaAvailable attribute changes.
|
||||
*/
|
||||
attribute nsIDOMEventListener onantennaavailablechange;
|
||||
|
||||
/* Fired when the FM radio's frequency is changed. */
|
||||
attribute nsIDOMEventListener onfrequencychange;
|
||||
|
||||
/**
|
||||
* Power the FM radio off.
|
||||
* The disabled event will be fired if this request completes successfully.
|
||||
*/
|
||||
nsIDOMDOMRequest disable();
|
||||
|
||||
/**
|
||||
* Power the FM radio on, and tune the radio to the given frequency in MHz.
|
||||
* This will fail if the given frequency is out of range.
|
||||
* The enabled event and frequencychange event will be fired if this request
|
||||
* completes successfully.
|
||||
*/
|
||||
nsIDOMDOMRequest enable(in double frequency);
|
||||
|
||||
/**
|
||||
* Tune the FM radio to the given frequency.
|
||||
* This will fail if the given frequency is out of range.
|
||||
*
|
||||
* Note that the FM radio may not tuned to the exact frequency given. To get
|
||||
* the frequency the radio is actually tuned to, wait for the request to fire
|
||||
* onsucess (or wait for the frequencychange event to fire), and then read the
|
||||
* frequency attribute.
|
||||
*/
|
||||
nsIDOMDOMRequest setFrequency(in double frequency);
|
||||
|
||||
/**
|
||||
* Tell the FM radio to seek up to the next channel. If the frequency is
|
||||
* successfully changed, the frequencychange event will be triggered.
|
||||
*
|
||||
* Only one seek is allowed at once:
|
||||
* If the radio is seeking when the seekUp is called, onerror will be fired.
|
||||
*/
|
||||
nsIDOMDOMRequest seekUp();
|
||||
|
||||
/**
|
||||
* Tell the FM radio to seek down to the next channel. If the frequency is
|
||||
* successfully changed, the frequencychange event will be triggered.
|
||||
*
|
||||
* Only one seek is allowed at once:
|
||||
* If the radio is seeking when the seekDown is called, onerror will be fired.
|
||||
*/
|
||||
nsIDOMDOMRequest seekDown();
|
||||
|
||||
/**
|
||||
* Cancel the seek action.
|
||||
* If the radio is not currently seeking up or down, onerror will be fired.
|
||||
*/
|
||||
nsIDOMDOMRequest cancelSeek();
|
||||
|
||||
|
||||
/**
|
||||
* These functions related to EventTarget are temporary hacks:
|
||||
* - addEventListener
|
||||
* - removeEventListener
|
||||
* - handleEvent
|
||||
*
|
||||
* These will be removed by inheriting from nsIJSDOMEventTarget,
|
||||
* see bug 731746.
|
||||
*/
|
||||
[optional_argc] void addEventListener(in DOMString type,
|
||||
in nsIDOMEventListener listener,
|
||||
[optional] in boolean useCapture,
|
||||
[optional] in boolean wantsUntrusted);
|
||||
|
||||
void removeEventListener(in DOMString type,
|
||||
in nsIDOMEventListener listener,
|
||||
[optional] in boolean useCapture);
|
||||
|
||||
boolean dispatchEvent(in nsIDOMEvent evt) raises(DOMException);
|
||||
};
|
||||
|
@ -1,107 +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/. */
|
||||
|
||||
#include "nsIDOMEventTarget.idl"
|
||||
|
||||
[scriptable, uuid(c142387a-5488-454b-8b5a-91f0dbee833b)]
|
||||
interface nsIFMRadioSettings : nsISupports
|
||||
{
|
||||
/* Upper limit in KHz */
|
||||
attribute long upperLimit;
|
||||
/* Lower limit in KHz */
|
||||
attribute long lowerLimit;
|
||||
/* Channel width in KHz */
|
||||
attribute long channelWidth;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is an interface to expose the FM radio hardware related functions;
|
||||
* it's kind of the FM radio hardware wrapper interface.
|
||||
*
|
||||
* Because the WebFM API (navigator.mozFMRadio) is implemented as a JS component,
|
||||
* it can't access our C++ hardware interface directly; instead it must go
|
||||
* through this interface.
|
||||
* Do not confuse this interface with the WebFM DOM interface (nsIDOMFMRadio).
|
||||
*
|
||||
* If the WebFM API is re-written in c++ some day, this interface will be useless.
|
||||
*/
|
||||
[scriptable, builtinclass, uuid(2ee7c122-b7aa-4948-9bc5-e4593ed4ac32)]
|
||||
interface nsIFMRadio : nsIDOMEventTarget {
|
||||
const long SEEK_DIRECTION_UP = 0;
|
||||
const long SEEK_DIRECTION_DOWN = 1;
|
||||
|
||||
/**
|
||||
* Indicates if the FM radio hardware is enabled.
|
||||
*/
|
||||
readonly attribute boolean enabled;
|
||||
|
||||
/**
|
||||
* Current frequency in KHz
|
||||
*/
|
||||
readonly attribute long frequency;
|
||||
|
||||
/**
|
||||
* Indicates if the antenna is plugged in and available.
|
||||
*/
|
||||
readonly attribute boolean isAntennaAvailable;
|
||||
|
||||
/**
|
||||
* Enable the FM radio hardware with the given settings.
|
||||
*/
|
||||
void enable(in nsIFMRadioSettings settings);
|
||||
|
||||
/**
|
||||
* Disable the FM radio hardware.
|
||||
*/
|
||||
void disable();
|
||||
|
||||
/**
|
||||
* Seek the next available channel (up or down).
|
||||
*
|
||||
* @param direction
|
||||
* The value should be one of SEEK_DIRECTION_DOWN and SEEK_DIRECTION_UP
|
||||
*/
|
||||
void seek(in long direction);
|
||||
|
||||
/**
|
||||
* Cancel the seek action.
|
||||
*/
|
||||
void cancelSeek();
|
||||
|
||||
/**
|
||||
* Get the current settings.
|
||||
*/
|
||||
nsIFMRadioSettings getSettings();
|
||||
|
||||
/**
|
||||
* Set the frequency in KHz
|
||||
*/
|
||||
void setFrequency(in long frequency);
|
||||
|
||||
/**
|
||||
* Update the visibility state of our client.
|
||||
*/
|
||||
void updateVisible(in boolean visible);
|
||||
|
||||
/**
|
||||
* Fired when the antenna state is changed.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onantennastatechange;
|
||||
|
||||
/**
|
||||
* Fired when a seek action completes.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onseekcomplete;
|
||||
|
||||
/**
|
||||
* Fired when the FM radio hardware is enabled.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval onenabled;
|
||||
|
||||
/**
|
||||
* Fired when the FM radio hardware is disabled.
|
||||
*/
|
||||
[implicit_jscontext] attribute jsval ondisabled;
|
||||
};
|
||||
|
295
dom/fmradio/FMRadio.cpp
Normal file
295
dom/fmradio/FMRadio.cpp
Normal file
@ -0,0 +1,295 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/FMRadio.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/FMRadioBinding.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/PFMRadioChild.h"
|
||||
#include "mozilla/dom/FMRadioService.h"
|
||||
#include "DOMRequest.h"
|
||||
|
||||
#undef LOG
|
||||
#define LOG(args...) FM_LOG("FMRadio", args)
|
||||
|
||||
// The pref indicates if the device has an internal antenna.
|
||||
// If the pref is true, the antanna will be always available.
|
||||
#define DOM_FM_ANTENNA_INTERNAL_PREF "dom.fmradio.antenna.internal"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
using mozilla::Preferences;
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class FMRadioRequest MOZ_FINAL : public ReplyRunnable
|
||||
, public DOMRequest
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
FMRadioRequest(nsPIDOMWindow* aWindow, FMRadio* aFMRadio)
|
||||
: DOMRequest(aWindow)
|
||||
{
|
||||
// |FMRadio| inherits from |nsIDOMEventTarget| and |nsISupportsWeakReference|
|
||||
// which both inherits from nsISupports, so |nsISupports| is an ambiguous
|
||||
// base of |FMRadio|, we have to cast |aFMRadio| to one of the base classes.
|
||||
mFMRadio = do_GetWeakReference(static_cast<nsIDOMEventTarget*>(aFMRadio));
|
||||
}
|
||||
|
||||
~FMRadioRequest() { }
|
||||
|
||||
NS_IMETHODIMP
|
||||
Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
nsCOMPtr<nsIDOMEventTarget> target = do_QueryReferent(mFMRadio);
|
||||
if (!target) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
FMRadio* fmRadio = static_cast<FMRadio*>(
|
||||
static_cast<nsIDOMEventTarget*>(target));
|
||||
|
||||
if (fmRadio->mIsShutdown) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
switch (mResponseType.type()) {
|
||||
case FMRadioResponseType::TErrorResponse:
|
||||
FireError(mResponseType.get_ErrorResponse().error());
|
||||
break;
|
||||
case FMRadioResponseType::TSuccessResponse:
|
||||
FireSuccess(JS::UndefinedHandleValue);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsWeakPtr mFMRadio;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FMRadioRequest, DOMRequest)
|
||||
|
||||
FMRadio::FMRadio()
|
||||
: mHeadphoneState(SWITCH_STATE_OFF)
|
||||
, mHasInternalAntenna(false)
|
||||
, mIsShutdown(false)
|
||||
{
|
||||
LOG("FMRadio is initialized.");
|
||||
|
||||
SetIsDOMBinding();
|
||||
}
|
||||
|
||||
FMRadio::~FMRadio()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FMRadio::Init(nsPIDOMWindow *aWindow)
|
||||
{
|
||||
BindToOwner(aWindow);
|
||||
|
||||
IFMRadioService::Singleton()->AddObserver(this);
|
||||
|
||||
mHasInternalAntenna = Preferences::GetBool(DOM_FM_ANTENNA_INTERNAL_PREF,
|
||||
/* default = */ false);
|
||||
if (mHasInternalAntenna) {
|
||||
LOG("We have an internal antenna.");
|
||||
} else {
|
||||
mHeadphoneState = GetCurrentSwitchState(SWITCH_HEADPHONES);
|
||||
RegisterSwitchObserver(SWITCH_HEADPHONES, this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FMRadio::Shutdown()
|
||||
{
|
||||
IFMRadioService::Singleton()->RemoveObserver(this);
|
||||
|
||||
if (!mHasInternalAntenna) {
|
||||
UnregisterSwitchObserver(SWITCH_HEADPHONES, this);
|
||||
}
|
||||
|
||||
mIsShutdown = true;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
FMRadio::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aScope)
|
||||
{
|
||||
return FMRadioBinding::Wrap(aCx, aScope, this);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadio::Notify(const SwitchEvent& aEvent)
|
||||
{
|
||||
MOZ_ASSERT(!mHasInternalAntenna);
|
||||
|
||||
if (mHeadphoneState != aEvent.status()) {
|
||||
mHeadphoneState = aEvent.status();
|
||||
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("antennaavailablechange"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FMRadio::Notify(const FMRadioEventType& aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case FrequencyChanged:
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("frequencychange"));
|
||||
break;
|
||||
case EnabledChanged:
|
||||
if (Enabled()) {
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("enabled"));
|
||||
} else {
|
||||
DispatchTrustedEvent(NS_LITERAL_STRING("disabled"));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
FMRadio::Enabled()
|
||||
{
|
||||
return IFMRadioService::Singleton()->IsEnabled();
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadio::AntennaAvailable() const
|
||||
{
|
||||
return mHasInternalAntenna ? true : mHeadphoneState != SWITCH_STATE_OFF;
|
||||
}
|
||||
|
||||
Nullable<double>
|
||||
FMRadio::GetFrequency() const
|
||||
{
|
||||
return Enabled() ?
|
||||
Nullable<double>(IFMRadioService::Singleton()->GetFrequency()) :
|
||||
Nullable<double>();
|
||||
}
|
||||
|
||||
double
|
||||
FMRadio::FrequencyUpperBound() const
|
||||
{
|
||||
return IFMRadioService::Singleton()->GetFrequencyUpperBound();
|
||||
}
|
||||
|
||||
double
|
||||
FMRadio::FrequencyLowerBound() const
|
||||
{
|
||||
return IFMRadioService::Singleton()->GetFrequencyLowerBound();
|
||||
}
|
||||
|
||||
double
|
||||
FMRadio::ChannelWidth() const
|
||||
{
|
||||
return IFMRadioService::Singleton()->GetChannelWidth();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::Enable(double aFrequency)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->Enable(aFrequency, r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::Disable()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->Disable(r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::SetFrequency(double aFrequency)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->SetFrequency(aFrequency, r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::SeekUp()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->Seek(FM_RADIO_SEEK_DIRECTION_UP, r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::SeekDown()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->Seek(FM_RADIO_SEEK_DIRECTION_DOWN, r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<DOMRequest>
|
||||
FMRadio::CancelSeek()
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetOwner();
|
||||
if (!win) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsRefPtr<FMRadioRequest> r = new FMRadioRequest(win, this);
|
||||
IFMRadioService::Singleton()->CancelSeek(r);
|
||||
|
||||
return r.forget();
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FMRadio)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FMRadio, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(FMRadio, nsDOMEventTargetHelper)
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
92
dom/fmradio/FMRadio.h
Normal file
92
dom/fmradio/FMRadio.h
Normal file
@ -0,0 +1,92 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_FMRadio_h
|
||||
#define mozilla_dom_FMRadio_h
|
||||
|
||||
#include "FMRadioCommon.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
#include "nsWeakReference.h"
|
||||
|
||||
class nsPIDOMWindow;
|
||||
class nsIScriptContext;
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class DOMRequest;
|
||||
|
||||
class FMRadio MOZ_FINAL : public nsDOMEventTargetHelper
|
||||
, public hal::SwitchObserver
|
||||
, public FMRadioEventObserver
|
||||
, public nsSupportsWeakReference
|
||||
{
|
||||
friend class FMRadioRequest;
|
||||
|
||||
public:
|
||||
FMRadio();
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper)
|
||||
|
||||
void Init(nsPIDOMWindow *aWindow);
|
||||
void Shutdown();
|
||||
|
||||
/* hal::SwitchObserver */
|
||||
virtual void Notify(const hal::SwitchEvent& aEvent) MOZ_OVERRIDE;
|
||||
/* FMRadioEventObserver */
|
||||
virtual void Notify(const FMRadioEventType& aType) MOZ_OVERRIDE;
|
||||
|
||||
nsPIDOMWindow* GetParentObject() const
|
||||
{
|
||||
return GetOwner();
|
||||
}
|
||||
|
||||
virtual JSObject* WrapObject(JSContext* aCx,
|
||||
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
|
||||
|
||||
static bool Enabled();
|
||||
|
||||
bool AntennaAvailable() const;
|
||||
|
||||
Nullable<double> GetFrequency() const;
|
||||
|
||||
double FrequencyUpperBound() const;
|
||||
|
||||
double FrequencyLowerBound() const;
|
||||
|
||||
double ChannelWidth() const;
|
||||
|
||||
already_AddRefed<DOMRequest> Enable(double aFrequency);
|
||||
|
||||
already_AddRefed<DOMRequest> Disable();
|
||||
|
||||
already_AddRefed<DOMRequest> SetFrequency(double aFrequency);
|
||||
|
||||
already_AddRefed<DOMRequest> SeekUp();
|
||||
|
||||
already_AddRefed<DOMRequest> SeekDown();
|
||||
|
||||
already_AddRefed<DOMRequest> CancelSeek();
|
||||
|
||||
IMPL_EVENT_HANDLER(enabled);
|
||||
IMPL_EVENT_HANDLER(disabled);
|
||||
IMPL_EVENT_HANDLER(antennaavailablechange);
|
||||
IMPL_EVENT_HANDLER(frequencychange);
|
||||
|
||||
private:
|
||||
~FMRadio();
|
||||
|
||||
hal::SwitchState mHeadphoneState;
|
||||
bool mHasInternalAntenna;
|
||||
bool mIsShutdown;
|
||||
};
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_FMRadio_h
|
||||
|
42
dom/fmradio/FMRadioCommon.h
Normal file
42
dom/fmradio/FMRadioCommon.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef FMRADIOCOMMON_H_
|
||||
#define FMRADIOCOMMON_H_
|
||||
|
||||
#include "mozilla/Observer.h"
|
||||
|
||||
#undef FM_LOG
|
||||
#if defined(ANDROID)
|
||||
#include <android/log.h>
|
||||
#define FM_LOG(FMRADIO_LOG_INFO, args...) \
|
||||
__android_log_print(ANDROID_LOG_INFO, \
|
||||
FMRADIO_LOG_INFO, \
|
||||
## args)
|
||||
#else
|
||||
#define FM_LOG(args...)
|
||||
#endif
|
||||
|
||||
#define BEGIN_FMRADIO_NAMESPACE \
|
||||
namespace mozilla { namespace dom {
|
||||
#define END_FMRADIO_NAMESPACE \
|
||||
} /* namespace dom */ } /* namespace mozilla */
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
enum FMRadioEventType
|
||||
{
|
||||
FrequencyChanged,
|
||||
EnabledChanged
|
||||
};
|
||||
|
||||
typedef mozilla::Observer<FMRadioEventType> FMRadioEventObserver;
|
||||
typedef mozilla::ObserverList<FMRadioEventType> FMRadioEventObserverList;
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif /* FMRADIOCOMMON_H_ */
|
||||
|
800
dom/fmradio/FMRadioService.cpp
Normal file
800
dom/fmradio/FMRadioService.cpp
Normal file
@ -0,0 +1,800 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FMRadioService.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "nsIAudioManager.h"
|
||||
#include "AudioManager.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/FMRadioChild.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsISettingsService.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsCxPusher.h"
|
||||
|
||||
#define BAND_87500_108000_kHz 1
|
||||
#define BAND_76000_108000_kHz 2
|
||||
#define BAND_76000_90000_kHz 3
|
||||
|
||||
#define CHANNEL_WIDTH_200KHZ 200
|
||||
#define CHANNEL_WIDTH_100KHZ 100
|
||||
#define CHANNEL_WIDTH_50KHZ 50
|
||||
|
||||
#define MOZSETTINGS_CHANGED_ID "mozsettings-changed"
|
||||
#define SETTING_KEY_RIL_RADIO_DISABLED "ril.radio.disabled"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
using mozilla::Preferences;
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
// static
|
||||
IFMRadioService*
|
||||
IFMRadioService::Singleton()
|
||||
{
|
||||
if (XRE_GetProcessType() != GeckoProcessType_Default) {
|
||||
return FMRadioChild::Singleton();
|
||||
} else {
|
||||
return FMRadioService::Singleton();
|
||||
}
|
||||
}
|
||||
|
||||
StaticRefPtr<FMRadioService> FMRadioService::sFMRadioService;
|
||||
|
||||
FMRadioService::FMRadioService()
|
||||
: mPendingFrequencyInKHz(0)
|
||||
, mState(Disabled)
|
||||
, mHasReadRilSetting(false)
|
||||
, mRilDisabled(false)
|
||||
, mPendingRequest(nullptr)
|
||||
, mObserverList(FMRadioEventObserverList())
|
||||
{
|
||||
|
||||
// Read power state and frequency from Hal.
|
||||
mEnabled = IsFMRadioOn();
|
||||
if (mEnabled) {
|
||||
mPendingFrequencyInKHz = GetFMRadioFrequency();
|
||||
SetState(Enabled);
|
||||
}
|
||||
|
||||
switch (Preferences::GetInt("dom.fmradio.band", BAND_87500_108000_kHz)) {
|
||||
case BAND_76000_90000_kHz:
|
||||
mUpperBoundInKHz = 90000;
|
||||
mLowerBoundInKHz = 76000;
|
||||
break;
|
||||
case BAND_76000_108000_kHz:
|
||||
mUpperBoundInKHz = 108000;
|
||||
mLowerBoundInKHz = 76000;
|
||||
break;
|
||||
case BAND_87500_108000_kHz:
|
||||
default:
|
||||
mUpperBoundInKHz = 108000;
|
||||
mLowerBoundInKHz = 87500;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (Preferences::GetInt("dom.fmradio.channelWidth",
|
||||
CHANNEL_WIDTH_100KHZ)) {
|
||||
case CHANNEL_WIDTH_200KHZ:
|
||||
mChannelWidthInKHz = 200;
|
||||
break;
|
||||
case CHANNEL_WIDTH_50KHZ:
|
||||
mChannelWidthInKHz = 50;
|
||||
break;
|
||||
case CHANNEL_WIDTH_100KHZ:
|
||||
default:
|
||||
mChannelWidthInKHz = 100;
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
|
||||
if (NS_FAILED(obs->AddObserver(this,
|
||||
MOZSETTINGS_CHANGED_ID,
|
||||
/* useWeak */ false))) {
|
||||
NS_WARNING("Failed to add settings change observer!");
|
||||
}
|
||||
|
||||
RegisterFMRadioObserver(this);
|
||||
}
|
||||
|
||||
FMRadioService::~FMRadioService()
|
||||
{
|
||||
UnregisterFMRadioObserver(this);
|
||||
}
|
||||
|
||||
class EnableRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
EnableRunnable(int32_t aUpperLimit, int32_t aLowerLimit, int32_t aSpaceType)
|
||||
: mUpperLimit(aUpperLimit)
|
||||
, mLowerLimit(aLowerLimit)
|
||||
, mSpaceType(aSpaceType) { }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
FMRadioSettings info;
|
||||
info.upperLimit() = mUpperLimit;
|
||||
info.lowerLimit() = mLowerLimit;
|
||||
info.spaceType() = mSpaceType;
|
||||
|
||||
EnableFMRadio(info);
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
audioManager->SetFmRadioAudioEnabled(true);
|
||||
|
||||
// TODO apply path from bug 862899: AudioChannelAgent per process
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t mUpperLimit;
|
||||
int32_t mLowerLimit;
|
||||
int32_t mSpaceType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read the airplane-mode setting, if the airplane-mode is not enabled, we
|
||||
* enable the FM radio.
|
||||
*/
|
||||
class ReadRilSettingTask MOZ_FINAL : public nsISettingsServiceCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
ReadRilSettingTask(nsRefPtr<ReplyRunnable> aPendingRequest)
|
||||
: mPendingRequest(aPendingRequest) { }
|
||||
|
||||
NS_IMETHOD
|
||||
Handle(const nsAString& aName, const JS::Value& aResult)
|
||||
{
|
||||
FMRadioService* fmRadioService = FMRadioService::Singleton();
|
||||
MOZ_ASSERT(mPendingRequest == fmRadioService->mPendingRequest);
|
||||
|
||||
fmRadioService->mHasReadRilSetting = true;
|
||||
|
||||
if (!aResult.isBoolean()) {
|
||||
// Failed to read the setting value, set the state back to Disabled.
|
||||
fmRadioService->TransitionState(
|
||||
ErrorResponse(NS_LITERAL_STRING("Unexpected error")), Disabled);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
fmRadioService->mRilDisabled = aResult.toBoolean();
|
||||
if (!fmRadioService->mRilDisabled) {
|
||||
EnableRunnable* runnable =
|
||||
new EnableRunnable(fmRadioService->mUpperBoundInKHz,
|
||||
fmRadioService->mLowerBoundInKHz,
|
||||
fmRadioService->mChannelWidthInKHz);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
} else {
|
||||
// Airplane mode is enabled, set the state back to Disabled.
|
||||
fmRadioService->TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Airplane mode currently enabled")), Disabled);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
HandleError(const nsAString& aName)
|
||||
{
|
||||
FMRadioService* fmRadioService = FMRadioService::Singleton();
|
||||
MOZ_ASSERT(mPendingRequest == fmRadioService->mPendingRequest);
|
||||
|
||||
fmRadioService->TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Unexpected error")), Disabled);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<ReplyRunnable> mPendingRequest;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS1(ReadRilSettingTask, nsISettingsServiceCallback)
|
||||
|
||||
class DisableRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
DisableRunnable() { }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
// Fix Bug 796733. DisableFMRadio should be called before
|
||||
// SetFmRadioAudioEnabled to prevent the annoying beep sound.
|
||||
DisableFMRadio();
|
||||
|
||||
nsCOMPtr<nsIAudioManager> audioManager =
|
||||
do_GetService(NS_AUDIOMANAGER_CONTRACTID);
|
||||
|
||||
audioManager->SetFmRadioAudioEnabled(false);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class SetFrequencyRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SetFrequencyRunnable(int32_t aFrequency)
|
||||
: mFrequency(aFrequency) { }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
SetFMRadioFrequency(mFrequency);
|
||||
|
||||
FMRadioService* fmRadioService = FMRadioService::Singleton();
|
||||
fmRadioService->UpdateFrequency();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t mFrequency;
|
||||
};
|
||||
|
||||
class SeekRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
public:
|
||||
SeekRunnable(FMRadioSeekDirection aDirection) : mDirection(aDirection) { }
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
switch (mDirection) {
|
||||
case FM_RADIO_SEEK_DIRECTION_UP:
|
||||
case FM_RADIO_SEEK_DIRECTION_DOWN:
|
||||
FMRadioSeek(mDirection);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
FMRadioSeekDirection mDirection;
|
||||
};
|
||||
|
||||
void
|
||||
FMRadioService::TransitionState(const FMRadioResponseType& aResponse,
|
||||
FMRadioState aState)
|
||||
{
|
||||
if (mPendingRequest) {
|
||||
mPendingRequest->SetReply(aResponse);
|
||||
NS_DispatchToMainThread(mPendingRequest);
|
||||
}
|
||||
|
||||
SetState(aState);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::SetState(FMRadioState aState)
|
||||
{
|
||||
mState = aState;
|
||||
mPendingRequest = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::AddObserver(FMRadioEventObserver* aObserver)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
mObserverList.AddObserver(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::RemoveObserver(FMRadioEventObserver* aObserver)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
mObserverList.RemoveObserver(aObserver);
|
||||
|
||||
if (mObserverList.Length() == 0)
|
||||
{
|
||||
// Turning off the FM radio HW because observer list is empty.
|
||||
if (IsFMRadioOn()) {
|
||||
NS_DispatchToMainThread(new DisableRunnable());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Round the frequency to match the range of frequency and the channel width. If
|
||||
* the given frequency is out of range, return 0. For example:
|
||||
* - lower: 87500KHz, upper: 108000KHz, channel width: 200KHz
|
||||
* 87.6MHz is rounded to 87700KHz
|
||||
* 87.58MHz is rounded to 87500KHz
|
||||
* 87.49MHz is rounded to 87500KHz
|
||||
* 109MHz is not rounded, 0 will be returned
|
||||
*
|
||||
* We take frequency in MHz to prevent precision losing, and return rounded
|
||||
* value in KHz for Gonk using.
|
||||
*/
|
||||
int32_t
|
||||
FMRadioService::RoundFrequency(double aFrequencyInMHz)
|
||||
{
|
||||
double halfChannelWidthInMHz = mChannelWidthInKHz / 1000.0 / 2;
|
||||
|
||||
// Make sure 87.49999MHz would be rounded to the lower bound when
|
||||
// the lower bound is 87500KHz.
|
||||
if (aFrequencyInMHz < mLowerBoundInKHz / 1000.0 - halfChannelWidthInMHz ||
|
||||
aFrequencyInMHz > mUpperBoundInKHz / 1000.0 + halfChannelWidthInMHz) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t partToBeRounded = round(aFrequencyInMHz * 1000) - mLowerBoundInKHz;
|
||||
int32_t roundedPart = round(partToBeRounded / (double)mChannelWidthInKHz) *
|
||||
mChannelWidthInKHz;
|
||||
|
||||
return mLowerBoundInKHz + roundedPart;
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioService::IsEnabled() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
return IsFMRadioOn();
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioService::GetFrequency() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
if (IsEnabled()) {
|
||||
int32_t frequencyInKHz = GetFMRadioFrequency();
|
||||
return frequencyInKHz / 1000.0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioService::GetFrequencyUpperBound() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
return mUpperBoundInKHz / 1000.0;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioService::GetFrequencyLowerBound() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
return mLowerBoundInKHz / 1000.0;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioService::GetChannelWidth() const
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
return mChannelWidthInKHz / 1000.0;
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::Enable(double aFrequencyInMHz, ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aReplyRunnable);
|
||||
|
||||
switch (mState) {
|
||||
case Seeking:
|
||||
case Enabled:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently enabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Enabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently enabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabled:
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t roundedFrequency = RoundFrequency(aFrequencyInMHz);
|
||||
|
||||
if (!roundedFrequency) {
|
||||
aReplyRunnable->SetReply(ErrorResponse(
|
||||
NS_LITERAL_STRING("Frequency is out of range")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mHasReadRilSetting && mRilDisabled) {
|
||||
aReplyRunnable->SetReply(ErrorResponse(
|
||||
NS_LITERAL_STRING("Airplane mode currently enabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
}
|
||||
|
||||
SetState(Enabling);
|
||||
// Cache the enable request just in case disable() is called
|
||||
// while the FM radio HW is being enabled.
|
||||
mPendingRequest = aReplyRunnable;
|
||||
|
||||
// Cache the frequency value, and set it after the FM radio HW is enabled
|
||||
mPendingFrequencyInKHz = roundedFrequency;
|
||||
|
||||
if (!mHasReadRilSetting) {
|
||||
nsCOMPtr<nsISettingsService> settings =
|
||||
do_GetService("@mozilla.org/settingsService;1");
|
||||
|
||||
nsCOMPtr<nsISettingsServiceLock> settingsLock;
|
||||
nsresult rv = settings->CreateLock(getter_AddRefs(settingsLock));
|
||||
if (NS_FAILED(rv)) {
|
||||
TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Can't create settings lock")), Disabled);
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<ReadRilSettingTask> callback =
|
||||
new ReadRilSettingTask(mPendingRequest);
|
||||
|
||||
rv = settingsLock->Get(SETTING_KEY_RIL_RADIO_DISABLED, callback);
|
||||
if (NS_FAILED(rv)) {
|
||||
TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Can't get settings lock")), Disabled);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(new EnableRunnable(mUpperBoundInKHz,
|
||||
mLowerBoundInKHz,
|
||||
mChannelWidthInKHz));
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::Disable(ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
// When airplane-mode is enabled, we will call this function from
|
||||
// FMRadioService::Observe without passing a ReplyRunnable, so we have to
|
||||
// check if |aReplyRunnable| is null before we dispatch it.
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
switch (mState) {
|
||||
case Disabling:
|
||||
if (aReplyRunnable) {
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
return;
|
||||
case Disabled:
|
||||
if (aReplyRunnable) {
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
return;
|
||||
case Enabled:
|
||||
case Enabling:
|
||||
case Seeking:
|
||||
break;
|
||||
}
|
||||
|
||||
nsRefPtr<ReplyRunnable> enablingRequest = mPendingRequest;
|
||||
|
||||
// If the FM Radio is currently seeking, no fail-to-seek or similar
|
||||
// event will be fired, execute the seek callback manually.
|
||||
if (mState == Seeking) {
|
||||
TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Seek action is cancelled")), Disabling);
|
||||
}
|
||||
|
||||
FMRadioState preState = mState;
|
||||
SetState(Disabling);
|
||||
mPendingRequest = aReplyRunnable;
|
||||
|
||||
if (preState == Enabling) {
|
||||
// If the radio is currently enabling, we fire the error callback on the
|
||||
// enable request immediately. When the radio finishes enabling, we'll call
|
||||
// DoDisable and fire the success callback on the disable request.
|
||||
enablingRequest->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("Enable action is cancelled")));
|
||||
NS_DispatchToMainThread(enablingRequest);
|
||||
|
||||
// If we haven't read the ril settings yet we won't enable the FM radio HW,
|
||||
// so fail the disable request immediately.
|
||||
if (!mHasReadRilSetting) {
|
||||
SetState(Disabled);
|
||||
|
||||
if (aReplyRunnable) {
|
||||
aReplyRunnable->SetReply(SuccessResponse());
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
DoDisable();
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::DoDisable()
|
||||
{
|
||||
// To make such codes work:
|
||||
// navigator.mozFMRadio.disable();
|
||||
// navigator.mozFMRadio.ondisabled = function() {
|
||||
// console.log("We will catch disabled event ");
|
||||
// };
|
||||
// we need to call hal::DisableFMRadio() asynchronously. Same reason for
|
||||
// EnableRunnable and SetFrequencyRunnable.
|
||||
NS_DispatchToMainThread(new DisableRunnable());
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::SetFrequency(double aFrequencyInMHz,
|
||||
ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aReplyRunnable);
|
||||
|
||||
switch (mState) {
|
||||
case Disabled:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Enabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently enabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Seeking:
|
||||
CancelFMRadioSeek();
|
||||
TransitionState(ErrorResponse(
|
||||
NS_LITERAL_STRING("Seek action is cancelled")), Enabled);
|
||||
break;
|
||||
case Enabled:
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t roundedFrequency = RoundFrequency(aFrequencyInMHz);
|
||||
|
||||
if (!roundedFrequency) {
|
||||
aReplyRunnable->SetReply(ErrorResponse(
|
||||
NS_LITERAL_STRING("Frequency is out of range")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_DispatchToMainThread(new SetFrequencyRunnable(roundedFrequency));
|
||||
|
||||
aReplyRunnable->SetReply(SuccessResponse());
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::Seek(FMRadioSeekDirection aDirection,
|
||||
ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aReplyRunnable);
|
||||
|
||||
switch (mState) {
|
||||
case Enabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently enabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabled:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabled")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Seeking:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently seeking")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Disabling:
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently disabling")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
case Enabled:
|
||||
break;
|
||||
}
|
||||
|
||||
SetState(Seeking);
|
||||
mPendingRequest = aReplyRunnable;
|
||||
|
||||
NS_DispatchToMainThread(new SeekRunnable(aDirection));
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::CancelSeek(ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
MOZ_ASSERT(aReplyRunnable);
|
||||
|
||||
// We accept canceling seek request only if it's currently seeking.
|
||||
if (mState != Seeking) {
|
||||
aReplyRunnable->SetReply(
|
||||
ErrorResponse(NS_LITERAL_STRING("FM radio currently not seeking")));
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
return;
|
||||
}
|
||||
|
||||
// Cancel the seek immediately to prevent it from completing.
|
||||
CancelFMRadioSeek();
|
||||
|
||||
TransitionState(
|
||||
ErrorResponse(NS_LITERAL_STRING("Seek action is cancelled")), Enabled);
|
||||
|
||||
aReplyRunnable->SetReply(SuccessResponse());
|
||||
NS_DispatchToMainThread(aReplyRunnable);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FMRadioService::Observe(nsISupports * aSubject,
|
||||
const char * aTopic,
|
||||
const PRUnichar * aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(sFMRadioService);
|
||||
|
||||
if (strcmp(aTopic, MOZSETTINGS_CHANGED_ID) != 0) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// The string that we're interested in will be a JSON string looks like:
|
||||
// {"key":"ril.radio.disabled","value":true}
|
||||
AutoSafeJSContext cx;
|
||||
const nsDependentString dataStr(aData);
|
||||
JS::Rooted<JS::Value> val(cx);
|
||||
if (!JS_ParseJSON(cx, dataStr.get(), dataStr.Length(), &val) ||
|
||||
!val.isObject()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JSObject& obj(val.toObject());
|
||||
JS::Rooted<JS::Value> key(cx);
|
||||
if (!JS_GetProperty(cx, &obj, "key", &key) ||
|
||||
!key.isString()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JSString*> jsKey(cx, key.toString());
|
||||
nsDependentJSString keyStr;
|
||||
if (!keyStr.init(cx, jsKey)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
JS::Rooted<JS::Value> value(cx);
|
||||
if (!JS_GetProperty(cx, &obj, "value", &value)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (keyStr.EqualsLiteral(SETTING_KEY_RIL_RADIO_DISABLED)) {
|
||||
if (!value.isBoolean()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mRilDisabled = value.toBoolean();
|
||||
mHasReadRilSetting = true;
|
||||
|
||||
// Disable the FM radio HW if Airplane mode is enabled.
|
||||
if (mRilDisabled) {
|
||||
Disable(nullptr);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::NotifyFMRadioEvent(FMRadioEventType aType)
|
||||
{
|
||||
mObserverList.Broadcast(aType);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::Notify(const FMRadioOperationInformation& aInfo)
|
||||
{
|
||||
switch (aInfo.operation()) {
|
||||
case FM_RADIO_OPERATION_ENABLE:
|
||||
MOZ_ASSERT(IsFMRadioOn());
|
||||
MOZ_ASSERT(mState == Disabling || mState == Enabling);
|
||||
|
||||
// If we're disabling, disable the radio right now.
|
||||
if (mState == Disabling) {
|
||||
DoDisable();
|
||||
return;
|
||||
}
|
||||
|
||||
// Fire success callback on the enable request.
|
||||
TransitionState(SuccessResponse(), Enabled);
|
||||
|
||||
// To make sure the FM app will get the right frequency after the FM
|
||||
// radio is enabled, we have to set the frequency first.
|
||||
SetFMRadioFrequency(mPendingFrequencyInKHz);
|
||||
|
||||
// Update the current frequency without sending the`FrequencyChanged`
|
||||
// event, to make sure the FM app will get the right frequency when the
|
||||
// `EnabledChange` event is sent.
|
||||
mPendingFrequencyInKHz = GetFMRadioFrequency();
|
||||
UpdatePowerState();
|
||||
|
||||
// The frequency was changed from '0' to some meaningful number, so we
|
||||
// should send the `FrequencyChanged` event manually.
|
||||
NotifyFMRadioEvent(FrequencyChanged);
|
||||
break;
|
||||
case FM_RADIO_OPERATION_DISABLE:
|
||||
MOZ_ASSERT(mState == Disabling);
|
||||
|
||||
TransitionState(SuccessResponse(), Disabled);
|
||||
UpdatePowerState();
|
||||
break;
|
||||
case FM_RADIO_OPERATION_SEEK:
|
||||
|
||||
// Seek action might be cancelled by SetFrequency(), we need to check if
|
||||
// the current state is Seeking.
|
||||
if (mState == Seeking) {
|
||||
TransitionState(SuccessResponse(), Enabled);
|
||||
}
|
||||
|
||||
UpdateFrequency();
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::UpdatePowerState()
|
||||
{
|
||||
bool enabled = IsFMRadioOn();
|
||||
if (enabled != mEnabled) {
|
||||
mEnabled = enabled;
|
||||
NotifyFMRadioEvent(EnabledChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioService::UpdateFrequency()
|
||||
{
|
||||
int32_t frequency = GetFMRadioFrequency();
|
||||
if (mPendingFrequencyInKHz != frequency) {
|
||||
mPendingFrequencyInKHz = frequency;
|
||||
NotifyFMRadioEvent(FrequencyChanged);
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
FMRadioService*
|
||||
FMRadioService::Singleton()
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sFMRadioService) {
|
||||
sFMRadioService = new FMRadioService();
|
||||
}
|
||||
|
||||
return sFMRadioService;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(FMRadioService, nsIObserver)
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
207
dom/fmradio/FMRadioService.h
Normal file
207
dom/fmradio/FMRadioService.h
Normal file
@ -0,0 +1,207 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_fmradioservice_h__
|
||||
#define mozilla_dom_fmradioservice_h__
|
||||
|
||||
#include "mozilla/dom/PFMRadioRequest.h"
|
||||
#include "FMRadioCommon.h"
|
||||
#include "mozilla/Hal.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class ReplyRunnable : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ReplyRunnable() : mResponseType(SuccessResponse()) {}
|
||||
virtual ~ReplyRunnable() {}
|
||||
|
||||
void
|
||||
SetReply(const FMRadioResponseType& aResponseType)
|
||||
{
|
||||
mResponseType = aResponseType;
|
||||
}
|
||||
|
||||
protected:
|
||||
FMRadioResponseType mResponseType;
|
||||
};
|
||||
|
||||
/**
|
||||
* The FMRadio Service Interface for FMRadio.
|
||||
*
|
||||
* There are two concrete classes which implement this interface:
|
||||
* - FMRadioService
|
||||
* It's used in the main process, implements all the logics about FM Radio.
|
||||
*
|
||||
* - FMRadioChild
|
||||
* It's used in subprocess. It's a kind of proxy which just sends all
|
||||
* the requests to main process through IPC channel.
|
||||
*
|
||||
* All the requests coming from the content page will be redirected to the
|
||||
* concrete class object.
|
||||
*
|
||||
* Consider navigator.mozFMRadio.enable(). Here is the call sequence:
|
||||
* - OOP
|
||||
* Child:
|
||||
* (1) Call navigator.mozFMRadio.enable().
|
||||
* (2) Return a DOMRequest object, and call FMRadioChild.Enable() with a
|
||||
* ReplyRunnable object.
|
||||
* (3) Send IPC message to main process.
|
||||
* Parent:
|
||||
* (4) Call FMRadioService::Enable() with a ReplyRunnable object.
|
||||
* (5) Call hal::EnableFMRadio().
|
||||
* (6) Notify FMRadioService object when FM radio HW is enabled.
|
||||
* (7) Dispatch the ReplyRunnable object created in (4).
|
||||
* (8) Send IPC message back to child process.
|
||||
* Child:
|
||||
* (9) Dispatch the ReplyRunnable object created in (2).
|
||||
* (10) Fire success callback of the DOMRequest Object created in (2).
|
||||
* _ _ _ _ _ _ _ _ _ _ _ _ _ _
|
||||
* | OOP |
|
||||
* | |
|
||||
* Page FMRadio | FMRadioChild IPC | FMRadioService Hal
|
||||
* | (1) | | | | | | |
|
||||
* |----->| (2) | | | | | |
|
||||
* | |--------|--------->| (3) | | | |
|
||||
* | | | |-----------> | | (4) | |
|
||||
* | | | | |--|---------->| (5) |
|
||||
* | | | | | | |--------->|
|
||||
* | | | | | | | (6) |
|
||||
* | | | | | | (7) |<---------|
|
||||
* | | | | (8) |<-|-----------| |
|
||||
* | | (9) | |<----------- | | | |
|
||||
* | (10) |<-------|----------| | | | |
|
||||
* |<-----| | | | | | |
|
||||
* | |
|
||||
* |_ _ _ _ _ _ _ _ _ _ _ _ _ _|
|
||||
* - non-OOP
|
||||
* In non-OOP model, we don't need to send messages between processes, so
|
||||
* the call sequences are much more simpler, it almost just follows the
|
||||
* sequences presented in OOP model: (1) (2) (5) (6) (9) and (10).
|
||||
*
|
||||
*/
|
||||
class IFMRadioService
|
||||
{
|
||||
protected:
|
||||
virtual ~IFMRadioService() { }
|
||||
|
||||
public:
|
||||
virtual bool IsEnabled() const = 0;
|
||||
virtual double GetFrequency() const = 0;
|
||||
virtual double GetFrequencyUpperBound() const = 0;
|
||||
virtual double GetFrequencyLowerBound() const = 0;
|
||||
virtual double GetChannelWidth() const = 0;
|
||||
|
||||
virtual void Enable(double aFrequency, ReplyRunnable* aReplyRunnable) = 0;
|
||||
virtual void Disable(ReplyRunnable* aReplyRunnable) = 0;
|
||||
virtual void SetFrequency(double aFrequency, ReplyRunnable* aReplyRunnable) = 0;
|
||||
virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection,
|
||||
ReplyRunnable* aReplyRunnable) = 0;
|
||||
virtual void CancelSeek(ReplyRunnable* aReplyRunnable) = 0;
|
||||
|
||||
/**
|
||||
* Register handler to receive the FM Radio events, including:
|
||||
* - StateChangedEvent
|
||||
* - FrequencyChangedEvent
|
||||
*
|
||||
* Called by FMRadio and FMRadioParent.
|
||||
*/
|
||||
virtual void AddObserver(FMRadioEventObserver* aObserver) = 0;
|
||||
virtual void RemoveObserver(FMRadioEventObserver* aObserver) = 0;
|
||||
|
||||
/**
|
||||
* Static method to return the singleton instance. If it's in the child
|
||||
* process, we will get an object of FMRadioChild.
|
||||
*/
|
||||
static IFMRadioService* Singleton();
|
||||
};
|
||||
|
||||
enum FMRadioState
|
||||
{
|
||||
Disabled,
|
||||
Disabling,
|
||||
Enabling,
|
||||
Enabled,
|
||||
Seeking
|
||||
};
|
||||
|
||||
class FMRadioService MOZ_FINAL : public IFMRadioService
|
||||
, public hal::FMRadioObserver
|
||||
, public nsIObserver
|
||||
{
|
||||
friend class ReadRilSettingTask;
|
||||
friend class SetFrequencyRunnable;
|
||||
|
||||
public:
|
||||
static FMRadioService* Singleton();
|
||||
virtual ~FMRadioService();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
virtual bool IsEnabled() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequency() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequencyUpperBound() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequencyLowerBound() const MOZ_OVERRIDE;
|
||||
virtual double GetChannelWidth() const MOZ_OVERRIDE;
|
||||
|
||||
virtual void Enable(double aFrequency, ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void Disable(ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void SetFrequency(double aFrequency, ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection,
|
||||
ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void CancelSeek(ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual void AddObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
|
||||
virtual void RemoveObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
|
||||
|
||||
/* FMRadioObserver */
|
||||
void Notify(const hal::FMRadioOperationInformation& aInfo) MOZ_OVERRIDE;
|
||||
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
protected:
|
||||
FMRadioService();
|
||||
|
||||
private:
|
||||
int32_t RoundFrequency(double aFrequencyInMHz);
|
||||
|
||||
void NotifyFMRadioEvent(FMRadioEventType aType);
|
||||
void DoDisable();
|
||||
void TransitionState(const FMRadioResponseType& aResponse, FMRadioState aState);
|
||||
void SetState(FMRadioState aState);
|
||||
void UpdatePowerState();
|
||||
void UpdateFrequency();
|
||||
|
||||
private:
|
||||
bool mEnabled;
|
||||
|
||||
int32_t mPendingFrequencyInKHz;
|
||||
|
||||
FMRadioState mState;
|
||||
|
||||
bool mHasReadRilSetting;
|
||||
bool mRilDisabled;
|
||||
|
||||
double mUpperBoundInKHz;
|
||||
double mLowerBoundInKHz;
|
||||
double mChannelWidthInKHz;
|
||||
|
||||
nsRefPtr<ReplyRunnable> mPendingRequest;
|
||||
|
||||
FMRadioEventObserverList mObserverList;
|
||||
|
||||
static StaticRefPtr<FMRadioService> sFMRadioService;
|
||||
};
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_fmradioservice_h__
|
||||
|
@ -2,7 +2,7 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = @DEPTH@
|
||||
DEPTH = ../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
@ -13,3 +13,4 @@ include $(topsrcdir)/dom/dom-config.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
182
dom/fmradio/ipc/FMRadioChild.cpp
Normal file
182
dom/fmradio/ipc/FMRadioChild.cpp
Normal file
@ -0,0 +1,182 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FMRadioChild.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/FMRadioRequestChild.h"
|
||||
|
||||
using namespace mozilla::hal;
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
StaticAutoPtr<FMRadioChild> FMRadioChild::sFMRadioChild;
|
||||
|
||||
FMRadioChild::FMRadioChild()
|
||||
: mEnabled(false)
|
||||
, mFrequency(0)
|
||||
, mObserverList(FMRadioEventObserverList())
|
||||
{
|
||||
MOZ_COUNT_CTOR(FMRadioChild);
|
||||
|
||||
ContentChild::GetSingleton()->SendPFMRadioConstructor(this);
|
||||
|
||||
StatusInfo statusInfo;
|
||||
SendGetStatusInfo(&statusInfo);
|
||||
|
||||
mEnabled = statusInfo.enabled();
|
||||
mFrequency = statusInfo.frequency();
|
||||
mUpperBound = statusInfo.upperBound();
|
||||
mLowerBound= statusInfo.lowerBound();
|
||||
mChannelWidth = statusInfo.channelWidth();
|
||||
}
|
||||
|
||||
FMRadioChild::~FMRadioChild()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FMRadioChild);
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioChild::IsEnabled() const
|
||||
{
|
||||
return mEnabled;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioChild::GetFrequency() const
|
||||
{
|
||||
return mFrequency;
|
||||
}
|
||||
|
||||
|
||||
double
|
||||
FMRadioChild::GetFrequencyUpperBound() const
|
||||
{
|
||||
return mUpperBound;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioChild::GetFrequencyLowerBound() const
|
||||
{
|
||||
return mLowerBound;
|
||||
}
|
||||
|
||||
double
|
||||
FMRadioChild::GetChannelWidth() const
|
||||
{
|
||||
return mChannelWidth;
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioChild::Enable(double aFrequency, ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
SendRequest(aReplyRunnable, EnableRequestArgs(aFrequency));
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioChild::Disable(ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
SendRequest(aReplyRunnable, DisableRequestArgs());
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioChild::SetFrequency(double aFrequency,
|
||||
ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
SendRequest(aReplyRunnable, SetFrequencyRequestArgs(aFrequency));
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioChild::Seek(FMRadioSeekDirection aDirection, ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
SendRequest(aReplyRunnable, SeekRequestArgs(aDirection));
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioChild::CancelSeek(ReplyRunnable* aReplyRunnable)
|
||||
{
|
||||
SendRequest(aReplyRunnable, CancelSeekRequestArgs());
|
||||
}
|
||||
|
||||
inline void
|
||||
FMRadioChild::NotifyFMRadioEvent(FMRadioEventType aType)
|
||||
{
|
||||
mObserverList.Broadcast(aType);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioChild::AddObserver(FMRadioEventObserver* aObserver)
|
||||
{
|
||||
mObserverList.AddObserver(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioChild::RemoveObserver(FMRadioEventObserver* aObserver)
|
||||
{
|
||||
mObserverList.RemoveObserver(aObserver);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioChild::SendRequest(ReplyRunnable* aReplyRunnable,
|
||||
FMRadioRequestArgs aArgs)
|
||||
{
|
||||
PFMRadioRequestChild* childRequest = new FMRadioRequestChild(aReplyRunnable);
|
||||
SendPFMRadioRequestConstructor(childRequest, aArgs);
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioChild::RecvNotifyFrequencyChanged(const double& aFrequency)
|
||||
{
|
||||
mFrequency = aFrequency;
|
||||
NotifyFMRadioEvent(FrequencyChanged);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioChild::RecvNotifyEnabledChanged(const bool& aEnabled,
|
||||
const double& aFrequency)
|
||||
{
|
||||
mEnabled = aEnabled;
|
||||
mFrequency = aFrequency;
|
||||
NotifyFMRadioEvent(EnabledChanged);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioChild::Recv__delete__()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
PFMRadioRequestChild*
|
||||
FMRadioChild::AllocPFMRadioRequestChild(const FMRadioRequestArgs& aArgs)
|
||||
{
|
||||
MOZ_CRASH();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioChild::DeallocPFMRadioRequestChild(PFMRadioRequestChild* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
FMRadioChild*
|
||||
FMRadioChild::Singleton()
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!sFMRadioChild) {
|
||||
sFMRadioChild = new FMRadioChild();
|
||||
}
|
||||
|
||||
return sFMRadioChild;
|
||||
}
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
91
dom/fmradio/ipc/FMRadioChild.h
Normal file
91
dom/fmradio/ipc/FMRadioChild.h
Normal file
@ -0,0 +1,91 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_fmradiochild_h__
|
||||
#define mozilla_dom_fmradiochild_h__
|
||||
|
||||
#include "FMRadioCommon.h"
|
||||
#include "FMRadioService.h"
|
||||
#include "mozilla/dom/PFMRadioChild.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
/**
|
||||
* FMRadioChild plays two roles:
|
||||
* - Kind of proxy of FMRadioService
|
||||
* Redirect all the requests coming from web content to FMRadioService
|
||||
* in parent through IPC channel.
|
||||
* - Child Actor of PFMRadio
|
||||
* IPC channel to transfer the requests.
|
||||
*/
|
||||
class FMRadioChild MOZ_FINAL : public IFMRadioService
|
||||
, public PFMRadioChild
|
||||
{
|
||||
public:
|
||||
static FMRadioChild* Singleton();
|
||||
~FMRadioChild();
|
||||
|
||||
void SendRequest(ReplyRunnable* aReplyRunnable, FMRadioRequestArgs aArgs);
|
||||
|
||||
/* IFMRadioService */
|
||||
virtual bool IsEnabled() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequency() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequencyUpperBound() const MOZ_OVERRIDE;
|
||||
virtual double GetFrequencyLowerBound() const MOZ_OVERRIDE;
|
||||
virtual double GetChannelWidth() const MOZ_OVERRIDE;
|
||||
|
||||
virtual void Enable(double aFrequency, ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void Disable(ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void SetFrequency(double frequency,
|
||||
ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void Seek(mozilla::hal::FMRadioSeekDirection aDirection,
|
||||
ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
virtual void CancelSeek(ReplyRunnable* aReplyRunnable) MOZ_OVERRIDE;
|
||||
|
||||
virtual void AddObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
|
||||
virtual void RemoveObserver(FMRadioEventObserver* aObserver) MOZ_OVERRIDE;
|
||||
|
||||
/* PFMRadioChild */
|
||||
virtual bool
|
||||
Recv__delete__() MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvNotifyFrequencyChanged(const double& aFrequency) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
RecvNotifyEnabledChanged(const bool& aEnabled,
|
||||
const double& aFrequency) MOZ_OVERRIDE;
|
||||
|
||||
virtual PFMRadioRequestChild*
|
||||
AllocPFMRadioRequestChild(const FMRadioRequestArgs& aArgs) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPFMRadioRequestChild(PFMRadioRequestChild* aActor) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
FMRadioChild();
|
||||
|
||||
void Init();
|
||||
|
||||
inline void NotifyFMRadioEvent(FMRadioEventType aType);
|
||||
|
||||
bool mEnabled;
|
||||
double mFrequency;
|
||||
double mUpperBound;
|
||||
double mLowerBound;
|
||||
double mChannelWidth;
|
||||
|
||||
FMRadioEventObserverList mObserverList;
|
||||
|
||||
private:
|
||||
static StaticAutoPtr<FMRadioChild> sFMRadioChild;
|
||||
};
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_fmradiochild_h__
|
||||
|
101
dom/fmradio/ipc/FMRadioParent.cpp
Normal file
101
dom/fmradio/ipc/FMRadioParent.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FMRadioParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "FMRadioRequestParent.h"
|
||||
#include "FMRadioService.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
FMRadioParent::FMRadioParent()
|
||||
{
|
||||
MOZ_COUNT_CTOR(FMRadioParent);
|
||||
|
||||
IFMRadioService::Singleton()->AddObserver(this);
|
||||
}
|
||||
|
||||
FMRadioParent::~FMRadioParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FMRadioParent);
|
||||
|
||||
IFMRadioService::Singleton()->RemoveObserver(this);
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioParent::RecvGetStatusInfo(StatusInfo* aStatusInfo)
|
||||
{
|
||||
aStatusInfo->enabled() = IFMRadioService::Singleton()->IsEnabled();
|
||||
aStatusInfo->frequency() = IFMRadioService::Singleton()->GetFrequency();
|
||||
aStatusInfo->upperBound() =
|
||||
IFMRadioService::Singleton()->GetFrequencyUpperBound();
|
||||
aStatusInfo->lowerBound() =
|
||||
IFMRadioService::Singleton()->GetFrequencyLowerBound();
|
||||
aStatusInfo->channelWidth() =
|
||||
IFMRadioService::Singleton()->GetChannelWidth();
|
||||
return true;
|
||||
}
|
||||
|
||||
PFMRadioRequestParent*
|
||||
FMRadioParent::AllocPFMRadioRequestParent(const FMRadioRequestArgs& aArgs)
|
||||
{
|
||||
nsRefPtr<FMRadioRequestParent> requestParent = new FMRadioRequestParent();
|
||||
|
||||
switch (aArgs.type()) {
|
||||
case FMRadioRequestArgs::TEnableRequestArgs:
|
||||
IFMRadioService::Singleton()->Enable(
|
||||
aArgs.get_EnableRequestArgs().frequency(), requestParent);
|
||||
break;
|
||||
case FMRadioRequestArgs::TDisableRequestArgs:
|
||||
IFMRadioService::Singleton()->Disable(requestParent);
|
||||
break;
|
||||
case FMRadioRequestArgs::TSetFrequencyRequestArgs:
|
||||
IFMRadioService::Singleton()->SetFrequency(
|
||||
aArgs.get_SetFrequencyRequestArgs().frequency(), requestParent);
|
||||
break;
|
||||
case FMRadioRequestArgs::TSeekRequestArgs:
|
||||
IFMRadioService::Singleton()->Seek(
|
||||
aArgs.get_SeekRequestArgs().direction(), requestParent);
|
||||
break;
|
||||
case FMRadioRequestArgs::TCancelSeekRequestArgs:
|
||||
IFMRadioService::Singleton()->CancelSeek(requestParent);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH();
|
||||
}
|
||||
|
||||
return requestParent.forget().get();
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioParent::DeallocPFMRadioRequestParent(PFMRadioRequestParent* aActor)
|
||||
{
|
||||
FMRadioRequestParent* parent = static_cast<FMRadioRequestParent*>(aActor);
|
||||
NS_RELEASE(parent);
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioParent::Notify(const FMRadioEventType& aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case FrequencyChanged:
|
||||
unused << SendNotifyFrequencyChanged(
|
||||
IFMRadioService::Singleton()->GetFrequency());
|
||||
break;
|
||||
case EnabledChanged:
|
||||
unused << SendNotifyEnabledChanged(
|
||||
IFMRadioService::Singleton()->IsEnabled(),
|
||||
IFMRadioService::Singleton()->GetFrequency());
|
||||
break;
|
||||
default:
|
||||
NS_RUNTIMEABORT("not reached");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
41
dom/fmradio/ipc/FMRadioParent.h
Normal file
41
dom/fmradio/ipc/FMRadioParent.h
Normal file
@ -0,0 +1,41 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_fmradioparent_h__
|
||||
#define mozilla_dom_fmradioparent_h__
|
||||
|
||||
#include "FMRadioCommon.h"
|
||||
#include "mozilla/dom/PFMRadioParent.h"
|
||||
#include "mozilla/HalTypes.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class PFMRadioRequestParent;
|
||||
|
||||
class FMRadioParent MOZ_FINAL : public PFMRadioParent
|
||||
, public FMRadioEventObserver
|
||||
{
|
||||
public:
|
||||
FMRadioParent();
|
||||
~FMRadioParent();
|
||||
|
||||
virtual bool
|
||||
RecvGetStatusInfo(StatusInfo* aStatusInfo) MOZ_OVERRIDE;
|
||||
|
||||
virtual PFMRadioRequestParent*
|
||||
AllocPFMRadioRequestParent(const FMRadioRequestArgs& aArgs) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool
|
||||
DeallocPFMRadioRequestParent(PFMRadioRequestParent* aActor) MOZ_OVERRIDE;
|
||||
|
||||
/* FMRadioEventObserver */
|
||||
virtual void Notify(const FMRadioEventType& aType) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_fmradioparent_h__
|
||||
|
33
dom/fmradio/ipc/FMRadioRequestChild.cpp
Normal file
33
dom/fmradio/ipc/FMRadioRequestChild.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/dom/PFMRadioRequestChild.h"
|
||||
#include "FMRadioRequestChild.h"
|
||||
#include "FMRadioService.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
FMRadioRequestChild::FMRadioRequestChild(ReplyRunnable* aReplyRunnable)
|
||||
: mReplyRunnable(aReplyRunnable)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FMRadioRequestChild);
|
||||
}
|
||||
|
||||
FMRadioRequestChild::~FMRadioRequestChild()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FMRadioRequestChild);
|
||||
}
|
||||
|
||||
bool
|
||||
FMRadioRequestChild::Recv__delete__(const FMRadioResponseType& aType)
|
||||
{
|
||||
mReplyRunnable->SetReply(aType);
|
||||
NS_DispatchToMainThread(mReplyRunnable);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
34
dom/fmradio/ipc/FMRadioRequestChild.h
Normal file
34
dom/fmradio/ipc/FMRadioRequestChild.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_fmradiorequestchild_h__
|
||||
#define mozilla_dom_fmradiorequestchild_h__
|
||||
|
||||
#include "FMRadioCommon.h"
|
||||
#include "mozilla/dom/PFMRadioRequestChild.h"
|
||||
#include "DOMRequest.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class ReplyRunnable;
|
||||
|
||||
class FMRadioRequestChild MOZ_FINAL : public PFMRadioRequestChild
|
||||
{
|
||||
public:
|
||||
FMRadioRequestChild(ReplyRunnable* aReplyRunnable);
|
||||
~FMRadioRequestChild();
|
||||
|
||||
virtual bool
|
||||
Recv__delete__(const FMRadioResponseType& aResponse) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
nsRefPtr<ReplyRunnable> mReplyRunnable;
|
||||
};
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_fmradiorequestchild_h__
|
||||
|
43
dom/fmradio/ipc/FMRadioRequestParent.cpp
Normal file
43
dom/fmradio/ipc/FMRadioRequestParent.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "FMRadioRequestParent.h"
|
||||
#include "FMRadioService.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/PFMRadio.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
FMRadioRequestParent::FMRadioRequestParent()
|
||||
: mActorDestroyed(false)
|
||||
{
|
||||
MOZ_COUNT_CTOR(FMRadioRequestParent);
|
||||
}
|
||||
|
||||
FMRadioRequestParent::~FMRadioRequestParent()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FMRadioRequestParent);
|
||||
}
|
||||
|
||||
void
|
||||
FMRadioRequestParent::ActorDestroy(ActorDestroyReason aWhy)
|
||||
{
|
||||
mActorDestroyed = true;
|
||||
}
|
||||
|
||||
nsresult
|
||||
FMRadioRequestParent::Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||
|
||||
if (!mActorDestroyed) {
|
||||
unused << Send__delete__(this, mResponseType);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
34
dom/fmradio/ipc/FMRadioRequestParent.h
Normal file
34
dom/fmradio/ipc/FMRadioRequestParent.h
Normal file
@ -0,0 +1,34 @@
|
||||
/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_fmradiorequestparent_h__
|
||||
#define mozilla_dom_fmradiorequestparent_h__
|
||||
|
||||
#include "FMRadioCommon.h"
|
||||
#include "mozilla/dom/PFMRadioRequestParent.h"
|
||||
#include "FMRadioService.h"
|
||||
|
||||
BEGIN_FMRADIO_NAMESPACE
|
||||
|
||||
class FMRadioRequestParent MOZ_FINAL : public PFMRadioRequestParent
|
||||
, public ReplyRunnable
|
||||
{
|
||||
public:
|
||||
FMRadioRequestParent();
|
||||
~FMRadioRequestParent();
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
NS_IMETHOD Run();
|
||||
|
||||
private:
|
||||
bool mActorDestroyed;
|
||||
};
|
||||
|
||||
END_FMRADIO_NAMESPACE
|
||||
|
||||
#endif // mozilla_dom_fmradiorequestparent_h__
|
||||
|
20
dom/fmradio/ipc/Makefile.in
Normal file
20
dom/fmradio/ipc/Makefile.in
Normal file
@ -0,0 +1,20 @@
|
||||
# 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/.
|
||||
|
||||
DEPTH = @DEPTH@
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/dom/fmradio \
|
||||
$(NULL)
|
||||
|
||||
include $(topsrcdir)/dom/dom-config.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
94
dom/fmradio/ipc/PFMRadio.ipdl
Normal file
94
dom/fmradio/ipc/PFMRadio.ipdl
Normal file
@ -0,0 +1,94 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include "mozilla/HalTypes.h";
|
||||
|
||||
include protocol PContent;
|
||||
include protocol PFMRadioRequest;
|
||||
|
||||
using mozilla::hal::FMRadioSeekDirection;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct EnableRequestArgs
|
||||
{
|
||||
double frequency;
|
||||
};
|
||||
|
||||
struct DisableRequestArgs
|
||||
{
|
||||
};
|
||||
|
||||
struct SetFrequencyRequestArgs
|
||||
{
|
||||
double frequency;
|
||||
};
|
||||
|
||||
struct SeekRequestArgs
|
||||
{
|
||||
FMRadioSeekDirection direction;
|
||||
};
|
||||
|
||||
struct CancelSeekRequestArgs
|
||||
{
|
||||
};
|
||||
|
||||
union FMRadioRequestArgs
|
||||
{
|
||||
EnableRequestArgs;
|
||||
DisableRequestArgs;
|
||||
SetFrequencyRequestArgs;
|
||||
SeekRequestArgs;
|
||||
CancelSeekRequestArgs;
|
||||
};
|
||||
|
||||
struct StatusInfo
|
||||
{
|
||||
bool enabled;
|
||||
double frequency;
|
||||
double upperBound;
|
||||
double lowerBound;
|
||||
double channelWidth;
|
||||
};
|
||||
|
||||
sync protocol PFMRadio
|
||||
{
|
||||
manager PContent;
|
||||
manages PFMRadioRequest;
|
||||
|
||||
child:
|
||||
/**
|
||||
* Sent when the frequency is changed.
|
||||
*/
|
||||
NotifyFrequencyChanged(double frequency);
|
||||
/**
|
||||
* Sent when the power state of FM radio HW is changed.
|
||||
*/
|
||||
NotifyEnabledChanged(bool enabled, double frequency);
|
||||
|
||||
__delete__();
|
||||
|
||||
parent:
|
||||
/**
|
||||
* Get the current status infomation of FM radio HW synchronously.
|
||||
* Sent when the singleton object of FMRadioChild is initialized.
|
||||
*/
|
||||
sync GetStatusInfo() returns (StatusInfo info);
|
||||
|
||||
/**
|
||||
* Send request to parent process to operate the FM radio HW.
|
||||
*
|
||||
* We don't have separate Enable/SetFrequency/etc. methods instead here,
|
||||
* because we can leverage the IPC messaging mechanism to manage the mapping
|
||||
* of the asynchronous request and the DOMRequest we returned to the caller
|
||||
* on web content, otherwise, we have to do the mapping stuff manually which
|
||||
* is more error prone.
|
||||
*/
|
||||
PFMRadioRequest(FMRadioRequestArgs requestType);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
43
dom/fmradio/ipc/PFMRadioRequest.ipdl
Normal file
43
dom/fmradio/ipc/PFMRadioRequest.ipdl
Normal file
@ -0,0 +1,43 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
include protocol PFMRadio;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct ErrorResponse
|
||||
{
|
||||
nsString error;
|
||||
};
|
||||
|
||||
struct SuccessResponse
|
||||
{
|
||||
};
|
||||
|
||||
union FMRadioResponseType
|
||||
{
|
||||
ErrorResponse;
|
||||
SuccessResponse;
|
||||
};
|
||||
|
||||
/**
|
||||
* The protocol is used for sending asynchronous operation requests of
|
||||
* FM radio HW from child to parent, and the type of the request is defined in
|
||||
* FMRadioRequestArgs.
|
||||
*
|
||||
* When the request completed, the result, i.e. FMRadioResponseType, will be
|
||||
* sent back to child from parent in the `__delete__` message.
|
||||
*/
|
||||
async protocol PFMRadioRequest
|
||||
{
|
||||
manager PFMRadio;
|
||||
|
||||
child:
|
||||
__delete__(FMRadioResponseType response);
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
@ -4,28 +4,22 @@
|
||||
# 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/.
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsIDOMFMRadio.idl',
|
||||
'nsIFMRadio.idl',
|
||||
EXPORTS.mozilla.dom += [
|
||||
'FMRadioChild.h',
|
||||
'FMRadioParent.h',
|
||||
'FMRadioRequestChild.h',
|
||||
'FMRadioRequestParent.h',
|
||||
]
|
||||
|
||||
XPIDL_MODULE = 'dom_fm'
|
||||
|
||||
MODULE = 'dom'
|
||||
LIBRARY_NAME = 'domfm_s'
|
||||
|
||||
CPP_SOURCES += [
|
||||
'FMRadio.cpp',
|
||||
'nsFMRadioSettings.cpp',
|
||||
'FMRadioChild.cpp',
|
||||
'FMRadioParent.cpp',
|
||||
'FMRadioRequestChild.cpp',
|
||||
'FMRadioRequestParent.cpp',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'DOMFMRadioParent.jsm',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'DOMFMRadio.manifest',
|
||||
'DOMFMRadioChild.js',
|
||||
]
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
||||
LIBXUL_LIBRARY = True
|
||||
LIBRARY_NAME = 'domfmradio_s'
|
||||
|
35
dom/fmradio/moz.build
Normal file
35
dom/fmradio/moz.build
Normal file
@ -0,0 +1,35 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG['MOZ_B2G_FM']:
|
||||
DIRS += [
|
||||
'ipc',
|
||||
]
|
||||
|
||||
MODULE = 'dom'
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'FMRadio.h',
|
||||
'FMRadioCommon.h',
|
||||
'FMRadioService.h',
|
||||
]
|
||||
|
||||
CPP_SOURCES += [
|
||||
'FMRadio.cpp',
|
||||
'FMRadioService.cpp',
|
||||
]
|
||||
|
||||
LIBXUL_LIBRARY = True
|
||||
|
||||
LIBRARY_NAME = 'domfmradio_s'
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'ipc/PFMRadio.ipdl',
|
||||
'ipc/PFMRadioRequest.ipdl',
|
||||
]
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -98,6 +98,7 @@
|
||||
#include "mozilla/dom/mobilemessage/SmsChild.h"
|
||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
|
||||
#include "mozilla/dom/bluetooth/PBluetoothChild.h"
|
||||
#include "mozilla/dom/PFMRadioChild.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
@ -954,6 +955,30 @@ ContentChild::DeallocPBluetoothChild(PBluetoothChild* aActor)
|
||||
#endif
|
||||
}
|
||||
|
||||
PFMRadioChild*
|
||||
ContentChild::AllocPFMRadioChild()
|
||||
{
|
||||
#ifdef MOZ_B2G_FM
|
||||
NS_RUNTIMEABORT("No one should be allocating PFMRadioChild actors");
|
||||
return nullptr;
|
||||
#else
|
||||
NS_RUNTIMEABORT("No support for FMRadio on this platform!");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPFMRadioChild(PFMRadioChild* aActor)
|
||||
{
|
||||
#ifdef MOZ_B2G_FM
|
||||
delete aActor;
|
||||
return true;
|
||||
#else
|
||||
NS_RUNTIMEABORT("No support for FMRadio on this platform!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
PSpeechSynthesisChild*
|
||||
ContentChild::AllocPSpeechSynthesisChild()
|
||||
{
|
||||
|
@ -158,6 +158,9 @@ public:
|
||||
virtual PBluetoothChild* AllocPBluetoothChild();
|
||||
virtual bool DeallocPBluetoothChild(PBluetoothChild* aActor);
|
||||
|
||||
virtual PFMRadioChild* AllocPFMRadioChild();
|
||||
virtual bool DeallocPFMRadioChild(PFMRadioChild* aActor);
|
||||
|
||||
virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild();
|
||||
virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor);
|
||||
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "mozilla/dom/power/PowerManagerService.h"
|
||||
#include "mozilla/dom/DOMStorageIPC.h"
|
||||
#include "mozilla/dom/bluetooth/PBluetoothParent.h"
|
||||
#include "mozilla/dom/PFMRadioParent.h"
|
||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
|
||||
#include "SmsParent.h"
|
||||
#include "mozilla/Hal.h"
|
||||
@ -125,6 +126,11 @@ using namespace mozilla::system;
|
||||
#endif
|
||||
|
||||
#include "JavaScriptParent.h"
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
#include "mozilla/dom/FMRadioParent.h"
|
||||
#endif
|
||||
|
||||
#include "Crypto.h"
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
@ -2291,6 +2297,32 @@ ContentParent::RecvPBluetoothConstructor(PBluetoothParent* aActor)
|
||||
#endif
|
||||
}
|
||||
|
||||
PFMRadioParent*
|
||||
ContentParent::AllocPFMRadioParent()
|
||||
{
|
||||
#ifdef MOZ_B2G_FM
|
||||
if (!AssertAppProcessPermission(this, "fmradio")) {
|
||||
return nullptr;
|
||||
}
|
||||
return new FMRadioParent();
|
||||
#else
|
||||
NS_WARNING("No support for FMRadio on this platform!");
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPFMRadioParent(PFMRadioParent* aActor)
|
||||
{
|
||||
#ifdef MOZ_B2G_FM
|
||||
delete aActor;
|
||||
return true;
|
||||
#else
|
||||
NS_WARNING("No support for FMRadio on this platform!");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
PSpeechSynthesisParent*
|
||||
ContentParent::AllocPSpeechSynthesisParent()
|
||||
{
|
||||
|
@ -328,6 +328,9 @@ private:
|
||||
virtual bool DeallocPBluetoothParent(PBluetoothParent* aActor);
|
||||
virtual bool RecvPBluetoothConstructor(PBluetoothParent* aActor);
|
||||
|
||||
virtual PFMRadioParent* AllocPFMRadioParent();
|
||||
virtual bool DeallocPFMRadioParent(PFMRadioParent* aActor);
|
||||
|
||||
virtual PSpeechSynthesisParent* AllocPSpeechSynthesisParent();
|
||||
virtual bool DeallocPSpeechSynthesisParent(PSpeechSynthesisParent* aActor);
|
||||
virtual bool RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor);
|
||||
|
@ -32,6 +32,7 @@ LOCAL_INCLUDES += \
|
||||
-I$(topsrcdir)/hal/sandbox \
|
||||
-I$(topsrcdir)/dom/mobilemessage/src/ipc \
|
||||
-I$(topsrcdir)/dom/devicestorage \
|
||||
-I$(topsrcdir)/dom/fmradio/ipc \
|
||||
-I$(topsrcdir)/widget/xpwidgets \
|
||||
-I$(topsrcdir)/dom/bluetooth \
|
||||
-I$(topsrcdir)/layout/base \
|
||||
|
@ -11,6 +11,7 @@ include protocol PCompositor;
|
||||
include protocol PCrashReporter;
|
||||
include protocol PExternalHelperApp;
|
||||
include protocol PDeviceStorageRequest;
|
||||
include protocol PFMRadio;
|
||||
include protocol PHal;
|
||||
include protocol PImageBridge;
|
||||
include protocol PIndexedDB;
|
||||
@ -126,6 +127,40 @@ union DeviceStorageParams
|
||||
DeviceStorageAvailableParams;
|
||||
};
|
||||
|
||||
struct FMRadioRequestEnableParams
|
||||
{
|
||||
double frequency;
|
||||
};
|
||||
|
||||
struct FMRadioRequestDisableParams
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
struct FMRadioRequestSetFrequencyParams
|
||||
{
|
||||
double frequency;
|
||||
};
|
||||
|
||||
struct FMRadioRequestSeekParams
|
||||
{
|
||||
bool upward;
|
||||
};
|
||||
|
||||
struct FMRadioRequestCancelSeekParams
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
union FMRadioRequestParams
|
||||
{
|
||||
FMRadioRequestEnableParams;
|
||||
FMRadioRequestDisableParams;
|
||||
FMRadioRequestSetFrequencyParams;
|
||||
FMRadioRequestSeekParams;
|
||||
FMRadioRequestCancelSeekParams;
|
||||
};
|
||||
|
||||
union PrefValue {
|
||||
nsCString;
|
||||
int32_t;
|
||||
@ -154,6 +189,7 @@ rpc protocol PContent
|
||||
manages PCrashReporter;
|
||||
manages PDeviceStorageRequest;
|
||||
manages PExternalHelperApp;
|
||||
manages PFMRadio;
|
||||
manages PHal;
|
||||
manages PIndexedDB;
|
||||
manages PMemoryReportRequest;
|
||||
@ -319,6 +355,8 @@ parent:
|
||||
|
||||
PBluetooth();
|
||||
|
||||
PFMRadio();
|
||||
|
||||
// Services remoting
|
||||
|
||||
async StartVisitedQuery(URIParams uri);
|
||||
|
@ -568,15 +568,14 @@ TabChild::HandlePossibleViewportChange()
|
||||
|
||||
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||
|
||||
nsViewportInfo viewportInfo =
|
||||
nsContentUtils::GetViewportInfo(document, mInnerSize.width, mInnerSize.height);
|
||||
nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize);
|
||||
SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(),
|
||||
CSSToScreenScale(viewportInfo.GetMinZoom()),
|
||||
CSSToScreenScale(viewportInfo.GetMaxZoom()));
|
||||
viewportInfo.GetMinZoom(),
|
||||
viewportInfo.GetMaxZoom());
|
||||
|
||||
float screenW = mInnerSize.width;
|
||||
float screenH = mInnerSize.height;
|
||||
CSSSize viewport(viewportInfo.GetWidth(), viewportInfo.GetHeight());
|
||||
CSSSize viewport(viewportInfo.GetSize());
|
||||
|
||||
// We're not being displayed in any way; don't bother doing anything because
|
||||
// that will just confuse future adjustments.
|
||||
@ -609,8 +608,6 @@ TabChild::HandlePossibleViewportChange()
|
||||
return;
|
||||
}
|
||||
|
||||
float minScale = 1.0f;
|
||||
|
||||
nsCOMPtr<Element> htmlDOMElement = document->GetHtmlElement();
|
||||
HTMLBodyElement* bodyDOMElement = document->GetBodyElement();
|
||||
|
||||
@ -638,12 +635,11 @@ TabChild::HandlePossibleViewportChange()
|
||||
return;
|
||||
}
|
||||
|
||||
minScale = mInnerSize.width / pageSize.width;
|
||||
minScale = clamped((double)minScale, viewportInfo.GetMinZoom(),
|
||||
viewportInfo.GetMaxZoom());
|
||||
NS_ENSURE_TRUE_VOID(minScale); // (return early rather than divide by 0)
|
||||
CSSToScreenScale minScale(mInnerSize.width / pageSize.width);
|
||||
minScale = clamped(minScale, viewportInfo.GetMinZoom(), viewportInfo.GetMaxZoom());
|
||||
NS_ENSURE_TRUE_VOID(minScale.scale); // (return early rather than divide by 0)
|
||||
|
||||
viewport.height = std::max(viewport.height, screenH / minScale);
|
||||
viewport.height = std::max(viewport.height, screenH / minScale.scale);
|
||||
SetCSSViewport(viewport);
|
||||
|
||||
float oldScreenWidth = mLastMetrics.mCompositionBounds.width;
|
||||
@ -680,14 +676,14 @@ TabChild::HandlePossibleViewportChange()
|
||||
// FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
|
||||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||
// it to the intrinsic scale.
|
||||
if (viewportInfo.GetDefaultZoom() < 0.01f) {
|
||||
viewportInfo.SetDefaultZoom(metrics.CalculateIntrinsicScale().scale);
|
||||
if (viewportInfo.GetDefaultZoom().scale < 0.01f) {
|
||||
viewportInfo.SetDefaultZoom(metrics.CalculateIntrinsicScale());
|
||||
}
|
||||
|
||||
double defaultZoom = viewportInfo.GetDefaultZoom();
|
||||
CSSToScreenScale defaultZoom = viewportInfo.GetDefaultZoom();
|
||||
MOZ_ASSERT(viewportInfo.GetMinZoom() <= defaultZoom &&
|
||||
defaultZoom <= viewportInfo.GetMaxZoom());
|
||||
metrics.mZoom = CSSToScreenScale(defaultZoom);
|
||||
metrics.mZoom = defaultZoom;
|
||||
}
|
||||
|
||||
metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||
|
@ -297,12 +297,16 @@ TabParent::ActorDestroy(ActorDestroyReason why)
|
||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (frameLoader) {
|
||||
nsCOMPtr<Element> frameElement(mFrameElement);
|
||||
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr);
|
||||
frameLoader->DestroyChild();
|
||||
|
||||
if (why == AbnormalShutdown && os) {
|
||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader),
|
||||
"oop-frameloader-crashed", nullptr);
|
||||
nsContentUtils::DispatchTrustedEvent(frameElement->OwnerDoc(), frameElement,
|
||||
NS_LITERAL_STRING("oop-browser-crashed"),
|
||||
true, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,3 +33,5 @@ phishingBlocked=The website at %S has been reported as a web forgery designed to
|
||||
cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
|
||||
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default.
|
||||
#LOCALIZATION NOTE (tabcrashed): The following string is shown in the tab title if a page with a blank title has crashed. Current UX says that the tab title should remain blank
|
||||
tabcrashed=
|
||||
|
@ -49,6 +49,7 @@ PARALLEL_DIRS += [
|
||||
'devicestorage',
|
||||
'encoding',
|
||||
'file',
|
||||
'fmradio',
|
||||
'media',
|
||||
'messages',
|
||||
'power',
|
||||
@ -86,9 +87,6 @@ if CONFIG['MOZ_B2G_RIL']:
|
||||
'voicemail',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_B2G_FM']:
|
||||
PARALLEL_DIRS += ['fm']
|
||||
|
||||
if CONFIG['MOZ_PAY']:
|
||||
PARALLEL_DIRS += ['payment']
|
||||
|
||||
|
@ -19,8 +19,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=815105
|
||||
var gData = [
|
||||
{
|
||||
perm: ["fmradio"],
|
||||
needParentPerm: true,
|
||||
obj: "mozFMRadio",
|
||||
idl: "nsIDOMFMRadio",
|
||||
webidl: "FMRadio",
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
@ -67,6 +67,10 @@ interface BluetoothAdapter : EventTarget {
|
||||
[SetterThrows]
|
||||
attribute EventHandler onscostatuschanged;
|
||||
|
||||
// Fired when remote devices query current media play status
|
||||
[SetterThrows]
|
||||
attribute EventHandler onrequestmediaplaystatus;
|
||||
|
||||
[Creator, Throws]
|
||||
DOMRequest setName(DOMString name);
|
||||
[Creator, Throws]
|
||||
|
102
dom/webidl/FMRadio.webidl
Normal file
102
dom/webidl/FMRadio.webidl
Normal file
@ -0,0 +1,102 @@
|
||||
/* 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/. */
|
||||
|
||||
interface FMRadio : EventTarget {
|
||||
/* Indicates if the FM radio is enabled. */
|
||||
readonly attribute boolean enabled;
|
||||
|
||||
/* Indicates if the antenna is plugged and available. */
|
||||
readonly attribute boolean antennaAvailable;
|
||||
|
||||
/**
|
||||
* Current frequency in MHz. The value will be null if the FM radio is
|
||||
* disabled.
|
||||
*/
|
||||
readonly attribute double? frequency;
|
||||
|
||||
/* The upper bound of frequency in MHz. */
|
||||
readonly attribute double frequencyUpperBound;
|
||||
|
||||
/* The lower bound of frequency in MHz. */
|
||||
readonly attribute double frequencyLowerBound;
|
||||
|
||||
/**
|
||||
* The difference in frequency between two "adjacent" channels, in MHz. That
|
||||
* is, any two radio channels' frequencies differ by at least channelWidth
|
||||
* MHz. Usually, the value is one of:
|
||||
* - 0.05 MHz
|
||||
* - 0.1 MHz
|
||||
* - 0.2 MHz
|
||||
*/
|
||||
readonly attribute double channelWidth;
|
||||
|
||||
/* Fired when the FM radio is enabled. */
|
||||
[SetterThrows]
|
||||
attribute EventHandler onenabled;
|
||||
|
||||
/* Fired when the FM radio is disabled. */
|
||||
[SetterThrows]
|
||||
attribute EventHandler ondisabled;
|
||||
|
||||
/**
|
||||
* Fired when the antenna becomes available or unavailable, i.e., fired when
|
||||
* the antennaAvailable attribute changes.
|
||||
*/
|
||||
[SetterThrows]
|
||||
attribute EventHandler onantennaavailablechange;
|
||||
|
||||
/* Fired when the FM radio's frequency is changed. */
|
||||
[SetterThrows]
|
||||
attribute EventHandler onfrequencychange;
|
||||
|
||||
/**
|
||||
* Power the FM radio off. The disabled event will be fired if this request
|
||||
* completes successfully.
|
||||
*/
|
||||
DOMRequest disable();
|
||||
|
||||
/**
|
||||
* Power the FM radio on, and tune the radio to the given frequency in MHz.
|
||||
* This will fail if the given frequency is out of range. The enabled event
|
||||
* and frequencychange event will be fired if this request completes
|
||||
* successfully.
|
||||
*/
|
||||
DOMRequest enable(double frequency);
|
||||
|
||||
/**
|
||||
* Tune the FM radio to the given frequency. This will fail if the given
|
||||
* frequency is out of range.
|
||||
*
|
||||
* Note that the FM radio may not tuned to the exact frequency given. To get
|
||||
* the frequency the radio is actually tuned to, wait for the request to fire
|
||||
* sucess (or wait for the frequencychange event to fire), and then read the
|
||||
* frequency attribute.
|
||||
*/
|
||||
DOMRequest setFrequency(double frequency);
|
||||
|
||||
/**
|
||||
* Tell the FM radio to seek up to the next channel. If the frequency is
|
||||
* successfully changed, the frequencychange event will be triggered.
|
||||
*
|
||||
* Only one seek is allowed at once: If the radio is seeking when the seekUp
|
||||
* is called, error will be fired.
|
||||
*/
|
||||
DOMRequest seekUp();
|
||||
|
||||
/**
|
||||
* Tell the FM radio to seek down to the next channel. If the frequency is
|
||||
* successfully changed, the frequencychange event will be triggered.
|
||||
*
|
||||
* Only one seek is allowed at once: If the radio is seeking when the
|
||||
* seekDown is called, error will be fired.
|
||||
*/
|
||||
DOMRequest seekDown();
|
||||
|
||||
/**
|
||||
* Cancel the seek action. If the radio is not currently seeking up or down,
|
||||
* error will be fired.
|
||||
*/
|
||||
DOMRequest cancelSeek();
|
||||
};
|
||||
|
@ -297,6 +297,13 @@ partial interface Navigator {
|
||||
};
|
||||
#endif // MOZ_B2G_BT
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasFMRadioSupport"]
|
||||
readonly attribute FMRadio mozFMRadio;
|
||||
};
|
||||
#endif // MOZ_B2G_FM
|
||||
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
// nsIDOMMozNavigatorTime
|
||||
partial interface Navigator {
|
||||
|
@ -525,6 +525,10 @@ webidl_files += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
ifdef MOZ_B2G_FM
|
||||
webidl_files += FMRadio.webidl
|
||||
endif
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
test_webidl_files := \
|
||||
TestCodeGen.webidl \
|
||||
|
@ -115,6 +115,12 @@ struct SizeTyped :
|
||||
};
|
||||
typedef SizeTyped<UnknownUnits> Size;
|
||||
|
||||
template<class units>
|
||||
IntSizeTyped<units> RoundedToInt(const SizeTyped<units>& aSize) {
|
||||
return IntSizeTyped<units>(int32_t(floorf(aSize.width + 0.5f)),
|
||||
int32_t(floorf(aSize.height + 0.5f)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -209,3 +209,7 @@ XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_ENDDOC , "Printing failed while c
|
||||
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_STARTPAGE , "Printing failed while starting a new page.")
|
||||
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY , "Cannot print this document yet, it is still being loaded.")
|
||||
XPC_MSG_DEF(NS_ERROR_GFX_PRINTER_NO_XUL , "Printing XUL documents is not supported.") // bugs 136185 & 240490
|
||||
|
||||
/* Codes related to content */
|
||||
XPC_MSG_DEF(NS_ERROR_CONTENT_CRASHED , "The process that hosted this content has crashed.")
|
||||
|
||||
|
@ -231,6 +231,18 @@ gfx::RectTyped<dst> operator/(const gfx::IntRectTyped<src>& aRect, const gfx::Sc
|
||||
float(aRect.height) / aScale.scale);
|
||||
}
|
||||
|
||||
template<class src, class dst>
|
||||
gfx::SizeTyped<dst> operator*(const gfx::SizeTyped<src>& aSize, const gfx::ScaleFactor<src, dst>& aScale) {
|
||||
return gfx::SizeTyped<dst>(aSize.width * aScale.scale,
|
||||
aSize.height * aScale.scale);
|
||||
}
|
||||
|
||||
template<class src, class dst>
|
||||
gfx::SizeTyped<dst> operator/(const gfx::SizeTyped<src>& aSize, const gfx::ScaleFactor<dst, src>& aScale) {
|
||||
return gfx::SizeTyped<dst>(aSize.width / aScale.scale,
|
||||
aSize.height / aScale.scale);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -9612,9 +9612,9 @@ nsIPresShell::RecomputeFontSizeInflationEnabled()
|
||||
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
|
||||
|
||||
nsViewportInfo vInf =
|
||||
nsContentUtils::GetViewportInfo(GetDocument(), screenWidth, screenHeight);
|
||||
nsContentUtils::GetViewportInfo(GetDocument(), ScreenIntSize(screenWidth, screenHeight));
|
||||
|
||||
if (vInf.GetDefaultZoom() >= 1.0 || vInf.IsAutoSizeEnabled()) {
|
||||
if (vInf.GetDefaultZoom() >= CSSToScreenScale(1.0f) || vInf.IsAutoSizeEnabled()) {
|
||||
mFontSizeInflationEnabled = false;
|
||||
return;
|
||||
}
|
||||
|
@ -122,7 +122,8 @@ endif #}
|
||||
|
||||
ifdef MOZ_B2G_FM #{
|
||||
SHARED_LIBRARY_LIBS += \
|
||||
$(DEPTH)/dom/fm/$(LIB_PREFIX)domfm_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/fmradio/$(LIB_PREFIX)domfmradio_s.$(LIB_SUFFIX) \
|
||||
$(DEPTH)/dom/fmradio/ipc/$(LIB_PREFIX)domfmradio_s.$(LIB_SUFFIX) \
|
||||
$(NULL)
|
||||
endif #}
|
||||
|
||||
@ -326,7 +327,7 @@ LOCAL_INCLUDES += -I$(topsrcdir)/dom/system/gonk
|
||||
endif #}
|
||||
|
||||
ifdef MOZ_B2G_FM #{
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/fm
|
||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/fmradio
|
||||
endif #}
|
||||
|
||||
ifdef MOZ_B2G_BT #{
|
||||
|
@ -125,11 +125,6 @@ using mozilla::dom::gonk::AudioManager;
|
||||
using mozilla::system::nsVolumeService;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
#include "FMRadio.h"
|
||||
using mozilla::dom::fm::FMRadio;
|
||||
#endif
|
||||
|
||||
#include "AudioChannelAgent.h"
|
||||
using mozilla::dom::AudioChannelAgent;
|
||||
|
||||
@ -303,10 +298,6 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSynthVoiceRegistry,
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AudioManager)
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(FMRadio)
|
||||
#endif
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AudioChannelAgent)
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceSensors)
|
||||
@ -761,10 +752,6 @@ NS_DEFINE_NAMED_CID(NS_AUDIOMANAGER_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_VOLUMESERVICE_CID);
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_B2G_FM
|
||||
NS_DEFINE_NAMED_CID(NS_FMRADIO_CID);
|
||||
#endif
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_AUDIOCHANNELAGENT_CID);
|
||||
|
||||
NS_DEFINE_NAMED_CID(NS_HTMLEDITOR_CID);
|
||||
@ -1049,9 +1036,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
{ &kNS_AUDIOMANAGER_CID, true, NULL, AudioManagerConstructor },
|
||||
{ &kNS_VOLUMESERVICE_CID, true, NULL, nsVolumeServiceConstructor },
|
||||
#endif
|
||||
#ifdef MOZ_B2G_FM
|
||||
{ &kNS_FMRADIO_CID, true, NULL, FMRadioConstructor },
|
||||
#endif
|
||||
{ &kNS_AUDIOCHANNELAGENT_CID, true, NULL, AudioChannelAgentConstructor },
|
||||
{ &kNS_HTMLEDITOR_CID, false, NULL, nsHTMLEditorConstructor },
|
||||
@ -1207,9 +1191,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
{ NS_AUDIOMANAGER_CONTRACTID, &kNS_AUDIOMANAGER_CID },
|
||||
{ NS_VOLUMESERVICE_CONTRACTID, &kNS_VOLUMESERVICE_CID },
|
||||
#endif
|
||||
#ifdef MOZ_B2G_FM
|
||||
{ NS_FMRADIO_CONTRACTID, &kNS_FMRADIO_CID },
|
||||
#endif
|
||||
{ NS_AUDIOCHANNELAGENT_CONTRACTID, &kNS_AUDIOCHANNELAGENT_CID },
|
||||
{ "@mozilla.org/editor/htmleditor;1", &kNS_HTMLEDITOR_CID },
|
||||
|
@ -255,7 +255,7 @@ this.OnRefTestLoad = function OnRefTestLoad(win)
|
||||
|
||||
#if BOOTSTRAP
|
||||
#if REFTEST_B2G
|
||||
var doc = gContainingWindow.document.getElementsByTagName("html")[0];
|
||||
var doc = gContainingWindow.document.getElementsByTagName("window")[0];
|
||||
#else
|
||||
var doc = gContainingWindow.document.getElementById('main-window');
|
||||
#endif
|
||||
|
@ -22,6 +22,7 @@ import org.mozilla.gecko.util.Clipboard;
|
||||
import org.mozilla.gecko.util.FloatUtils;
|
||||
import org.mozilla.gecko.util.GamepadUtils;
|
||||
import org.mozilla.gecko.util.HardwareUtils;
|
||||
import org.mozilla.gecko.util.StringUtils;
|
||||
import org.mozilla.gecko.util.ThreadUtils;
|
||||
import org.mozilla.gecko.util.UiAsyncTask;
|
||||
import org.mozilla.gecko.widget.GeckoActionProvider;
|
||||
@ -74,6 +75,7 @@ import android.widget.Toast;
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
@ -1422,9 +1424,46 @@ abstract public class BrowserApp extends GeckoApp
|
||||
animateHideHomePager();
|
||||
hideBrowserSearch();
|
||||
|
||||
if (!TextUtils.isEmpty(url)) {
|
||||
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
|
||||
// Don't do anything if the user entered an empty URL.
|
||||
if (TextUtils.isEmpty(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the URL doesn't look like a search query, just load it.
|
||||
if (!StringUtils.isSearchQuery(url, true)) {
|
||||
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, check for a bookmark keyword.
|
||||
ThreadUtils.postToBackgroundThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
final String keyword;
|
||||
final String keywordSearch;
|
||||
|
||||
final int index = url.indexOf(" ");
|
||||
if (index == -1) {
|
||||
keyword = url;
|
||||
keywordSearch = "";
|
||||
} else {
|
||||
keyword = url.substring(0, index);
|
||||
keywordSearch = url.substring(index + 1);
|
||||
}
|
||||
|
||||
final String keywordUrl = BrowserDB.getUrlForKeyword(getContentResolver(), keyword);
|
||||
|
||||
// If there isn't a bookmark keyword, just load the URL.
|
||||
if (TextUtils.isEmpty(keywordUrl)) {
|
||||
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
|
||||
return;
|
||||
}
|
||||
|
||||
// Otherwise, construct a search query from the bookmark keyword.
|
||||
final String searchUrl = keywordUrl.replace("%s", URLEncoder.encode(keywordSearch));
|
||||
Tabs.getInstance().loadUrl(searchUrl, Tabs.LOADURL_USER_ENTERED);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
boolean dismissEditingMode() {
|
||||
|
@ -141,6 +141,42 @@ abstract class AboutHomeTest extends BaseTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the title and keyword of a bookmark with the given URL.
|
||||
*
|
||||
* Warning: This method assumes that there's only one bookmark with the given URL.
|
||||
*/
|
||||
protected void updateBookmark(String url, String title, String keyword) {
|
||||
try {
|
||||
ContentResolver resolver = getActivity().getContentResolver();
|
||||
ClassLoader classLoader = getActivity().getClassLoader();
|
||||
Class browserDB = classLoader.loadClass("org.mozilla.gecko.db.BrowserDB");
|
||||
Method getBookmarkForUrl = browserDB.getMethod("getBookmarkForUrl", ContentResolver.class, String.class);
|
||||
|
||||
// Get the id for the bookmark with the given URL.
|
||||
Cursor c = null;
|
||||
try {
|
||||
c = (Cursor) getBookmarkForUrl.invoke(null, resolver, url);
|
||||
if (!c.moveToFirst()) {
|
||||
mAsserter.ok(false, "Getting bookmark with url", "Couldn't find bookmark with url = " + url);
|
||||
return;
|
||||
}
|
||||
|
||||
int id = c.getInt(c.getColumnIndexOrThrow("_id"));
|
||||
Method updateBookmark = browserDB.getMethod("updateBookmark", ContentResolver.class, int.class, String.class, String.class, String.class);
|
||||
updateBookmark.invoke(null, resolver, id, url, title, keyword);
|
||||
|
||||
mAsserter.ok(true, "Updating bookmark", "Updating bookmark with url = " + url);
|
||||
} finally {
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
mAsserter.ok(false, "Exception updating bookmark: ", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void deleteBookmark(String url) {
|
||||
try {
|
||||
ContentResolver resolver = getActivity().getContentResolver();
|
||||
|
@ -2,6 +2,7 @@
|
||||
# [testAwesomebarSwipes] # disabled on fig - bug 880060
|
||||
# [testBookmark] # disabled on fig - bug 880060
|
||||
# [testBookmarklets] # disabled on fig - bug 880060
|
||||
[testBookmarkKeyword]
|
||||
[testBrowserSearchVisibility]
|
||||
[testJNI]
|
||||
# [testLoad] # see bug 851861
|
||||
|
36
mobile/android/base/tests/testBookmarkKeyword.java.in
Normal file
36
mobile/android/base/tests/testBookmarkKeyword.java.in
Normal file
@ -0,0 +1,36 @@
|
||||
#filter substitution
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
|
||||
public class testBookmarkKeyword extends AboutHomeTest {
|
||||
|
||||
@Override
|
||||
protected int getTestType() {
|
||||
return TEST_MOCHITEST;
|
||||
}
|
||||
|
||||
public void testBookmarkKeyword() {
|
||||
blockForGeckoReady();
|
||||
|
||||
final String url = getAbsoluteUrl("/robocop/robocop_blank_01.html");
|
||||
final String title = "Browser Blank Page 01";
|
||||
final String keyword = "testkeyword";
|
||||
|
||||
// Add a bookmark, and update it to have a keyword.
|
||||
addOrUpdateMobileBookmark(title, url);
|
||||
updateBookmark(url, title, keyword);
|
||||
|
||||
// Enter the keyword in the urlbar.
|
||||
inputAndLoadUrl(keyword);
|
||||
|
||||
// Wait for the page to load.
|
||||
waitForText(title);
|
||||
|
||||
// Make sure the title of the page appeared.
|
||||
verifyPageTitle(title);
|
||||
|
||||
// Delete the bookmark to clean up.
|
||||
deleteBookmark(url);
|
||||
}
|
||||
}
|
@ -13,8 +13,7 @@ class testElementTouch(MarionetteTestCase):
|
||||
button.tap()
|
||||
expected = "button1-touchstart-touchend-mousemove-mousedown-mouseup-click"
|
||||
self.wait_for_condition(lambda m: m.execute_script("return document.getElementById('button1').innerHTML;") == expected)
|
||||
button = self.marionette.find_element("id", "button2")
|
||||
button.tap()
|
||||
button.tap(0, 300)
|
||||
expected = "button2-touchstart-touchend-mousemove-mousedown-mouseup-click"
|
||||
self.wait_for_condition(lambda m: m.execute_script("return document.getElementById('button2').innerHTML;") == expected)
|
||||
|
||||
|
@ -9,7 +9,7 @@ const CHILD_SCRIPT = "chrome://specialpowers/content/specialpowers.js";
|
||||
const CHILD_SCRIPT_API = "chrome://specialpowers/content/specialpowersAPI.js";
|
||||
const CHILD_LOGGER_SCRIPT = "chrome://specialpowers/content/MozillaLogger.js";
|
||||
|
||||
let homescreen = document.getElementById('systemapp');
|
||||
let homescreen = document.getElementById('homescreen');
|
||||
let container = homescreen.contentWindow.document.getElementById('test-container');
|
||||
|
||||
function openWindow(aEvent) {
|
||||
|
@ -409,7 +409,7 @@ toolbar#nav-bar {
|
||||
if options.browserChrome or options.chrome or options.a11y or options.webapprtChrome:
|
||||
chrome += """
|
||||
overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
|
||||
overlay chrome://browser/content/shell.xhtml chrome://mochikit/content/browser-test-overlay.xul
|
||||
overlay chrome://browser/content/shell.xul chrome://mochikit/content/browser-test-overlay.xul
|
||||
overlay chrome://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
|
||||
overlay chrome://webapprt/content/webapp.xul chrome://mochikit/content/browser-test-overlay.xul
|
||||
"""
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user