Merge latest green inbound changeset and mozilla-central
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#filter substitution
|
#filter substitution
|
||||||
|
|
||||||
pref("toolkit.defaultChromeURI", "chrome://browser/content/shell.html");
|
pref("toolkit.defaultChromeURI", "chrome://browser/content/shell.xul");
|
||||||
pref("browser.chromeURL", "chrome://browser/content/");
|
pref("browser.chromeURL", "chrome://browser/content/");
|
||||||
|
|
||||||
// Device pixel to CSS px ratio, in percent. Set to -1 to calculate based on display density.
|
// 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');
|
let shell = document.getElementById('shell');
|
||||||
|
|
||||||
// The <browser> element inside it
|
// The <browser> element inside it
|
||||||
let browser = document.getElementById('systemapp');
|
let browser = document.getElementById('homescreen');
|
||||||
|
|
||||||
// Figure out the native resolution of the screen
|
// Figure out the native resolution of the screen
|
||||||
let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor)
|
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/ContactService.jsm');
|
||||||
Cu.import('resource://gre/modules/SettingsChangeNotifier.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/AlarmService.jsm');
|
||||||
Cu.import('resource://gre/modules/ActivitiesService.jsm');
|
Cu.import('resource://gre/modules/ActivitiesService.jsm');
|
||||||
Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
|
Cu.import('resource://gre/modules/PermissionPromptHelper.jsm');
|
||||||
@@ -186,7 +183,7 @@ var shell = {
|
|||||||
|
|
||||||
get contentBrowser() {
|
get contentBrowser() {
|
||||||
delete this.contentBrowser;
|
delete this.contentBrowser;
|
||||||
return this.contentBrowser = document.getElementById('systemapp');
|
return this.contentBrowser = document.getElementById('homescreen');
|
||||||
},
|
},
|
||||||
|
|
||||||
get homeURL() {
|
get homeURL() {
|
||||||
@@ -269,21 +266,21 @@ var shell = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let manifestURL = this.manifestURL;
|
let manifestURL = this.manifestURL;
|
||||||
// <html:iframe id="systemapp"
|
// <html:iframe id="homescreen"
|
||||||
// mozbrowser="true" allowfullscreen="true"
|
// 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;'>"/>
|
// 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');
|
document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe');
|
||||||
systemAppFrame.setAttribute('id', 'systemapp');
|
browserFrame.setAttribute('id', 'homescreen');
|
||||||
systemAppFrame.setAttribute('mozbrowser', 'true');
|
browserFrame.setAttribute('mozbrowser', 'true');
|
||||||
systemAppFrame.setAttribute('mozapp', manifestURL);
|
browserFrame.setAttribute('mozapp', manifestURL);
|
||||||
systemAppFrame.setAttribute('allowfullscreen', 'true');
|
browserFrame.setAttribute('allowfullscreen', 'true');
|
||||||
systemAppFrame.setAttribute('style', "overflow: hidden; height: 100%; width: 100%; border: none;");
|
browserFrame.setAttribute('style', "overflow: hidden; -moz-box-flex: 1; border: none;");
|
||||||
systemAppFrame.setAttribute('src', "data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;");
|
browserFrame.setAttribute('src', "data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;");
|
||||||
document.getElementById('container').appendChild(systemAppFrame);
|
document.getElementById('shell').appendChild(browserFrame);
|
||||||
|
|
||||||
systemAppFrame.contentWindow
|
browserFrame.contentWindow
|
||||||
.QueryInterface(Ci.nsIInterfaceRequestor)
|
.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||||
.getInterface(Ci.nsIWebNavigation)
|
.getInterface(Ci.nsIWebNavigation)
|
||||||
.sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
|
.sessionHistory = Cc["@mozilla.org/browser/shistory;1"]
|
||||||
|
|||||||
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/dbg-browser-actors.js (content/dbg-browser-actors.js)
|
||||||
content/forms.js (content/forms.js)
|
content/forms.js (content/forms.js)
|
||||||
* content/settings.js (content/settings.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)
|
* content/shell.js (content/shell.js)
|
||||||
#ifndef ANDROID
|
#ifndef ANDROID
|
||||||
content/screen.js (content/screen.js)
|
content/screen.js (content/screen.js)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"revision": "f2d88904536ccd68a3981a7feb17e56b2132838c",
|
"revision": "752ced5b3cc3208f79806eccf8d8768910f17f2b",
|
||||||
"repo_path": "/integration/gaia-central"
|
"repo_path": "/integration/gaia-central"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -172,9 +172,6 @@
|
|||||||
@BINPATH@/components/dom_cellbroadcast.xpt
|
@BINPATH@/components/dom_cellbroadcast.xpt
|
||||||
@BINPATH@/components/dom_wappush.xpt
|
@BINPATH@/components/dom_wappush.xpt
|
||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_B2G_FM
|
|
||||||
@BINPATH@/components/dom_fm.xpt
|
|
||||||
#endif
|
|
||||||
#ifdef MOZ_B2G_BT
|
#ifdef MOZ_B2G_BT
|
||||||
@BINPATH@/components/dom_bluetooth.xpt
|
@BINPATH@/components/dom_bluetooth.xpt
|
||||||
#endif
|
#endif
|
||||||
@@ -475,10 +472,6 @@
|
|||||||
@BINPATH@/components/NetworkInterfaceListService.manifest
|
@BINPATH@/components/NetworkInterfaceListService.manifest
|
||||||
@BINPATH@/components/NetworkInterfaceListService.js
|
@BINPATH@/components/NetworkInterfaceListService.js
|
||||||
#endif
|
#endif
|
||||||
#ifdef MOZ_B2G_FM
|
|
||||||
@BINPATH@/components/DOMFMRadioChild.js
|
|
||||||
@BINPATH@/components/DOMFMRadio.manifest
|
|
||||||
#endif
|
|
||||||
#ifdef MOZ_ENABLE_DBUS
|
#ifdef MOZ_ENABLE_DBUS
|
||||||
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
|
@BINPATH@/components/@DLL_PREFIX@dbusservice@DLL_SUFFIX@
|
||||||
#endif
|
#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") {
|
ownerDoc.documentURI.toLowerCase() == "about:newtab") {
|
||||||
this.onE10sAboutNewTab(aEvent, ownerDoc);
|
this.onE10sAboutNewTab(aEvent, ownerDoc);
|
||||||
}
|
}
|
||||||
|
else if (ownerDoc.documentURI.startsWith("about:tabcrashed")) {
|
||||||
|
this.onAboutTabCrashed(aEvent, ownerDoc);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onAboutCertError: function BrowserOnClick_onAboutCertError(aTargetElm, aOwnerDoc) {
|
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) {
|
ignoreWarningButton: function BrowserOnClick_ignoreWarningButton(aIsMalware) {
|
||||||
// Allow users to override and continue through to the site,
|
// Allow users to override and continue through to the site,
|
||||||
// but add a notify bar as a reminder, so that they don't lose
|
// but add a notify bar as a reminder, so that they don't lose
|
||||||
@@ -2582,6 +2601,16 @@ function getWebNavigation()
|
|||||||
}
|
}
|
||||||
|
|
||||||
function BrowserReloadWithFlags(reloadFlags) {
|
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
|
/* First, we'll try to use the session history object to reload so
|
||||||
* that framesets are handled properly. If we're in a special
|
* that framesets are handled properly. If we're in a special
|
||||||
* window (such as view-source) that has no session history, fall
|
* window (such as view-source) that has no session history, fall
|
||||||
|
|||||||
@@ -1317,7 +1317,7 @@
|
|||||||
<![CDATA[
|
<![CDATA[
|
||||||
let isRemote = aBrowser.getAttribute("remote") == "true";
|
let isRemote = aBrowser.getAttribute("remote") == "true";
|
||||||
if (isRemote == aRemote)
|
if (isRemote == aRemote)
|
||||||
return;
|
return false;
|
||||||
|
|
||||||
// Unhook our progress listener.
|
// Unhook our progress listener.
|
||||||
let tab = this._getTabForBrowser(aBrowser);
|
let tab = this._getTabForBrowser(aBrowser);
|
||||||
@@ -1338,6 +1338,8 @@
|
|||||||
tab.setAttribute("remote", "true");
|
tab.setAttribute("remote", "true");
|
||||||
else
|
else
|
||||||
tab.removeAttribute("remote");
|
tab.removeAttribute("remote");
|
||||||
|
|
||||||
|
return true;
|
||||||
]]>
|
]]>
|
||||||
</body>
|
</body>
|
||||||
</method>
|
</method>
|
||||||
@@ -3118,6 +3120,22 @@
|
|||||||
tab.setAttribute("titlechanged", "true");
|
tab.setAttribute("titlechanged", "true");
|
||||||
]]>
|
]]>
|
||||||
</handler>
|
</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>
|
</handlers>
|
||||||
</binding>
|
</binding>
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ browser.jar:
|
|||||||
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
|
content/browser/aboutRobots-icon.png (content/aboutRobots-icon.png)
|
||||||
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
|
content/browser/aboutRobots-widget-left.png (content/aboutRobots-widget-left.png)
|
||||||
content/browser/aboutSocialError.xhtml (content/aboutSocialError.xhtml)
|
content/browser/aboutSocialError.xhtml (content/aboutSocialError.xhtml)
|
||||||
|
content/browser/aboutTabCrashed.xhtml (content/aboutTabCrashed.xhtml)
|
||||||
* content/browser/browser.css (content/browser.css)
|
* content/browser/browser.css (content/browser.css)
|
||||||
* content/browser/browser.js (content/browser.js)
|
* content/browser/browser.js (content/browser.js)
|
||||||
* content/browser/browser.xul (content/browser.xul)
|
* content/browser/browser.xul (content/browser.xul)
|
||||||
|
|||||||
@@ -44,6 +44,10 @@ static RedirEntry kRedirMap[] = {
|
|||||||
{ "socialerror", "chrome://browser/content/aboutSocialError.xhtml",
|
{ "socialerror", "chrome://browser/content/aboutSocialError.xhtml",
|
||||||
nsIAboutModule::ALLOW_SCRIPT |
|
nsIAboutModule::ALLOW_SCRIPT |
|
||||||
nsIAboutModule::HIDE_FROM_ABOUTABOUT },
|
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",
|
{ "feeds", "chrome://browser/content/feeds/subscribe.xhtml",
|
||||||
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
nsIAboutModule::URI_SAFE_FOR_UNTRUSTED_CONTENT |
|
||||||
nsIAboutModule::ALLOW_SCRIPT |
|
nsIAboutModule::ALLOW_SCRIPT |
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
|
|||||||
#endif
|
#endif
|
||||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "certerror", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
{ 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 "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 "feeds", &kNS_BROWSER_ABOUT_REDIRECTOR_CID },
|
||||||
{ NS_ABOUT_MODULE_CONTRACTID_PREFIX "privatebrowsing", &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 },
|
{ 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 pluginActivateAlways.label "Allow and Remember">
|
||||||
<!ENTITY pluginBlockNow.label "Block Plugin">
|
<!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
|
<!-- LOCALIZATION NOTE: the following strings are unused in Australis, they're
|
||||||
kept here to avoid warnings from l10n tools like compare-locales on
|
kept here to avoid warnings from l10n tools like compare-locales on
|
||||||
l10n-central. They will be definitely removed when Australis is ready
|
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
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
skin/classic/browser/aboutSyncTabs.css
|
skin/classic/browser/aboutSyncTabs.css
|
||||||
#endif
|
#endif
|
||||||
|
skin/classic/browser/aboutTabCrashed.css
|
||||||
skin/classic/browser/actionicon-tab.png
|
skin/classic/browser/actionicon-tab.png
|
||||||
* skin/classic/browser/browser.css
|
* skin/classic/browser/browser.css
|
||||||
skin/classic/browser/click-to-play-warning-stripes.png
|
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
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
skin/classic/browser/aboutSyncTabs.css
|
skin/classic/browser/aboutSyncTabs.css
|
||||||
#endif
|
#endif
|
||||||
|
skin/classic/browser/aboutTabCrashed.css
|
||||||
skin/classic/browser/actionicon-tab.png
|
skin/classic/browser/actionicon-tab.png
|
||||||
skin/classic/browser/actionicon-tab@2x.png
|
skin/classic/browser/actionicon-tab@2x.png
|
||||||
* skin/classic/browser/browser.css (browser.css)
|
* 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
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
skin/classic/browser/aboutSyncTabs.css
|
skin/classic/browser/aboutSyncTabs.css
|
||||||
#endif
|
#endif
|
||||||
|
skin/classic/browser/aboutTabCrashed.css
|
||||||
skin/classic/browser/actionicon-tab.png
|
skin/classic/browser/actionicon-tab.png
|
||||||
skin/classic/browser/appmenu-icons.png
|
skin/classic/browser/appmenu-icons.png
|
||||||
skin/classic/browser/appmenu-dropmarker.png
|
skin/classic/browser/appmenu-dropmarker.png
|
||||||
@@ -282,6 +283,7 @@ browser.jar:
|
|||||||
#ifdef MOZ_SERVICES_SYNC
|
#ifdef MOZ_SERVICES_SYNC
|
||||||
skin/classic/aero/browser/aboutSyncTabs.css
|
skin/classic/aero/browser/aboutSyncTabs.css
|
||||||
#endif
|
#endif
|
||||||
|
skin/classic/aero/browser/aboutTabCrashed.css
|
||||||
skin/classic/aero/browser/actionicon-tab.png
|
skin/classic/aero/browser/actionicon-tab.png
|
||||||
skin/classic/aero/browser/appmenu-dropmarker.png
|
skin/classic/aero/browser/appmenu-dropmarker.png
|
||||||
skin/classic/aero/browser/appmenu-icons.png
|
skin/classic/aero/browser/appmenu-icons.png
|
||||||
|
|||||||
@@ -25,6 +25,7 @@
|
|||||||
#include "mozilla/TimeStamp.h"
|
#include "mozilla/TimeStamp.h"
|
||||||
#include "nsContentListDeclarations.h"
|
#include "nsContentListDeclarations.h"
|
||||||
#include "nsMathUtils.h"
|
#include "nsMathUtils.h"
|
||||||
|
#include "Units.h"
|
||||||
|
|
||||||
class imgICache;
|
class imgICache;
|
||||||
class imgIContainer;
|
class imgIContainer;
|
||||||
@@ -1508,8 +1509,7 @@ public:
|
|||||||
* will return viewport information that specifies default information.
|
* will return viewport information that specifies default information.
|
||||||
*/
|
*/
|
||||||
static nsViewportInfo GetViewportInfo(nsIDocument* aDocument,
|
static nsViewportInfo GetViewportInfo(nsIDocument* aDocument,
|
||||||
uint32_t aDisplayWidth,
|
const mozilla::ScreenIntSize& aDisplaySize);
|
||||||
uint32_t aDisplayHeight);
|
|
||||||
|
|
||||||
// Call EnterMicroTask when you're entering JS execution.
|
// Call EnterMicroTask when you're entering JS execution.
|
||||||
// Usually the best way to do this is to use nsAutoMicroTask.
|
// Usually the best way to do this is to use nsAutoMicroTask.
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
#include "nsPropertyTable.h" // for member
|
#include "nsPropertyTable.h" // for member
|
||||||
#include "nsTHashtable.h" // for member
|
#include "nsTHashtable.h" // for member
|
||||||
#include "mozilla/dom/DocumentBinding.h"
|
#include "mozilla/dom/DocumentBinding.h"
|
||||||
|
#include "Units.h"
|
||||||
|
|
||||||
class imgIRequest;
|
class imgIRequest;
|
||||||
class nsAString;
|
class nsAString;
|
||||||
@@ -622,8 +623,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
Element* GetRootElement() const;
|
Element* GetRootElement() const;
|
||||||
|
|
||||||
virtual nsViewportInfo GetViewportInfo(uint32_t aDisplayWidth,
|
virtual nsViewportInfo GetViewportInfo(const mozilla::ScreenIntSize& aDisplaySize) = 0;
|
||||||
uint32_t aDisplayHeight) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True iff this doc will ignore manual character encoding overrides.
|
* True iff this doc will ignore manual character encoding overrides.
|
||||||
|
|||||||
@@ -7,16 +7,15 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "nscore.h"
|
#include "nscore.h"
|
||||||
|
#include "Units.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default values for the nsViewportInfo class.
|
* Default values for the nsViewportInfo class.
|
||||||
*/
|
*/
|
||||||
static const double kViewportMinScale = 0.0;
|
static const mozilla::LayoutDeviceToScreenScale kViewportMinScale(0.0f);
|
||||||
static const double kViewportMaxScale = 10.0;
|
static const mozilla::LayoutDeviceToScreenScale kViewportMaxScale(10.0f);
|
||||||
static const uint32_t kViewportMinWidth = 200;
|
static const mozilla::CSSIntSize kViewportMinSize(200, 223);
|
||||||
static const uint32_t kViewportMaxWidth = 10000;
|
static const mozilla::CSSIntSize kViewportMaxSize(10000, 10000);
|
||||||
static const uint32_t kViewportMinHeight = 223;
|
|
||||||
static const uint32_t kViewportMaxHeight = 10000;
|
|
||||||
static const int32_t kViewportDefaultScreenWidth = 980;
|
static const int32_t kViewportDefaultScreenWidth = 980;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,43 +25,40 @@ static const int32_t kViewportDefaultScreenWidth = 980;
|
|||||||
class MOZ_STACK_CLASS nsViewportInfo
|
class MOZ_STACK_CLASS nsViewportInfo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
nsViewportInfo(uint32_t aDisplayWidth, uint32_t aDisplayHeight) :
|
nsViewportInfo(const mozilla::ScreenIntSize& aDisplaySize) :
|
||||||
mDefaultZoom(1.0),
|
mDefaultZoom(1.0),
|
||||||
mMinZoom(kViewportMinScale),
|
|
||||||
mMaxZoom(kViewportMaxScale),
|
|
||||||
mWidth(aDisplayWidth),
|
|
||||||
mHeight(aDisplayHeight),
|
|
||||||
mAutoSize(true),
|
mAutoSize(true),
|
||||||
mAllowZoom(true)
|
mAllowZoom(true)
|
||||||
{
|
{
|
||||||
|
mSize = mozilla::gfx::RoundedToInt(mozilla::ScreenSize(aDisplaySize) / mDefaultZoom);
|
||||||
|
mozilla::CSSToLayoutDeviceScale pixelRatio(1.0f);
|
||||||
|
mMinZoom = pixelRatio * kViewportMinScale;
|
||||||
|
mMaxZoom = pixelRatio * kViewportMaxScale;
|
||||||
ConstrainViewportValues();
|
ConstrainViewportValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
nsViewportInfo(double aDefaultZoom,
|
nsViewportInfo(const mozilla::CSSToScreenScale& aDefaultZoom,
|
||||||
double aMinZoom,
|
const mozilla::CSSToScreenScale& aMinZoom,
|
||||||
double aMaxZoom,
|
const mozilla::CSSToScreenScale& aMaxZoom,
|
||||||
uint32_t aWidth,
|
const mozilla::CSSIntSize& aSize,
|
||||||
uint32_t aHeight,
|
|
||||||
bool aAutoSize,
|
bool aAutoSize,
|
||||||
bool aAllowZoom) :
|
bool aAllowZoom) :
|
||||||
mDefaultZoom(aDefaultZoom),
|
mDefaultZoom(aDefaultZoom),
|
||||||
mMinZoom(aMinZoom),
|
mMinZoom(aMinZoom),
|
||||||
mMaxZoom(aMaxZoom),
|
mMaxZoom(aMaxZoom),
|
||||||
mWidth(aWidth),
|
mSize(aSize),
|
||||||
mHeight(aHeight),
|
|
||||||
mAutoSize(aAutoSize),
|
mAutoSize(aAutoSize),
|
||||||
mAllowZoom(aAllowZoom)
|
mAllowZoom(aAllowZoom)
|
||||||
{
|
{
|
||||||
ConstrainViewportValues();
|
ConstrainViewportValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
double GetDefaultZoom() { return mDefaultZoom; }
|
mozilla::CSSToScreenScale GetDefaultZoom() { return mDefaultZoom; }
|
||||||
void SetDefaultZoom(const double aDefaultZoom);
|
void SetDefaultZoom(const mozilla::CSSToScreenScale& aDefaultZoom);
|
||||||
double GetMinZoom() { return mMinZoom; }
|
mozilla::CSSToScreenScale GetMinZoom() { return mMinZoom; }
|
||||||
double GetMaxZoom() { return mMaxZoom; }
|
mozilla::CSSToScreenScale GetMaxZoom() { return mMaxZoom; }
|
||||||
|
|
||||||
uint32_t GetWidth() { return mWidth; }
|
mozilla::CSSIntSize GetSize() { return mSize; }
|
||||||
uint32_t GetHeight() { return mHeight; }
|
|
||||||
|
|
||||||
bool IsAutoSizeEnabled() { return mAutoSize; }
|
bool IsAutoSizeEnabled() { return mAutoSize; }
|
||||||
bool IsZoomAllowed() { return mAllowZoom; }
|
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'
|
// Default zoom indicates the level at which the display is 'zoomed in'
|
||||||
// initially for the user, upon loading of the page.
|
// initially for the user, upon loading of the page.
|
||||||
double mDefaultZoom;
|
mozilla::CSSToScreenScale mDefaultZoom;
|
||||||
|
|
||||||
// The minimum zoom level permitted by the page.
|
// The minimum zoom level permitted by the page.
|
||||||
double mMinZoom;
|
mozilla::CSSToScreenScale mMinZoom;
|
||||||
|
|
||||||
// The maximum zoom level permitted by the page.
|
// 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,
|
// The size of the viewport, specified by the <meta name="viewport"> tag.
|
||||||
// in CSS pixels.
|
mozilla::CSSIntSize mSize;
|
||||||
uint32_t mWidth;
|
|
||||||
|
|
||||||
// The height of the viewport, specified by the <meta name="viewport"> tag,
|
|
||||||
// in CSS pixels.
|
|
||||||
uint32_t mHeight;
|
|
||||||
|
|
||||||
// Whether or not we should automatically size the viewport to the device's
|
// 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
|
// width. This is true if the document has been optimized for mobile, and
|
||||||
|
|||||||
@@ -4875,10 +4875,9 @@ static void ProcessViewportToken(nsIDocument *aDocument,
|
|||||||
/* static */
|
/* static */
|
||||||
nsViewportInfo
|
nsViewportInfo
|
||||||
nsContentUtils::GetViewportInfo(nsIDocument *aDocument,
|
nsContentUtils::GetViewportInfo(nsIDocument *aDocument,
|
||||||
uint32_t aDisplayWidth,
|
const ScreenIntSize& aDisplaySize)
|
||||||
uint32_t aDisplayHeight)
|
|
||||||
{
|
{
|
||||||
return aDocument->GetViewportInfo(aDisplayWidth, aDisplayHeight);
|
return aDocument->GetViewportInfo(aDisplaySize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* static */
|
/* static */
|
||||||
|
|||||||
@@ -6782,12 +6782,11 @@ nsIDocument::AdoptNode(nsINode& aAdoptedNode, ErrorResult& rv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
nsViewportInfo
|
nsViewportInfo
|
||||||
nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
nsDocument::GetViewportInfo(const ScreenIntSize& aDisplaySize)
|
||||||
uint32_t aDisplayHeight)
|
|
||||||
{
|
{
|
||||||
switch (mViewportType) {
|
switch (mViewportType) {
|
||||||
case DisplayWidthHeight:
|
case DisplayWidthHeight:
|
||||||
return nsViewportInfo(aDisplayWidth, aDisplayHeight);
|
return nsViewportInfo(aDisplaySize);
|
||||||
case Unknown:
|
case Unknown:
|
||||||
{
|
{
|
||||||
nsAutoString viewport;
|
nsAutoString viewport;
|
||||||
@@ -6807,8 +6806,7 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
|||||||
{
|
{
|
||||||
// We're making an assumption that the docType can't change here
|
// We're making an assumption that the docType can't change here
|
||||||
mViewportType = DisplayWidthHeight;
|
mViewportType = DisplayWidthHeight;
|
||||||
nsViewportInfo ret(aDisplayWidth, aDisplayHeight);
|
return nsViewportInfo(aDisplaySize);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6817,8 +6815,7 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
|||||||
GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
|
GetHeaderData(nsGkAtoms::handheldFriendly, handheldFriendly);
|
||||||
if (handheldFriendly.EqualsLiteral("true")) {
|
if (handheldFriendly.EqualsLiteral("true")) {
|
||||||
mViewportType = DisplayWidthHeight;
|
mViewportType = DisplayWidthHeight;
|
||||||
nsViewportInfo ret(aDisplayWidth, aDisplayHeight);
|
return nsViewportInfo(aDisplaySize);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6826,14 +6823,14 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
|||||||
GetHeaderData(nsGkAtoms::viewport_minimum_scale, minScaleStr);
|
GetHeaderData(nsGkAtoms::viewport_minimum_scale, minScaleStr);
|
||||||
|
|
||||||
nsresult errorCode;
|
nsresult errorCode;
|
||||||
mScaleMinFloat = minScaleStr.ToFloat(&errorCode);
|
mScaleMinFloat = LayoutDeviceToScreenScale(minScaleStr.ToFloat(&errorCode));
|
||||||
|
|
||||||
if (NS_FAILED(errorCode)) {
|
if (NS_FAILED(errorCode)) {
|
||||||
mScaleMinFloat = kViewportMinScale;
|
mScaleMinFloat = kViewportMinScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
mScaleMinFloat = std::min((double)mScaleMinFloat, kViewportMaxScale);
|
mScaleMinFloat = mozilla::clamped(
|
||||||
mScaleMinFloat = std::max((double)mScaleMinFloat, kViewportMinScale);
|
mScaleMinFloat, kViewportMinScale, kViewportMaxScale);
|
||||||
|
|
||||||
nsAutoString maxScaleStr;
|
nsAutoString maxScaleStr;
|
||||||
GetHeaderData(nsGkAtoms::viewport_maximum_scale, 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,
|
// We define a special error code variable for the scale and max scale,
|
||||||
// because they are used later (see the width calculations).
|
// because they are used later (see the width calculations).
|
||||||
nsresult scaleMaxErrorCode;
|
nsresult scaleMaxErrorCode;
|
||||||
mScaleMaxFloat = maxScaleStr.ToFloat(&scaleMaxErrorCode);
|
mScaleMaxFloat = LayoutDeviceToScreenScale(maxScaleStr.ToFloat(&scaleMaxErrorCode));
|
||||||
|
|
||||||
if (NS_FAILED(scaleMaxErrorCode)) {
|
if (NS_FAILED(scaleMaxErrorCode)) {
|
||||||
mScaleMaxFloat = kViewportMaxScale;
|
mScaleMaxFloat = kViewportMaxScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
mScaleMaxFloat = std::min((double)mScaleMaxFloat, kViewportMaxScale);
|
mScaleMaxFloat = mozilla::clamped(
|
||||||
mScaleMaxFloat = std::max((double)mScaleMaxFloat, kViewportMinScale);
|
mScaleMaxFloat, kViewportMinScale, kViewportMaxScale);
|
||||||
|
|
||||||
nsAutoString scaleStr;
|
nsAutoString scaleStr;
|
||||||
GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
|
GetHeaderData(nsGkAtoms::viewport_initial_scale, scaleStr);
|
||||||
|
|
||||||
nsresult scaleErrorCode;
|
nsresult scaleErrorCode;
|
||||||
mScaleFloat = scaleStr.ToFloat(&scaleErrorCode);
|
mScaleFloat = LayoutDeviceToScreenScale(scaleStr.ToFloat(&scaleErrorCode));
|
||||||
|
|
||||||
nsAutoString widthStr, heightStr;
|
nsAutoString widthStr, heightStr;
|
||||||
|
|
||||||
@@ -6869,20 +6866,19 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
|||||||
|
|
||||||
if (widthStr.IsEmpty() &&
|
if (widthStr.IsEmpty() &&
|
||||||
(heightStr.EqualsLiteral("device-height") ||
|
(heightStr.EqualsLiteral("device-height") ||
|
||||||
(mScaleFloat /* not adjusted for pixel ratio */ == 1.0)))
|
(mScaleFloat.scale == 1.0)))
|
||||||
{
|
{
|
||||||
mAutoSize = true;
|
mAutoSize = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsresult widthErrorCode, heightErrorCode;
|
nsresult widthErrorCode, heightErrorCode;
|
||||||
mViewportWidth = widthStr.ToInteger(&widthErrorCode);
|
mViewportSize.width = widthStr.ToInteger(&widthErrorCode);
|
||||||
mViewportHeight = heightStr.ToInteger(&heightErrorCode);
|
mViewportSize.height = heightStr.ToInteger(&heightErrorCode);
|
||||||
|
|
||||||
// If width or height has not been set to a valid number by this point,
|
// If width or height has not been set to a valid number by this point,
|
||||||
// fall back to a default value.
|
// fall back to a default value.
|
||||||
mValidWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && mViewportWidth > 0);
|
mValidWidth = (!widthStr.IsEmpty() && NS_SUCCEEDED(widthErrorCode) && mViewportSize.width > 0);
|
||||||
mValidHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && mViewportHeight > 0);
|
mValidHeight = (!heightStr.IsEmpty() && NS_SUCCEEDED(heightErrorCode) && mViewportSize.height > 0);
|
||||||
|
|
||||||
|
|
||||||
mAllowZoom = true;
|
mAllowZoom = true;
|
||||||
nsAutoString userScalable;
|
nsAutoString userScalable;
|
||||||
@@ -6903,63 +6899,62 @@ nsDocument::GetViewportInfo(uint32_t aDisplayWidth,
|
|||||||
}
|
}
|
||||||
case Specified:
|
case Specified:
|
||||||
default:
|
default:
|
||||||
uint32_t width = mViewportWidth, height = mViewportHeight;
|
CSSIntSize size = mViewportSize;
|
||||||
|
|
||||||
if (!mValidWidth) {
|
if (!mValidWidth) {
|
||||||
if (mValidHeight && aDisplayWidth > 0 && aDisplayHeight > 0) {
|
if (mValidHeight && !aDisplaySize.IsEmpty()) {
|
||||||
width = uint32_t((height * aDisplayWidth) / aDisplayHeight);
|
size.width = int32_t(size.height * aDisplaySize.width / aDisplaySize.height);
|
||||||
} else {
|
} else {
|
||||||
width = Preferences::GetInt("browser.viewport.desktopWidth",
|
size.width = Preferences::GetInt("browser.viewport.desktopWidth",
|
||||||
kViewportDefaultScreenWidth);
|
kViewportDefaultScreenWidth);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mValidHeight) {
|
if (!mValidHeight) {
|
||||||
if (aDisplayWidth > 0 && aDisplayHeight > 0) {
|
if (!aDisplaySize.IsEmpty()) {
|
||||||
height = uint32_t((width * aDisplayHeight) / aDisplayWidth);
|
size.height = int32_t(size.width * aDisplaySize.height / aDisplaySize.width);
|
||||||
} else {
|
} else {
|
||||||
height = width;
|
size.height = size.width;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Now convert the scale into device pixels per CSS pixel.
|
// Now convert the scale into device pixels per CSS pixel.
|
||||||
nsIWidget *widget = nsContentUtils::WidgetForDocument(this);
|
nsIWidget *widget = nsContentUtils::WidgetForDocument(this);
|
||||||
double pixelRatio = widget ? widget->GetDefaultScale() : 1.0;
|
CSSToLayoutDeviceScale pixelRatio(widget ? widget->GetDefaultScale() : 1.0f);
|
||||||
float scaleFloat = mScaleFloat * pixelRatio;
|
CSSToScreenScale scaleFloat = mScaleFloat * pixelRatio;
|
||||||
float scaleMinFloat= mScaleMinFloat * pixelRatio;
|
CSSToScreenScale scaleMinFloat = mScaleMinFloat * pixelRatio;
|
||||||
float scaleMaxFloat = mScaleMaxFloat * pixelRatio;
|
CSSToScreenScale scaleMaxFloat = mScaleMaxFloat * pixelRatio;
|
||||||
|
|
||||||
if (mAutoSize) {
|
if (mAutoSize) {
|
||||||
// aDisplayWidth and aDisplayHeight are in device pixels; convert them to
|
// aDisplaySize is in screen pixels; convert them to CSS pixels for the viewport size.
|
||||||
// CSS pixels for the viewport size.
|
CSSToScreenScale defaultPixelScale = pixelRatio * LayoutDeviceToScreenScale(1.0f);
|
||||||
width = aDisplayWidth / pixelRatio;
|
size = mozilla::gfx::RoundedToInt(ScreenSize(aDisplaySize) / defaultPixelScale);
|
||||||
height = aDisplayHeight / pixelRatio;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
width = std::min(width, kViewportMaxWidth);
|
size.width = clamped(size.width, kViewportMinSize.width, kViewportMaxSize.width);
|
||||||
width = std::max(width, kViewportMinWidth);
|
|
||||||
|
|
||||||
// Also recalculate the default zoom, if it wasn't specified in the metadata,
|
// Also recalculate the default zoom, if it wasn't specified in the metadata,
|
||||||
// and the width is specified.
|
// and the width is specified.
|
||||||
if (mScaleStrEmpty && !mWidthStrEmpty) {
|
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);
|
size.height = clamped(size.height, kViewportMinSize.height, kViewportMaxSize.height);
|
||||||
height = std::max(height, kViewportMinHeight);
|
|
||||||
|
|
||||||
// We need to perform a conversion, but only if the initial or maximum
|
// We need to perform a conversion, but only if the initial or maximum
|
||||||
// scale were set explicitly by the user.
|
// scale were set explicitly by the user.
|
||||||
if (mValidScaleFloat) {
|
if (mValidScaleFloat) {
|
||||||
width = std::max(width, (uint32_t)(aDisplayWidth / scaleFloat));
|
CSSIntSize displaySize = RoundedToInt(ScreenSize(aDisplaySize) / scaleFloat);
|
||||||
height = std::max(height, (uint32_t)(aDisplayHeight / scaleFloat));
|
size.width = std::max(size.width, displaySize.width);
|
||||||
|
size.height = std::max(size.height, displaySize.height);
|
||||||
} else if (mValidMaxScale) {
|
} else if (mValidMaxScale) {
|
||||||
width = std::max(width, (uint32_t)(aDisplayWidth / scaleMaxFloat));
|
CSSIntSize displaySize = RoundedToInt(ScreenSize(aDisplaySize) / scaleMaxFloat);
|
||||||
height = std::max(height, (uint32_t)(aDisplayHeight / scaleMaxFloat));
|
size.width = std::max(size.width, displaySize.width);
|
||||||
|
size.height = std::max(size.height, displaySize.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsViewportInfo ret(scaleFloat, scaleMinFloat, scaleMaxFloat, width, height,
|
return nsViewportInfo(scaleFloat, scaleMinFloat, scaleMaxFloat, size,
|
||||||
mAutoSize, mAllowZoom);
|
mAutoSize, mAllowZoom);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -753,9 +753,7 @@ public:
|
|||||||
nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
|
nsRadioGroupStruct* GetRadioGroup(const nsAString& aName) const;
|
||||||
nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
|
nsRadioGroupStruct* GetOrCreateRadioGroup(const nsAString& aName);
|
||||||
|
|
||||||
virtual nsViewportInfo GetViewportInfo(uint32_t aDisplayWidth,
|
virtual nsViewportInfo GetViewportInfo(const mozilla::ScreenIntSize& aDisplaySize) MOZ_OVERRIDE;
|
||||||
uint32_t aDisplayHeight) MOZ_OVERRIDE;
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
nsRadioGroupStruct* GetRadioGroupInternal(const nsAString& aName) const;
|
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
|
// These member variables cache information about the viewport so we don't have to
|
||||||
// recalculate it each time.
|
// recalculate it each time.
|
||||||
bool mValidWidth, mValidHeight;
|
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;
|
bool mAutoSize, mAllowZoom, mValidScaleFloat, mValidMaxScale, mScaleStrEmpty, mWidthStrEmpty;
|
||||||
uint32_t mViewportWidth, mViewportHeight;
|
mozilla::CSSIntSize mViewportSize;
|
||||||
|
|
||||||
nsrefcnt mStackRefCnt;
|
nsrefcnt mStackRefCnt;
|
||||||
bool mNeedsReleaseAfterStackRefCntRelease;
|
bool mNeedsReleaseAfterStackRefCntRelease;
|
||||||
|
|||||||
@@ -638,6 +638,7 @@ GK_ATOM(onalerting, "onalerting")
|
|||||||
GK_ATOM(onanimationend, "onanimationend")
|
GK_ATOM(onanimationend, "onanimationend")
|
||||||
GK_ATOM(onanimationiteration, "onanimationiteration")
|
GK_ATOM(onanimationiteration, "onanimationiteration")
|
||||||
GK_ATOM(onanimationstart, "onanimationstart")
|
GK_ATOM(onanimationstart, "onanimationstart")
|
||||||
|
GK_ATOM(onantennaavailablechange, "onantennaavailablechange")
|
||||||
GK_ATOM(onAppCommand, "onAppCommand")
|
GK_ATOM(onAppCommand, "onAppCommand")
|
||||||
GK_ATOM(onaudioprocess, "onaudioprocess")
|
GK_ATOM(onaudioprocess, "onaudioprocess")
|
||||||
GK_ATOM(onbeforecopy, "onbeforecopy")
|
GK_ATOM(onbeforecopy, "onbeforecopy")
|
||||||
@@ -709,6 +710,7 @@ GK_ATOM(onemergencycbmodechange, "onemergencycbmodechange")
|
|||||||
GK_ATOM(onerror, "onerror")
|
GK_ATOM(onerror, "onerror")
|
||||||
GK_ATOM(onfailed, "onfailed")
|
GK_ATOM(onfailed, "onfailed")
|
||||||
GK_ATOM(onfocus, "onfocus")
|
GK_ATOM(onfocus, "onfocus")
|
||||||
|
GK_ATOM(onfrequencychange, "onfrequencychange")
|
||||||
GK_ATOM(onget, "onget")
|
GK_ATOM(onget, "onget")
|
||||||
GK_ATOM(ongroupchange, "ongroupchange")
|
GK_ATOM(ongroupchange, "ongroupchange")
|
||||||
GK_ATOM(onhashchange, "onhashchange")
|
GK_ATOM(onhashchange, "onhashchange")
|
||||||
@@ -771,6 +773,7 @@ GK_ATOM(onremoteheld, "onremoteheld")
|
|||||||
GK_ATOM(onremoteresumed, "onremoteresumed")
|
GK_ATOM(onremoteresumed, "onremoteresumed")
|
||||||
GK_ATOM(onretrieving, "onretrieving")
|
GK_ATOM(onretrieving, "onretrieving")
|
||||||
GK_ATOM(onRequest, "onRequest")
|
GK_ATOM(onRequest, "onRequest")
|
||||||
|
GK_ATOM(onrequestmediaplaystatus, "onrequestmediaplaystatus")
|
||||||
GK_ATOM(onreset, "onreset")
|
GK_ATOM(onreset, "onreset")
|
||||||
GK_ATOM(onresuming, "onresuming")
|
GK_ATOM(onresuming, "onresuming")
|
||||||
GK_ATOM(onMozBeforeResize, "onMozBeforeResize")
|
GK_ATOM(onMozBeforeResize, "onMozBeforeResize")
|
||||||
@@ -785,8 +788,6 @@ GK_ATOM(onshow, "onshow")
|
|||||||
GK_ATOM(onstatechange, "onstatechange")
|
GK_ATOM(onstatechange, "onstatechange")
|
||||||
GK_ATOM(onstatuschanged, "onstatuschanged")
|
GK_ATOM(onstatuschanged, "onstatuschanged")
|
||||||
GK_ATOM(onstkcommand, "onstkcommand")
|
GK_ATOM(onstkcommand, "onstkcommand")
|
||||||
GK_ATOM(onantennastatechange, "onantennastatechange")
|
|
||||||
GK_ATOM(onseekcomplete, "onseekcomplete")
|
|
||||||
GK_ATOM(onstksessionend, "onstksessionend")
|
GK_ATOM(onstksessionend, "onstksessionend")
|
||||||
GK_ATOM(onsubmit, "onsubmit")
|
GK_ATOM(onsubmit, "onsubmit")
|
||||||
GK_ATOM(onsuccess, "onsuccess")
|
GK_ATOM(onsuccess, "onsuccess")
|
||||||
|
|||||||
@@ -6,10 +6,12 @@
|
|||||||
#include "mozilla/Assertions.h"
|
#include "mozilla/Assertions.h"
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
using namespace mozilla;
|
||||||
|
|
||||||
void
|
void
|
||||||
nsViewportInfo::SetDefaultZoom(const double aDefaultZoom)
|
nsViewportInfo::SetDefaultZoom(const CSSToScreenScale& aDefaultZoom)
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(aDefaultZoom >= 0.0f);
|
MOZ_ASSERT(aDefaultZoom.scale >= 0.0f);
|
||||||
mDefaultZoom = aDefaultZoom;
|
mDefaultZoom = aDefaultZoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -20,6 +22,6 @@ nsViewportInfo::ConstrainViewportValues()
|
|||||||
// dev.w3.org/csswg/css-device-adapt section 6.2
|
// dev.w3.org/csswg/css-device-adapt section 6.2
|
||||||
mMaxZoom = std::max(mMinZoom, mMaxZoom);
|
mMaxZoom = std::max(mMinZoom, mMaxZoom);
|
||||||
|
|
||||||
mDefaultZoom = std::min(mDefaultZoom, mMaxZoom);
|
mDefaultZoom = mDefaultZoom < mMaxZoom ? mDefaultZoom : mMaxZoom;
|
||||||
mDefaultZoom = std::max(mDefaultZoom, mMinZoom);
|
mDefaultZoom = mDefaultZoom > mMinZoom ? mDefaultZoom : mMinZoom;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3962,7 +3962,7 @@ bool
|
|||||||
nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
|
nsDocShell::IsPrintingOrPP(bool aDisplayErrorDialog)
|
||||||
{
|
{
|
||||||
if (mIsPrintingOrPP && aDisplayErrorDialog) {
|
if (mIsPrintingOrPP && aDisplayErrorDialog) {
|
||||||
DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr);
|
DisplayLoadError(NS_ERROR_DOCUMENT_IS_PRINTMODE, nullptr, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mIsPrintingOrPP;
|
return mIsPrintingOrPP;
|
||||||
@@ -4118,7 +4118,7 @@ nsDocShell::LoadURI(const PRUnichar * aURI,
|
|||||||
// what happens
|
// what happens
|
||||||
|
|
||||||
if (NS_ERROR_MALFORMED_URI == rv) {
|
if (NS_ERROR_MALFORMED_URI == rv) {
|
||||||
DisplayLoadError(rv, uri, aURI);
|
DisplayLoadError(rv, uri, aURI, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NS_FAILED(rv) || !uri)
|
if (NS_FAILED(rv) || !uri)
|
||||||
@@ -4333,6 +4333,15 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
|||||||
bucketId);
|
bucketId);
|
||||||
|
|
||||||
cssClass.AssignLiteral("blacklist");
|
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 {
|
else {
|
||||||
// Errors requiring simple formatting
|
// Errors requiring simple formatting
|
||||||
|
|||||||
@@ -509,9 +509,6 @@ protected:
|
|||||||
nsresult EnsureTransferableHookData();
|
nsresult EnsureTransferableHookData();
|
||||||
NS_IMETHOD EnsureFind();
|
NS_IMETHOD EnsureFind();
|
||||||
nsresult RefreshURIFromQueue();
|
nsresult RefreshURIFromQueue();
|
||||||
NS_IMETHOD DisplayLoadError(nsresult aError, nsIURI *aURI,
|
|
||||||
const PRUnichar *aURL,
|
|
||||||
nsIChannel* aFailedChannel = nullptr);
|
|
||||||
NS_IMETHOD LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
|
NS_IMETHOD LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
|
||||||
const char *aErrorPage,
|
const char *aErrorPage,
|
||||||
const PRUnichar *aErrorType,
|
const PRUnichar *aErrorType,
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ interface nsIVariant;
|
|||||||
interface nsIPrivacyTransitionObserver;
|
interface nsIPrivacyTransitionObserver;
|
||||||
interface nsIReflowObserver;
|
interface nsIReflowObserver;
|
||||||
|
|
||||||
[scriptable, builtinclass, uuid(4bb2261b-4c13-44a4-ace3-fc2eec17cc34)]
|
[scriptable, builtinclass, uuid(62f1b40d-1d15-4640-95dc-20caae775bd1)]
|
||||||
interface nsIDocShell : nsIDocShellTreeItem
|
interface nsIDocShell : nsIDocShellTreeItem
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@@ -411,6 +411,22 @@ interface nsIDocShell : nsIDocShellTreeItem
|
|||||||
/* attribute to access whether error pages are enabled */
|
/* attribute to access whether error pages are enabled */
|
||||||
attribute boolean useErrorPages;
|
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
|
* Keeps track of the previous SHTransaction index and the current
|
||||||
* SHTransaction index at the time that the doc shell begins to load.
|
* SHTransaction index at the time that the doc shell begins to load.
|
||||||
|
|||||||
@@ -65,6 +65,10 @@
|
|||||||
#include "AudioChannelManager.h"
|
#include "AudioChannelManager.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef MOZ_B2G_FM
|
||||||
|
#include "mozilla/dom/FMRadio.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "nsIDOMGlobalPropertyInitializer.h"
|
#include "nsIDOMGlobalPropertyInitializer.h"
|
||||||
#include "nsJSUtils.h"
|
#include "nsJSUtils.h"
|
||||||
|
|
||||||
@@ -195,6 +199,13 @@ Navigator::Invalidate()
|
|||||||
mBatteryManager = nullptr;
|
mBatteryManager = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MOZ_B2G_FM
|
||||||
|
if (mFMRadio) {
|
||||||
|
mFMRadio->Shutdown();
|
||||||
|
mFMRadio = nullptr;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (mPowerManager) {
|
if (mPowerManager) {
|
||||||
mPowerManager->Shutdown();
|
mPowerManager->Shutdown();
|
||||||
mPowerManager = nullptr;
|
mPowerManager = nullptr;
|
||||||
@@ -1044,6 +1055,34 @@ Navigator::GetMozNotification(ErrorResult& aRv)
|
|||||||
return mNotification;
|
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*
|
battery::BatteryManager*
|
||||||
Navigator::GetBattery(ErrorResult& aRv)
|
Navigator::GetBattery(ErrorResult& aRv)
|
||||||
{
|
{
|
||||||
@@ -1710,6 +1749,16 @@ Navigator::HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal)
|
|||||||
}
|
}
|
||||||
#endif // MOZ_B2G_BT
|
#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
|
#ifdef MOZ_TIME_MANAGER
|
||||||
/* static */
|
/* static */
|
||||||
bool
|
bool
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ namespace battery {
|
|||||||
class BatteryManager;
|
class BatteryManager;
|
||||||
} // namespace battery
|
} // namespace battery
|
||||||
|
|
||||||
|
#ifdef MOZ_B2G_FM
|
||||||
|
class FMRadio;
|
||||||
|
#endif
|
||||||
|
|
||||||
class DesktopNotificationCenter;
|
class DesktopNotificationCenter;
|
||||||
class MobileMessageManager;
|
class MobileMessageManager;
|
||||||
class MozIdleObserver;
|
class MozIdleObserver;
|
||||||
@@ -230,6 +234,9 @@ public:
|
|||||||
#ifdef MOZ_GAMEPAD
|
#ifdef MOZ_GAMEPAD
|
||||||
void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
|
void GetGamepads(nsTArray<nsRefPtr<Gamepad> >& aGamepads, ErrorResult& aRv);
|
||||||
#endif // MOZ_GAMEPAD
|
#endif // MOZ_GAMEPAD
|
||||||
|
#ifdef MOZ_B2G_FM
|
||||||
|
FMRadio* GetMozFMRadio(ErrorResult& aRv);
|
||||||
|
#endif
|
||||||
#ifdef MOZ_B2G_BT
|
#ifdef MOZ_B2G_BT
|
||||||
bluetooth::BluetoothManager* GetMozBluetooth(ErrorResult& aRv);
|
bluetooth::BluetoothManager* GetMozBluetooth(ErrorResult& aRv);
|
||||||
#endif // MOZ_B2G_BT
|
#endif // MOZ_B2G_BT
|
||||||
@@ -283,6 +290,9 @@ public:
|
|||||||
#ifdef MOZ_B2G_BT
|
#ifdef MOZ_B2G_BT
|
||||||
static bool HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal);
|
static bool HasBluetoothSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||||
#endif // MOZ_B2G_BT
|
#endif // MOZ_B2G_BT
|
||||||
|
#ifdef MOZ_B2G_FM
|
||||||
|
static bool HasFMRadioSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||||
|
#endif // MOZ_B2G_FM
|
||||||
#ifdef MOZ_TIME_MANAGER
|
#ifdef MOZ_TIME_MANAGER
|
||||||
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
|
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||||
#endif // MOZ_TIME_MANAGER
|
#endif // MOZ_TIME_MANAGER
|
||||||
@@ -314,6 +324,9 @@ private:
|
|||||||
nsRefPtr<Geolocation> mGeolocation;
|
nsRefPtr<Geolocation> mGeolocation;
|
||||||
nsRefPtr<DesktopNotificationCenter> mNotification;
|
nsRefPtr<DesktopNotificationCenter> mNotification;
|
||||||
nsRefPtr<battery::BatteryManager> mBatteryManager;
|
nsRefPtr<battery::BatteryManager> mBatteryManager;
|
||||||
|
#ifdef MOZ_B2G_FM
|
||||||
|
nsRefPtr<FMRadio> mFMRadio;
|
||||||
|
#endif
|
||||||
nsRefPtr<power::PowerManager> mPowerManager;
|
nsRefPtr<power::PowerManager> mPowerManager;
|
||||||
nsRefPtr<MobileMessageManager> mMobileMessageManager;
|
nsRefPtr<MobileMessageManager> mMobileMessageManager;
|
||||||
#ifdef MOZ_B2G_RIL
|
#ifdef MOZ_B2G_RIL
|
||||||
|
|||||||
@@ -537,11 +537,6 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
|||||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_B2G_FM
|
|
||||||
NS_DEFINE_CLASSINFO_DATA(FMRadio, nsEventTargetSH,
|
|
||||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MOZ_B2G_BT
|
#ifdef MOZ_B2G_BT
|
||||||
NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
|
NS_DEFINE_CLASSINFO_DATA(BluetoothDevice, nsEventTargetSH,
|
||||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||||
@@ -1399,13 +1394,6 @@ nsDOMClassInfo::Init()
|
|||||||
|
|
||||||
#endif
|
#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
|
#ifdef MOZ_B2G_BT
|
||||||
DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
|
DOM_CLASSINFO_MAP_BEGIN(BluetoothDevice, nsIDOMBluetoothDevice)
|
||||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
|
DOM_CLASSINFO_MAP_ENTRY(nsIDOMBluetoothDevice)
|
||||||
|
|||||||
@@ -130,10 +130,6 @@ DOMCI_CLASS(MediaQueryList)
|
|||||||
DOMCI_CLASS(MozIccManager)
|
DOMCI_CLASS(MozIccManager)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_B2G_FM
|
|
||||||
DOMCI_CLASS(FMRadio)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef MOZ_B2G_BT
|
#ifdef MOZ_B2G_BT
|
||||||
DOMCI_CLASS(BluetoothDevice)
|
DOMCI_CLASS(BluetoothDevice)
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -281,13 +281,13 @@ nsDOMWindowUtils::GetViewportInfo(uint32_t aDisplayWidth,
|
|||||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||||
NS_ENSURE_STATE(doc);
|
NS_ENSURE_STATE(doc);
|
||||||
|
|
||||||
nsViewportInfo info = nsContentUtils::GetViewportInfo(doc, aDisplayWidth, aDisplayHeight);
|
nsViewportInfo info = nsContentUtils::GetViewportInfo(doc, ScreenIntSize(aDisplayWidth, aDisplayHeight));
|
||||||
*aDefaultZoom = info.GetDefaultZoom();
|
*aDefaultZoom = info.GetDefaultZoom().scale;
|
||||||
*aAllowZoom = info.IsZoomAllowed();
|
*aAllowZoom = info.IsZoomAllowed();
|
||||||
*aMinZoom = info.GetMinZoom();
|
*aMinZoom = info.GetMinZoom().scale;
|
||||||
*aMaxZoom = info.GetMaxZoom();
|
*aMaxZoom = info.GetMaxZoom().scale;
|
||||||
*aWidth = info.GetWidth();
|
*aWidth = info.GetSize().width;
|
||||||
*aHeight = info.GetHeight();
|
*aHeight = info.GetSize().height;
|
||||||
*aAutoSize = info.IsAutoSizeEnabled();
|
*aAutoSize = info.IsAutoSizeEnabled();
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -345,6 +345,15 @@ BluetoothAdapter::Notify(const BluetoothSignal& aData)
|
|||||||
e->InitBluetoothStatusChangedEvent(aData.name(), false, false,
|
e->InitBluetoothStatusChangedEvent(aData.name(), false, false,
|
||||||
address, status);
|
address, status);
|
||||||
DispatchTrustedEvent(event);
|
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 {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
nsCString warningMsg;
|
nsCString warningMsg;
|
||||||
|
|||||||
@@ -144,6 +144,7 @@ public:
|
|||||||
IMPL_EVENT_HANDLER(a2dpstatuschanged);
|
IMPL_EVENT_HANDLER(a2dpstatuschanged);
|
||||||
IMPL_EVENT_HANDLER(hfpstatuschanged);
|
IMPL_EVENT_HANDLER(hfpstatuschanged);
|
||||||
IMPL_EVENT_HANDLER(pairedstatuschanged);
|
IMPL_EVENT_HANDLER(pairedstatuschanged);
|
||||||
|
IMPL_EVENT_HANDLER(requestmediaplaystatus);
|
||||||
IMPL_EVENT_HANDLER(scostatuschanged);
|
IMPL_EVENT_HANDLER(scostatuschanged);
|
||||||
|
|
||||||
nsPIDOMWindow* GetParentObject() const
|
nsPIDOMWindow* GetParentObject() const
|
||||||
|
|||||||
@@ -62,18 +62,24 @@ extern bool gBluetoothDebugFlag;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* When the connection status of a Bluetooth profile is changed, we'll
|
* 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 A2DP_STATUS_CHANGED_ID "a2dpstatuschanged"
|
||||||
#define HFP_STATUS_CHANGED_ID "hfpstatuschanged"
|
#define HFP_STATUS_CHANGED_ID "hfpstatuschanged"
|
||||||
#define SCO_STATUS_CHANGED_ID "scostatuschanged"
|
#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.
|
* event.
|
||||||
*/
|
*/
|
||||||
#define PAIRED_STATUS_CHANGED_ID "pairedstatuschanged"
|
#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)
|
// Bluetooth address format: xx:xx:xx:xx:xx:xx (or xx_xx_xx_xx_xx_xx)
|
||||||
#define BLUETOOTH_ADDRESS_LENGTH 17
|
#define BLUETOOTH_ADDRESS_LENGTH 17
|
||||||
#define BLUETOOTH_ADDRESS_NONE "00:00:00:00:00:00"
|
#define BLUETOOTH_ADDRESS_NONE "00:00:00:00:00:00"
|
||||||
|
|||||||
@@ -178,11 +178,21 @@ static nsTArray<uint32_t> sAuthorizedServiceClass;
|
|||||||
static nsString sAdapterPath;
|
static nsString sAdapterPath;
|
||||||
static Atomic<int32_t> sIsPairing(0);
|
static Atomic<int32_t> sIsPairing(0);
|
||||||
static int sConnectedDeviceCount = 0;
|
static int sConnectedDeviceCount = 0;
|
||||||
static Monitor sStopBluetoothMonitor("BluetoothService.sStopBluetoothMonitor");
|
static StaticAutoPtr<Monitor> sStopBluetoothMonitor;
|
||||||
|
|
||||||
typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
|
typedef void (*UnpackFunc)(DBusMessage*, DBusError*, BluetoothValue&, nsAString&);
|
||||||
typedef bool (*FilterFunc)(const BluetoothValue&);
|
typedef bool (*FilterFunc)(const BluetoothValue&);
|
||||||
|
|
||||||
|
BluetoothDBusService::BluetoothDBusService()
|
||||||
|
{
|
||||||
|
sStopBluetoothMonitor = new Monitor("BluetoothService.sStopBluetoothMonitor");
|
||||||
|
}
|
||||||
|
|
||||||
|
BluetoothDBusService::~BluetoothDBusService()
|
||||||
|
{
|
||||||
|
sStopBluetoothMonitor = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
GetConnectedDevicesFilter(const BluetoothValue& aValue)
|
GetConnectedDevicesFilter(const BluetoothValue& aValue)
|
||||||
{
|
{
|
||||||
@@ -1298,10 +1308,10 @@ private:
|
|||||||
nsString mAdapterPath;
|
nsString mAdapterPath;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SendPlayStatusTask : public nsRunnable
|
class RequestPlayStatusTask : public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
SendPlayStatusTask()
|
RequestPlayStatusTask()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
}
|
}
|
||||||
@@ -1310,15 +1320,14 @@ public:
|
|||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread());
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
|
|
||||||
BluetoothA2dpManager* a2dp = BluetoothA2dpManager::Get();
|
BluetoothSignal signal(NS_LITERAL_STRING(REQUEST_MEDIA_PLAYSTATUS_ID),
|
||||||
NS_ENSURE_TRUE(a2dp, NS_ERROR_FAILURE);
|
NS_LITERAL_STRING(KEY_ADAPTER),
|
||||||
|
InfallibleTArray<BluetoothNamedValue>());
|
||||||
|
|
||||||
BluetoothService* bs = BluetoothService::Get();
|
BluetoothService* bs = BluetoothService::Get();
|
||||||
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
NS_ENSURE_TRUE(bs, NS_ERROR_FAILURE);
|
||||||
|
bs->DistributeSignal(signal);
|
||||||
|
|
||||||
bs->UpdatePlayStatus(a2dp->GetDuration(),
|
|
||||||
a2dp->GetPosition(),
|
|
||||||
a2dp->GetPlayStatus());
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1494,15 +1503,13 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
|
|||||||
signal.value() = parameters;
|
signal.value() = parameters;
|
||||||
NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
|
NS_DispatchToMainThread(new DistributeBluetoothSignalTask(signal));
|
||||||
} else if (property.name().EqualsLiteral("Connected")) {
|
} else if (property.name().EqualsLiteral("Connected")) {
|
||||||
MonitorAutoLock lock(sStopBluetoothMonitor);
|
MonitorAutoLock lock(*sStopBluetoothMonitor);
|
||||||
|
|
||||||
if (property.value().get_bool()) {
|
if (property.value().get_bool()) {
|
||||||
++sConnectedDeviceCount;
|
++sConnectedDeviceCount;
|
||||||
} else {
|
} else {
|
||||||
MOZ_ASSERT(sConnectedDeviceCount > 0);
|
MOZ_ASSERT(sConnectedDeviceCount > 0);
|
||||||
|
if (--sConnectedDeviceCount == 0) {
|
||||||
--sConnectedDeviceCount;
|
|
||||||
if (sConnectedDeviceCount == 0) {
|
|
||||||
lock.Notify();
|
lock.Notify();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1533,7 +1540,7 @@ EventFilter(DBusConnection* aConn, DBusMessage* aMsg, void* aData)
|
|||||||
sSinkProperties,
|
sSinkProperties,
|
||||||
ArrayLength(sSinkProperties));
|
ArrayLength(sSinkProperties));
|
||||||
} else if (dbus_message_is_signal(aMsg, DBUS_CTL_IFACE, "GetPlayStatus")) {
|
} else if (dbus_message_is_signal(aMsg, DBUS_CTL_IFACE, "GetPlayStatus")) {
|
||||||
NS_DispatchToMainThread(new SendPlayStatusTask());
|
NS_DispatchToMainThread(new RequestPlayStatusTask());
|
||||||
return DBUS_HANDLER_RESULT_HANDLED;
|
return DBUS_HANDLER_RESULT_HANDLED;
|
||||||
} else if (dbus_message_is_signal(aMsg, DBUS_CTL_IFACE, "PropertyChanged")) {
|
} else if (dbus_message_is_signal(aMsg, DBUS_CTL_IFACE, "PropertyChanged")) {
|
||||||
ParsePropertyChange(aMsg,
|
ParsePropertyChange(aMsg,
|
||||||
@@ -1697,7 +1704,7 @@ BluetoothDBusService::StopInternal()
|
|||||||
MOZ_ASSERT(!NS_IsMainThread());
|
MOZ_ASSERT(!NS_IsMainThread());
|
||||||
|
|
||||||
{
|
{
|
||||||
MonitorAutoLock lock(sStopBluetoothMonitor);
|
MonitorAutoLock lock(*sStopBluetoothMonitor);
|
||||||
if (sConnectedDeviceCount > 0) {
|
if (sConnectedDeviceCount > 0) {
|
||||||
lock.Wait(PR_SecondsToInterval(TIMEOUT_FORCE_TO_DISABLE_BT));
|
lock.Wait(PR_SecondsToInterval(TIMEOUT_FORCE_TO_DISABLE_BT));
|
||||||
}
|
}
|
||||||
@@ -2656,55 +2663,6 @@ BluetoothDBusService::IsConnected(const uint16_t aProfileId)
|
|||||||
return profile->IsConnected();
|
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
|
class OnUpdateSdpRecordsRunnable : public nsRunnable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -162,6 +162,9 @@ public:
|
|||||||
SendInputMessage(const nsAString& aDeviceAddresses,
|
SendInputMessage(const nsAString& aDeviceAddresses,
|
||||||
const nsAString& aMessage,
|
const nsAString& aMessage,
|
||||||
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
BluetoothReplyRunnable* aRunnable) MOZ_OVERRIDE;
|
||||||
|
protected:
|
||||||
|
BluetoothDBusService();
|
||||||
|
~BluetoothDBusService();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
@@ -196,7 +199,6 @@ private:
|
|||||||
void UpdateNotification(ControlEventId aEventId, uint64_t aData);
|
void UpdateNotification(ControlEventId aEventId, uint64_t aData);
|
||||||
|
|
||||||
void DisconnectAllAcls(const nsAString& aAdapterPath);
|
void DisconnectAllAcls(const nsAString& aAdapterPath);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
END_BLUETOOTH_NAMESPACE
|
END_BLUETOOTH_NAMESPACE
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ endif
|
|||||||
|
|
||||||
ifdef MOZ_B2G_FM
|
ifdef MOZ_B2G_FM
|
||||||
DOM_SRCDIRS += \
|
DOM_SRCDIRS += \
|
||||||
dom/fm \
|
dom/fmradio \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
endif
|
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,
|
# 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/.
|
# You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
DEPTH = @DEPTH@
|
DEPTH = ../..
|
||||||
topsrcdir = @top_srcdir@
|
topsrcdir = @top_srcdir@
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
VPATH = @srcdir@
|
VPATH = @srcdir@
|
||||||
@@ -13,3 +13,4 @@ include $(topsrcdir)/dom/dom-config.mk
|
|||||||
|
|
||||||
include $(topsrcdir)/config/rules.mk
|
include $(topsrcdir)/config/rules.mk
|
||||||
include $(topsrcdir)/ipc/chromium/chromium-config.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
|
# 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/.
|
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||||
|
|
||||||
XPIDL_SOURCES += [
|
EXPORTS.mozilla.dom += [
|
||||||
'nsIDOMFMRadio.idl',
|
'FMRadioChild.h',
|
||||||
'nsIFMRadio.idl',
|
'FMRadioParent.h',
|
||||||
|
'FMRadioRequestChild.h',
|
||||||
|
'FMRadioRequestParent.h',
|
||||||
]
|
]
|
||||||
|
|
||||||
XPIDL_MODULE = 'dom_fm'
|
|
||||||
|
|
||||||
MODULE = 'dom'
|
|
||||||
LIBRARY_NAME = 'domfm_s'
|
|
||||||
|
|
||||||
CPP_SOURCES += [
|
CPP_SOURCES += [
|
||||||
'FMRadio.cpp',
|
'FMRadioChild.cpp',
|
||||||
'nsFMRadioSettings.cpp',
|
'FMRadioParent.cpp',
|
||||||
|
'FMRadioRequestChild.cpp',
|
||||||
|
'FMRadioRequestParent.cpp',
|
||||||
]
|
]
|
||||||
|
|
||||||
EXTRA_JS_MODULES += [
|
FAIL_ON_WARNINGS = True
|
||||||
'DOMFMRadioParent.jsm',
|
|
||||||
]
|
|
||||||
|
|
||||||
EXTRA_COMPONENTS += [
|
|
||||||
'DOMFMRadio.manifest',
|
|
||||||
'DOMFMRadioChild.js',
|
|
||||||
]
|
|
||||||
|
|
||||||
LIBXUL_LIBRARY = 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/mobilemessage/SmsChild.h"
|
||||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
|
#include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h"
|
||||||
#include "mozilla/dom/bluetooth/PBluetoothChild.h"
|
#include "mozilla/dom/bluetooth/PBluetoothChild.h"
|
||||||
|
#include "mozilla/dom/PFMRadioChild.h"
|
||||||
#include "mozilla/ipc/InputStreamUtils.h"
|
#include "mozilla/ipc/InputStreamUtils.h"
|
||||||
|
|
||||||
#ifdef MOZ_WEBSPEECH
|
#ifdef MOZ_WEBSPEECH
|
||||||
@@ -954,6 +955,30 @@ ContentChild::DeallocPBluetoothChild(PBluetoothChild* aActor)
|
|||||||
#endif
|
#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*
|
PSpeechSynthesisChild*
|
||||||
ContentChild::AllocPSpeechSynthesisChild()
|
ContentChild::AllocPSpeechSynthesisChild()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -158,6 +158,9 @@ public:
|
|||||||
virtual PBluetoothChild* AllocPBluetoothChild();
|
virtual PBluetoothChild* AllocPBluetoothChild();
|
||||||
virtual bool DeallocPBluetoothChild(PBluetoothChild* aActor);
|
virtual bool DeallocPBluetoothChild(PBluetoothChild* aActor);
|
||||||
|
|
||||||
|
virtual PFMRadioChild* AllocPFMRadioChild();
|
||||||
|
virtual bool DeallocPFMRadioChild(PFMRadioChild* aActor);
|
||||||
|
|
||||||
virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild();
|
virtual PSpeechSynthesisChild* AllocPSpeechSynthesisChild();
|
||||||
virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor);
|
virtual bool DeallocPSpeechSynthesisChild(PSpeechSynthesisChild* aActor);
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "mozilla/dom/power/PowerManagerService.h"
|
#include "mozilla/dom/power/PowerManagerService.h"
|
||||||
#include "mozilla/dom/DOMStorageIPC.h"
|
#include "mozilla/dom/DOMStorageIPC.h"
|
||||||
#include "mozilla/dom/bluetooth/PBluetoothParent.h"
|
#include "mozilla/dom/bluetooth/PBluetoothParent.h"
|
||||||
|
#include "mozilla/dom/PFMRadioParent.h"
|
||||||
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
|
#include "mozilla/dom/devicestorage/DeviceStorageRequestParent.h"
|
||||||
#include "SmsParent.h"
|
#include "SmsParent.h"
|
||||||
#include "mozilla/Hal.h"
|
#include "mozilla/Hal.h"
|
||||||
@@ -125,6 +126,11 @@ using namespace mozilla::system;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "JavaScriptParent.h"
|
#include "JavaScriptParent.h"
|
||||||
|
|
||||||
|
#ifdef MOZ_B2G_FM
|
||||||
|
#include "mozilla/dom/FMRadioParent.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "Crypto.h"
|
#include "Crypto.h"
|
||||||
|
|
||||||
#ifdef MOZ_WEBSPEECH
|
#ifdef MOZ_WEBSPEECH
|
||||||
@@ -2291,6 +2297,32 @@ ContentParent::RecvPBluetoothConstructor(PBluetoothParent* aActor)
|
|||||||
#endif
|
#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*
|
PSpeechSynthesisParent*
|
||||||
ContentParent::AllocPSpeechSynthesisParent()
|
ContentParent::AllocPSpeechSynthesisParent()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -328,6 +328,9 @@ private:
|
|||||||
virtual bool DeallocPBluetoothParent(PBluetoothParent* aActor);
|
virtual bool DeallocPBluetoothParent(PBluetoothParent* aActor);
|
||||||
virtual bool RecvPBluetoothConstructor(PBluetoothParent* aActor);
|
virtual bool RecvPBluetoothConstructor(PBluetoothParent* aActor);
|
||||||
|
|
||||||
|
virtual PFMRadioParent* AllocPFMRadioParent();
|
||||||
|
virtual bool DeallocPFMRadioParent(PFMRadioParent* aActor);
|
||||||
|
|
||||||
virtual PSpeechSynthesisParent* AllocPSpeechSynthesisParent();
|
virtual PSpeechSynthesisParent* AllocPSpeechSynthesisParent();
|
||||||
virtual bool DeallocPSpeechSynthesisParent(PSpeechSynthesisParent* aActor);
|
virtual bool DeallocPSpeechSynthesisParent(PSpeechSynthesisParent* aActor);
|
||||||
virtual bool RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor);
|
virtual bool RecvPSpeechSynthesisConstructor(PSpeechSynthesisParent* aActor);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ LOCAL_INCLUDES += \
|
|||||||
-I$(topsrcdir)/hal/sandbox \
|
-I$(topsrcdir)/hal/sandbox \
|
||||||
-I$(topsrcdir)/dom/mobilemessage/src/ipc \
|
-I$(topsrcdir)/dom/mobilemessage/src/ipc \
|
||||||
-I$(topsrcdir)/dom/devicestorage \
|
-I$(topsrcdir)/dom/devicestorage \
|
||||||
|
-I$(topsrcdir)/dom/fmradio/ipc \
|
||||||
-I$(topsrcdir)/widget/xpwidgets \
|
-I$(topsrcdir)/widget/xpwidgets \
|
||||||
-I$(topsrcdir)/dom/bluetooth \
|
-I$(topsrcdir)/dom/bluetooth \
|
||||||
-I$(topsrcdir)/layout/base \
|
-I$(topsrcdir)/layout/base \
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ include protocol PCompositor;
|
|||||||
include protocol PCrashReporter;
|
include protocol PCrashReporter;
|
||||||
include protocol PExternalHelperApp;
|
include protocol PExternalHelperApp;
|
||||||
include protocol PDeviceStorageRequest;
|
include protocol PDeviceStorageRequest;
|
||||||
|
include protocol PFMRadio;
|
||||||
include protocol PHal;
|
include protocol PHal;
|
||||||
include protocol PImageBridge;
|
include protocol PImageBridge;
|
||||||
include protocol PIndexedDB;
|
include protocol PIndexedDB;
|
||||||
@@ -126,6 +127,40 @@ union DeviceStorageParams
|
|||||||
DeviceStorageAvailableParams;
|
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 {
|
union PrefValue {
|
||||||
nsCString;
|
nsCString;
|
||||||
int32_t;
|
int32_t;
|
||||||
@@ -154,6 +189,7 @@ rpc protocol PContent
|
|||||||
manages PCrashReporter;
|
manages PCrashReporter;
|
||||||
manages PDeviceStorageRequest;
|
manages PDeviceStorageRequest;
|
||||||
manages PExternalHelperApp;
|
manages PExternalHelperApp;
|
||||||
|
manages PFMRadio;
|
||||||
manages PHal;
|
manages PHal;
|
||||||
manages PIndexedDB;
|
manages PIndexedDB;
|
||||||
manages PMemoryReportRequest;
|
manages PMemoryReportRequest;
|
||||||
@@ -319,6 +355,8 @@ parent:
|
|||||||
|
|
||||||
PBluetooth();
|
PBluetooth();
|
||||||
|
|
||||||
|
PFMRadio();
|
||||||
|
|
||||||
// Services remoting
|
// Services remoting
|
||||||
|
|
||||||
async StartVisitedQuery(URIParams uri);
|
async StartVisitedQuery(URIParams uri);
|
||||||
|
|||||||
@@ -568,15 +568,14 @@ TabChild::HandlePossibleViewportChange()
|
|||||||
|
|
||||||
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
nsCOMPtr<nsIDOMWindowUtils> utils(GetDOMWindowUtils());
|
||||||
|
|
||||||
nsViewportInfo viewportInfo =
|
nsViewportInfo viewportInfo = nsContentUtils::GetViewportInfo(document, mInnerSize);
|
||||||
nsContentUtils::GetViewportInfo(document, mInnerSize.width, mInnerSize.height);
|
|
||||||
SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(),
|
SendUpdateZoomConstraints(viewportInfo.IsZoomAllowed(),
|
||||||
CSSToScreenScale(viewportInfo.GetMinZoom()),
|
viewportInfo.GetMinZoom(),
|
||||||
CSSToScreenScale(viewportInfo.GetMaxZoom()));
|
viewportInfo.GetMaxZoom());
|
||||||
|
|
||||||
float screenW = mInnerSize.width;
|
float screenW = mInnerSize.width;
|
||||||
float screenH = mInnerSize.height;
|
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
|
// We're not being displayed in any way; don't bother doing anything because
|
||||||
// that will just confuse future adjustments.
|
// that will just confuse future adjustments.
|
||||||
@@ -609,8 +608,6 @@ TabChild::HandlePossibleViewportChange()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float minScale = 1.0f;
|
|
||||||
|
|
||||||
nsCOMPtr<Element> htmlDOMElement = document->GetHtmlElement();
|
nsCOMPtr<Element> htmlDOMElement = document->GetHtmlElement();
|
||||||
HTMLBodyElement* bodyDOMElement = document->GetBodyElement();
|
HTMLBodyElement* bodyDOMElement = document->GetBodyElement();
|
||||||
|
|
||||||
@@ -638,12 +635,11 @@ TabChild::HandlePossibleViewportChange()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
minScale = mInnerSize.width / pageSize.width;
|
CSSToScreenScale minScale(mInnerSize.width / pageSize.width);
|
||||||
minScale = clamped((double)minScale, viewportInfo.GetMinZoom(),
|
minScale = clamped(minScale, viewportInfo.GetMinZoom(), viewportInfo.GetMaxZoom());
|
||||||
viewportInfo.GetMaxZoom());
|
NS_ENSURE_TRUE_VOID(minScale.scale); // (return early rather than divide by 0)
|
||||||
NS_ENSURE_TRUE_VOID(minScale); // (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);
|
SetCSSViewport(viewport);
|
||||||
|
|
||||||
float oldScreenWidth = mLastMetrics.mCompositionBounds.width;
|
float oldScreenWidth = mLastMetrics.mCompositionBounds.width;
|
||||||
@@ -680,14 +676,14 @@ TabChild::HandlePossibleViewportChange()
|
|||||||
// FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
|
// FIXME/bug 799585(?): GetViewportInfo() returns a defaultZoom of
|
||||||
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
// 0.0 to mean "did not calculate a zoom". In that case, we default
|
||||||
// it to the intrinsic scale.
|
// it to the intrinsic scale.
|
||||||
if (viewportInfo.GetDefaultZoom() < 0.01f) {
|
if (viewportInfo.GetDefaultZoom().scale < 0.01f) {
|
||||||
viewportInfo.SetDefaultZoom(metrics.CalculateIntrinsicScale().scale);
|
viewportInfo.SetDefaultZoom(metrics.CalculateIntrinsicScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
double defaultZoom = viewportInfo.GetDefaultZoom();
|
CSSToScreenScale defaultZoom = viewportInfo.GetDefaultZoom();
|
||||||
MOZ_ASSERT(viewportInfo.GetMinZoom() <= defaultZoom &&
|
MOZ_ASSERT(viewportInfo.GetMinZoom() <= defaultZoom &&
|
||||||
defaultZoom <= viewportInfo.GetMaxZoom());
|
defaultZoom <= viewportInfo.GetMaxZoom());
|
||||||
metrics.mZoom = CSSToScreenScale(defaultZoom);
|
metrics.mZoom = defaultZoom;
|
||||||
}
|
}
|
||||||
|
|
||||||
metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
|
metrics.mDisplayPort = AsyncPanZoomController::CalculatePendingDisplayPort(
|
||||||
|
|||||||
@@ -297,12 +297,16 @@ TabParent::ActorDestroy(ActorDestroyReason why)
|
|||||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
|
||||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||||
if (frameLoader) {
|
if (frameLoader) {
|
||||||
|
nsCOMPtr<Element> frameElement(mFrameElement);
|
||||||
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr);
|
ReceiveMessage(CHILD_PROCESS_SHUTDOWN_MESSAGE, false, nullptr, nullptr);
|
||||||
frameLoader->DestroyChild();
|
frameLoader->DestroyChild();
|
||||||
|
|
||||||
if (why == AbnormalShutdown && os) {
|
if (why == AbnormalShutdown && os) {
|
||||||
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader),
|
os->NotifyObservers(NS_ISUPPORTS_CAST(nsIFrameLoader*, frameLoader),
|
||||||
"oop-frameloader-crashed", nullptr);
|
"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.
|
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.
|
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.
|
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',
|
'devicestorage',
|
||||||
'encoding',
|
'encoding',
|
||||||
'file',
|
'file',
|
||||||
|
'fmradio',
|
||||||
'media',
|
'media',
|
||||||
'messages',
|
'messages',
|
||||||
'power',
|
'power',
|
||||||
@@ -86,9 +87,6 @@ if CONFIG['MOZ_B2G_RIL']:
|
|||||||
'voicemail',
|
'voicemail',
|
||||||
]
|
]
|
||||||
|
|
||||||
if CONFIG['MOZ_B2G_FM']:
|
|
||||||
PARALLEL_DIRS += ['fm']
|
|
||||||
|
|
||||||
if CONFIG['MOZ_PAY']:
|
if CONFIG['MOZ_PAY']:
|
||||||
PARALLEL_DIRS += ['payment']
|
PARALLEL_DIRS += ['payment']
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=815105
|
|||||||
var gData = [
|
var gData = [
|
||||||
{
|
{
|
||||||
perm: ["fmradio"],
|
perm: ["fmradio"],
|
||||||
|
needParentPerm: true,
|
||||||
obj: "mozFMRadio",
|
obj: "mozFMRadio",
|
||||||
idl: "nsIDOMFMRadio",
|
webidl: "FMRadio",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -67,6 +67,10 @@ interface BluetoothAdapter : EventTarget {
|
|||||||
[SetterThrows]
|
[SetterThrows]
|
||||||
attribute EventHandler onscostatuschanged;
|
attribute EventHandler onscostatuschanged;
|
||||||
|
|
||||||
|
// Fired when remote devices query current media play status
|
||||||
|
[SetterThrows]
|
||||||
|
attribute EventHandler onrequestmediaplaystatus;
|
||||||
|
|
||||||
[Creator, Throws]
|
[Creator, Throws]
|
||||||
DOMRequest setName(DOMString name);
|
DOMRequest setName(DOMString name);
|
||||||
[Creator, Throws]
|
[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
|
#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
|
#ifdef MOZ_TIME_MANAGER
|
||||||
// nsIDOMMozNavigatorTime
|
// nsIDOMMozNavigatorTime
|
||||||
partial interface Navigator {
|
partial interface Navigator {
|
||||||
|
|||||||
@@ -525,6 +525,10 @@ webidl_files += \
|
|||||||
$(NULL)
|
$(NULL)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef MOZ_B2G_FM
|
||||||
|
webidl_files += FMRadio.webidl
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef ENABLE_TESTS
|
ifdef ENABLE_TESTS
|
||||||
test_webidl_files := \
|
test_webidl_files := \
|
||||||
TestCodeGen.webidl \
|
TestCodeGen.webidl \
|
||||||
|
|||||||
@@ -115,6 +115,12 @@ struct SizeTyped :
|
|||||||
};
|
};
|
||||||
typedef SizeTyped<UnknownUnits> Size;
|
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_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_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
|
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);
|
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
|
#endif
|
||||||
|
|||||||
@@ -9612,9 +9612,9 @@ nsIPresShell::RecomputeFontSizeInflationEnabled()
|
|||||||
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
|
screen->GetRect(&screenLeft, &screenTop, &screenWidth, &screenHeight);
|
||||||
|
|
||||||
nsViewportInfo vInf =
|
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;
|
mFontSizeInflationEnabled = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ endif #}
|
|||||||
|
|
||||||
ifdef MOZ_B2G_FM #{
|
ifdef MOZ_B2G_FM #{
|
||||||
SHARED_LIBRARY_LIBS += \
|
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)
|
$(NULL)
|
||||||
endif #}
|
endif #}
|
||||||
|
|
||||||
@@ -326,7 +327,7 @@ LOCAL_INCLUDES += -I$(topsrcdir)/dom/system/gonk
|
|||||||
endif #}
|
endif #}
|
||||||
|
|
||||||
ifdef MOZ_B2G_FM #{
|
ifdef MOZ_B2G_FM #{
|
||||||
LOCAL_INCLUDES += -I$(topsrcdir)/dom/fm
|
LOCAL_INCLUDES += -I$(topsrcdir)/dom/fmradio
|
||||||
endif #}
|
endif #}
|
||||||
|
|
||||||
ifdef MOZ_B2G_BT #{
|
ifdef MOZ_B2G_BT #{
|
||||||
|
|||||||
@@ -125,11 +125,6 @@ using mozilla::dom::gonk::AudioManager;
|
|||||||
using mozilla::system::nsVolumeService;
|
using mozilla::system::nsVolumeService;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_B2G_FM
|
|
||||||
#include "FMRadio.h"
|
|
||||||
using mozilla::dom::fm::FMRadio;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "AudioChannelAgent.h"
|
#include "AudioChannelAgent.h"
|
||||||
using mozilla::dom::AudioChannelAgent;
|
using mozilla::dom::AudioChannelAgent;
|
||||||
|
|
||||||
@@ -303,10 +298,6 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsSynthVoiceRegistry,
|
|||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AudioManager)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(AudioManager)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef MOZ_B2G_FM
|
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(FMRadio)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(AudioChannelAgent)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(AudioChannelAgent)
|
||||||
|
|
||||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceSensors)
|
NS_GENERIC_FACTORY_CONSTRUCTOR(nsDeviceSensors)
|
||||||
@@ -761,10 +752,6 @@ NS_DEFINE_NAMED_CID(NS_AUDIOMANAGER_CID);
|
|||||||
NS_DEFINE_NAMED_CID(NS_VOLUMESERVICE_CID);
|
NS_DEFINE_NAMED_CID(NS_VOLUMESERVICE_CID);
|
||||||
#endif
|
#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_AUDIOCHANNELAGENT_CID);
|
||||||
|
|
||||||
NS_DEFINE_NAMED_CID(NS_HTMLEDITOR_CID);
|
NS_DEFINE_NAMED_CID(NS_HTMLEDITOR_CID);
|
||||||
@@ -1049,9 +1036,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
|||||||
#ifdef MOZ_WIDGET_GONK
|
#ifdef MOZ_WIDGET_GONK
|
||||||
{ &kNS_AUDIOMANAGER_CID, true, NULL, AudioManagerConstructor },
|
{ &kNS_AUDIOMANAGER_CID, true, NULL, AudioManagerConstructor },
|
||||||
{ &kNS_VOLUMESERVICE_CID, true, NULL, nsVolumeServiceConstructor },
|
{ &kNS_VOLUMESERVICE_CID, true, NULL, nsVolumeServiceConstructor },
|
||||||
#endif
|
|
||||||
#ifdef MOZ_B2G_FM
|
|
||||||
{ &kNS_FMRADIO_CID, true, NULL, FMRadioConstructor },
|
|
||||||
#endif
|
#endif
|
||||||
{ &kNS_AUDIOCHANNELAGENT_CID, true, NULL, AudioChannelAgentConstructor },
|
{ &kNS_AUDIOCHANNELAGENT_CID, true, NULL, AudioChannelAgentConstructor },
|
||||||
{ &kNS_HTMLEDITOR_CID, false, NULL, nsHTMLEditorConstructor },
|
{ &kNS_HTMLEDITOR_CID, false, NULL, nsHTMLEditorConstructor },
|
||||||
@@ -1207,9 +1191,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
|
|||||||
#ifdef MOZ_WIDGET_GONK
|
#ifdef MOZ_WIDGET_GONK
|
||||||
{ NS_AUDIOMANAGER_CONTRACTID, &kNS_AUDIOMANAGER_CID },
|
{ NS_AUDIOMANAGER_CONTRACTID, &kNS_AUDIOMANAGER_CID },
|
||||||
{ NS_VOLUMESERVICE_CONTRACTID, &kNS_VOLUMESERVICE_CID },
|
{ NS_VOLUMESERVICE_CONTRACTID, &kNS_VOLUMESERVICE_CID },
|
||||||
#endif
|
|
||||||
#ifdef MOZ_B2G_FM
|
|
||||||
{ NS_FMRADIO_CONTRACTID, &kNS_FMRADIO_CID },
|
|
||||||
#endif
|
#endif
|
||||||
{ NS_AUDIOCHANNELAGENT_CONTRACTID, &kNS_AUDIOCHANNELAGENT_CID },
|
{ NS_AUDIOCHANNELAGENT_CONTRACTID, &kNS_AUDIOCHANNELAGENT_CID },
|
||||||
{ "@mozilla.org/editor/htmleditor;1", &kNS_HTMLEDITOR_CID },
|
{ "@mozilla.org/editor/htmleditor;1", &kNS_HTMLEDITOR_CID },
|
||||||
|
|||||||
@@ -255,7 +255,7 @@ this.OnRefTestLoad = function OnRefTestLoad(win)
|
|||||||
|
|
||||||
#if BOOTSTRAP
|
#if BOOTSTRAP
|
||||||
#if REFTEST_B2G
|
#if REFTEST_B2G
|
||||||
var doc = gContainingWindow.document.getElementsByTagName("html")[0];
|
var doc = gContainingWindow.document.getElementsByTagName("window")[0];
|
||||||
#else
|
#else
|
||||||
var doc = gContainingWindow.document.getElementById('main-window');
|
var doc = gContainingWindow.document.getElementById('main-window');
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import org.mozilla.gecko.util.Clipboard;
|
|||||||
import org.mozilla.gecko.util.FloatUtils;
|
import org.mozilla.gecko.util.FloatUtils;
|
||||||
import org.mozilla.gecko.util.GamepadUtils;
|
import org.mozilla.gecko.util.GamepadUtils;
|
||||||
import org.mozilla.gecko.util.HardwareUtils;
|
import org.mozilla.gecko.util.HardwareUtils;
|
||||||
|
import org.mozilla.gecko.util.StringUtils;
|
||||||
import org.mozilla.gecko.util.ThreadUtils;
|
import org.mozilla.gecko.util.ThreadUtils;
|
||||||
import org.mozilla.gecko.util.UiAsyncTask;
|
import org.mozilla.gecko.util.UiAsyncTask;
|
||||||
import org.mozilla.gecko.widget.GeckoActionProvider;
|
import org.mozilla.gecko.widget.GeckoActionProvider;
|
||||||
@@ -74,6 +75,7 @@ import android.widget.Toast;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.net.URLEncoder;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
@@ -1422,9 +1424,46 @@ abstract public class BrowserApp extends GeckoApp
|
|||||||
animateHideHomePager();
|
animateHideHomePager();
|
||||||
hideBrowserSearch();
|
hideBrowserSearch();
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(url)) {
|
// Don't do anything if the user entered an empty URL.
|
||||||
Tabs.getInstance().loadUrl(url, Tabs.LOADURL_USER_ENTERED);
|
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() {
|
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) {
|
protected void deleteBookmark(String url) {
|
||||||
try {
|
try {
|
||||||
ContentResolver resolver = getActivity().getContentResolver();
|
ContentResolver resolver = getActivity().getContentResolver();
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
# [testAwesomebarSwipes] # disabled on fig - bug 880060
|
# [testAwesomebarSwipes] # disabled on fig - bug 880060
|
||||||
# [testBookmark] # disabled on fig - bug 880060
|
# [testBookmark] # disabled on fig - bug 880060
|
||||||
# [testBookmarklets] # disabled on fig - bug 880060
|
# [testBookmarklets] # disabled on fig - bug 880060
|
||||||
|
[testBookmarkKeyword]
|
||||||
[testBrowserSearchVisibility]
|
[testBrowserSearchVisibility]
|
||||||
[testJNI]
|
[testJNI]
|
||||||
# [testLoad] # see bug 851861
|
# [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()
|
button.tap()
|
||||||
expected = "button1-touchstart-touchend-mousemove-mousedown-mouseup-click"
|
expected = "button1-touchstart-touchend-mousemove-mousedown-mouseup-click"
|
||||||
self.wait_for_condition(lambda m: m.execute_script("return document.getElementById('button1').innerHTML;") == expected)
|
self.wait_for_condition(lambda m: m.execute_script("return document.getElementById('button1').innerHTML;") == expected)
|
||||||
button = self.marionette.find_element("id", "button2")
|
button.tap(0, 300)
|
||||||
button.tap()
|
|
||||||
expected = "button2-touchstart-touchend-mousemove-mousedown-mouseup-click"
|
expected = "button2-touchstart-touchend-mousemove-mousedown-mouseup-click"
|
||||||
self.wait_for_condition(lambda m: m.execute_script("return document.getElementById('button2').innerHTML;") == expected)
|
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_SCRIPT_API = "chrome://specialpowers/content/specialpowersAPI.js";
|
||||||
const CHILD_LOGGER_SCRIPT = "chrome://specialpowers/content/MozillaLogger.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');
|
let container = homescreen.contentWindow.document.getElementById('test-container');
|
||||||
|
|
||||||
function openWindow(aEvent) {
|
function openWindow(aEvent) {
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ toolbar#nav-bar {
|
|||||||
if options.browserChrome or options.chrome or options.a11y or options.webapprtChrome:
|
if options.browserChrome or options.chrome or options.a11y or options.webapprtChrome:
|
||||||
chrome += """
|
chrome += """
|
||||||
overlay chrome://browser/content/browser.xul chrome://mochikit/content/browser-test-overlay.xul
|
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://navigator/content/navigator.xul chrome://mochikit/content/browser-test-overlay.xul
|
||||||
overlay chrome://webapprt/content/webapp.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
Reference in New Issue
Block a user