diff options
Diffstat (limited to 'b2g/chrome/content')
47 files changed, 0 insertions, 6197 deletions
diff --git a/b2g/chrome/content/ErrorPage.js b/b2g/chrome/content/ErrorPage.js deleted file mode 100644 index d51782466..000000000 --- a/b2g/chrome/content/ErrorPage.js +++ /dev/null @@ -1,73 +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'; - -var Cu = Components.utils; -var Cc = Components.classes; -var Ci = Components.interfaces; - -dump("############ ErrorPage.js\n"); - -var ErrorPageHandler = { - _reload: function() { - docShell.QueryInterface(Ci.nsIWebNavigation).reload(Ci.nsIWebNavigation.LOAD_FLAGS_NONE); - }, - - _certErrorPageEventHandler: function(e) { - let target = e.originalTarget; - let errorDoc = target.ownerDocument; - - // If the event came from an ssl error page, it is one of the "Add - // Exception…" buttons. - if (/^about:certerror\?e=nssBadCert/.test(errorDoc.documentURI)) { - let permanent = errorDoc.getElementById("permanentExceptionButton"); - let temp = errorDoc.getElementById("temporaryExceptionButton"); - if (target == temp || target == permanent) { - sendAsyncMessage("ErrorPage:AddCertException", { - url: errorDoc.location.href, - isPermanent: target == permanent - }); - } - } - }, - - _bindPageEvent: function(target) { - if (!target) { - return; - } - - if (/^about:certerror/.test(target.documentURI)) { - let errorPageEventHandler = this._certErrorPageEventHandler.bind(this); - addEventListener("click", errorPageEventHandler, true, false); - let listener = function() { - removeEventListener("click", errorPageEventHandler, true); - removeEventListener("pagehide", listener, true); - }.bind(this); - - addEventListener("pagehide", listener, true); - } - }, - - domContentLoadedHandler: function(e) { - let target = e.originalTarget; - let targetDocShell = target.defaultView - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation); - if (targetDocShell != docShell) { - return; - } - this._bindPageEvent(target); - }, - - init: function() { - addMessageListener("ErrorPage:ReloadPage", this._reload.bind(this)); - addEventListener('DOMContentLoaded', - this.domContentLoadedHandler.bind(this), - true); - this._bindPageEvent(content.document); - } -}; - -ErrorPageHandler.init(); diff --git a/b2g/chrome/content/aboutCertError.xhtml b/b2g/chrome/content/aboutCertError.xhtml deleted file mode 100644 index 616657e54..000000000 --- a/b2g/chrome/content/aboutCertError.xhtml +++ /dev/null @@ -1,233 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> - -<!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 % certerrorDTD - SYSTEM "chrome://b2g-l10n/locale/aboutCertError.dtd"> - %certerrorDTD; -]> - -<!-- 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"> - <head> - <title>&certerror.pagetitle;</title> - <meta name="viewport" content="width=device-width; user-scalable=false" /> - <link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" /> - <!-- This page currently uses the same favicon as neterror.xhtml. - If the location of the favicon is changed for both pages, the - FAVICON_ERRORPAGE_URL symbol in toolkit/components/places/src/nsFaviconService.h - should be updated. If this page starts using a different favicon - than neterrorm nsFaviconService->SetAndLoadFaviconForPage - should be updated to ignore this one as well. --> - <link rel="icon" type="image/png" id="favicon" sizes="64x64" href="chrome://global/skin/icons/warning-64.png"/> - - <script type="application/javascript"><![CDATA[ - // Error url MUST be formatted like this: - // about:certerror?e=error&u=url&d=desc - - // Note that this file uses document.documentURI to get - // the URL (with the format from above). This is because - // document.location.href gets the current URI off the docshell, - // which is the URL displayed in the location bar, i.e. - // the URI that the user attempted to load. - - function getCSSClass() - { - var url = document.documentURI; - var matches = url.match(/s\=([^&]+)\&/); - // s is optional, if no match just return nothing - if (!matches || matches.length < 2) - return ""; - - // parenthetical match is the second entry - return decodeURIComponent(matches[1]); - } - - function getDescription() - { - var url = document.documentURI; - var desc = url.search(/d\=/); - - // desc == -1 if not found; if so, return an empty string - // instead of what would turn out to be portions of the URI - if (desc == -1) - return ""; - - return decodeURIComponent(url.slice(desc + 2)); - } - - function initPage() - { - // Replace the "#1" string in the intro with the hostname. Trickier - // than it might seem since we want to preserve the <b> tags, but - // not allow for any injection by just using innerHTML. Instead, - // just find the right target text node. - var intro = document.getElementById('introContentP1'); - function replaceWithHost(node) { - if (node.textContent == "#1") - node.textContent = location.host; - else - for(var i = 0; i < node.childNodes.length; i++) - replaceWithHost(node.childNodes[i]); - }; - replaceWithHost(intro); - - if (getCSSClass() == "expertBadCert") { - toggle('technicalContent'); - toggle('expertContent'); - } - - var tech = document.getElementById("technicalContentText"); - if (tech) - tech.textContent = getDescription(); - - addDomainErrorLink(); - } - - /* In the case of SSL error pages about domain mismatch, see if - we can hyperlink the user to the correct site. We don't want - to do this generically since it allows MitM attacks to redirect - users to a site under attacker control, but in certain cases - it is safe (and helpful!) to do so. Bug 402210 - */ - function addDomainErrorLink() { - // Rather than textContent, we need to treat description as HTML - var sd = document.getElementById("technicalContentText"); - if (sd) { - var desc = getDescription(); - - // sanitize description text - see bug 441169 - - // First, find the index of the <a> tag we care about, being careful not to - // use an over-greedy regex - var re = /<a id="cert_domain_link" title="([^"]+)">/; - var result = re.exec(desc); - if(!result) - return; - - // Remove sd's existing children - sd.textContent = ""; - - // Everything up to the link should be text content - sd.appendChild(document.createTextNode(desc.slice(0, result.index))); - - // Now create the link itself - var anchorEl = document.createElement("a"); - anchorEl.setAttribute("id", "cert_domain_link"); - anchorEl.setAttribute("title", result[1]); - anchorEl.appendChild(document.createTextNode(result[1])); - sd.appendChild(anchorEl); - - // Finally, append text for anything after the closing </a> - sd.appendChild(document.createTextNode(desc.slice(desc.indexOf("</a>") + "</a>".length))); - } - - var link = document.getElementById('cert_domain_link'); - if (!link) - return; - - var okHost = link.getAttribute("title"); - var thisHost = document.location.hostname; - var proto = document.location.protocol; - - // If okHost is a wildcard domain ("*.example.com") let's - // use "www" instead. "*.example.com" isn't going to - // get anyone anywhere useful. bug 432491 - okHost = okHost.replace(/^\*\./, "www."); - - /* case #1: - * example.com uses an invalid security certificate. - * - * The certificate is only valid for www.example.com - * - * Make sure to include the "." ahead of thisHost so that - * a MitM attack on paypal.com doesn't hyperlink to "notpaypal.com" - * - * We'd normally just use a RegExp here except that we lack a - * library function to escape them properly (bug 248062), and - * domain names are famous for having '.' characters in them, - * which would allow spurious and possibly hostile matches. - */ - if (endsWith(okHost, "." + thisHost)) - link.href = proto + okHost; - - /* case #2: - * browser.garage.maemo.org uses an invalid security certificate. - * - * The certificate is only valid for garage.maemo.org - */ - if (endsWith(thisHost, "." + okHost)) - link.href = proto + okHost; - - // If we set a link, meaning there's something helpful for - // the user here, expand the section by default - if (link.href && getCSSClass() != "expertBadCert") - toggle("technicalContent"); - } - - function endsWith(haystack, needle) { - return haystack.slice(-needle.length) == needle; - } - - function toggle(id) { - var el = document.getElementById(id); - if (el.getAttribute("collapsed")) - el.setAttribute("collapsed", false); - else - el.setAttribute("collapsed", true); - } - ]]></script> - </head> - - <body id="errorPage" class="certerror" dir="&locale.dir;"> - - <!-- Error Title --> - <div id="errorTitle"> - <h1 class="errorTitleText">&certerror.longpagetitle;</h1> - </div> - - <!-- PAGE CONTAINER (for styling purposes only) --> - <div id="errorPageContainer"> - - <!-- LONG CONTENT (the section most likely to require scrolling) --> - <div id="errorLongContent"> - <div id="introContent"> - <p id="introContentP1">&certerror.introPara1;</p> - </div> - - <!-- The following sections can be unhidden by default by setting the - "browser.xul.error_pages.expert_bad_cert" pref to true --> - <div id="technicalContent" collapsed="true"> - <h2 onclick="toggle('technicalContent');" id="technicalContentHeading">&certerror.technical.heading;</h2> - <p id="technicalContentText"/> - </div> - - <div id="expertContent" collapsed="true"> - <h2 onclick="toggle('expertContent');" id="expertContentHeading">&certerror.expert.heading;</h2> - <div> - <p>&certerror.expert.content;</p> - <p>&certerror.expert.contentPara2;</p> - <button id="temporaryExceptionButton">&certerror.addTemporaryException.label;</button> - <button id="permanentExceptionButton">&certerror.addPermanentException.label;</button> - </div> - </div> - </div> - </div> - - <!-- - - Note: It is important to run the script this way, instead of using - - an onload handler. This is because error pages are loaded as - - LOAD_BACKGROUND, which means that onload handlers will not be executed. - --> - <script type="application/javascript">initPage();</script> - - </body> -</html> diff --git a/b2g/chrome/content/arrow.svg b/b2g/chrome/content/arrow.svg deleted file mode 100644 index d3d9e8246..000000000 --- a/b2g/chrome/content/arrow.svg +++ /dev/null @@ -1,5 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="no"?> - -<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.1" width="11px" style="position: absolute; top: -moz-calc(50% - 2px);"> - <polyline points="1 1 5 6 9 1" stroke="#414141" stroke-width="2" stroke-linecap="round" fill="transparent" stroke-linejoin="round"/> -</svg> diff --git a/b2g/chrome/content/blank.css b/b2g/chrome/content/blank.css deleted file mode 100644 index 71914be1f..000000000 --- a/b2g/chrome/content/blank.css +++ /dev/null @@ -1,7 +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/. */ - -body { - background: black; -} diff --git a/b2g/chrome/content/blank.html b/b2g/chrome/content/blank.html deleted file mode 100644 index b8b20e2c6..000000000 --- a/b2g/chrome/content/blank.html +++ /dev/null @@ -1,10 +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> - <head> - <link rel="stylesheet" href="blank.css" type="text/css" media="all" /> - </head> -</html> diff --git a/b2g/chrome/content/content.css b/b2g/chrome/content/content.css deleted file mode 100644 index bb478087e..000000000 --- a/b2g/chrome/content/content.css +++ /dev/null @@ -1,321 +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/. */ - -@namespace url("http://www.w3.org/1999/xhtml"); -@namespace xul url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"); - -/* Style the scrollbars */ -xul|window xul|scrollbar { - display: none; -} - -/* Bug 1041576 - Scrollable with scrollgrab should not have scrollbars */ - -@-moz-document domain(system.gaiamobile.org) { - .browser-container > xul|scrollbar { - display: none; - } -} - -%ifdef MOZ_GRAPHENE -.moz-noscrollbars > xul|scrollbar { - display: none; -} -%endif - -xul|scrollbar[root="true"] { - position: relative; - z-index: 2147483647; -} - -xul|scrollbar { - -moz-appearance: none !important; - background-color: transparent !important; - background-image: none !important; - border: 0px solid transparent !important; - pointer-events: none; -} - -/* Scrollbar code will reset the margin to the correct side depending on - where layout actually puts the scrollbar */ -xul|scrollbar[orient="vertical"] { - margin-left: -8px; - min-width: 8px; - max-width: 8px; -} - -xul|scrollbar[orient="vertical"] xul|thumb { - max-width: 6px !important; - min-width: 6px !important; -} - -xul|scrollbar[orient="horizontal"] { - margin-top: -8px; - min-height: 8px; - max-height: 8px; -} - -xul|scrollbar[orient="horizontal"] xul|thumb { - max-height: 6px !important; - min-height: 6px !important; -} - -xul|scrollbar:not([active="true"]), -xul|scrollbar[disabled] { - opacity: 0; -} - -xul|scrollbarbutton { - min-height: 8px !important; - min-width: 8px !important; - -moz-appearance: none !important; - visibility: hidden; -} - -xul|scrollbarbutton[sbattr="scrollbar-up-top"], -xul|scrollbarbutton[sbattr="scrollbar-bottom-top"] { - display: none; -} - -xul|thumb { - background-color: rgba(0, 0, 0, 0.4) !important; - -moz-border-top-colors: none !important; - -moz-border-bottom-colors: none !important; - -moz-border-right-colors: none !important; - -moz-border-left-colors: none !important; - border: 1px solid rgba(255, 255, 255, 0.4) !important; - border-radius: 3px; -} - -xul|scrollbarbutton { - background-image: none !important; -} - -%ifndef MOZ_GRAPHENE -/* -moz-touch-enabled? media elements */ -:-moz-any(video, audio) > xul|videocontrols { - -moz-binding: url("chrome://global/content/bindings/videocontrols.xml#touchControlsGonk"); -} - -select:not([size]):not([multiple]) > xul|scrollbar, -select[size="1"] > xul|scrollbar, -select:not([size]):not([multiple]) xul|scrollbarbutton, -select[size="1"] xul|scrollbarbutton { - display: block; - margin-left: 0; - min-width: 16px; -} - -/* Override inverse OS themes */ -select, -textarea, -button, -xul|button, -* > input:not([type="image"]) { - -moz-appearance: none !important; /* See bug 598421 for fixing the platform */ - border-radius: 3px; -} - -select[size], -select[multiple], -select[size][multiple], -textarea, -* > input:not([type="image"]) { - border-style: solid; - border-color: #7d7d7d; - color: #414141; - background-color: white; -} - -/* Selects are handled by the form helper, see bug 685197 */ -select option, select optgroup { - pointer-events: none; -} - -select:not([size]):not([multiple]), -select[size="0"], -select[size="1"], -* > input[type="button"], -* > input[type="submit"], -* > input[type="reset"], -button { - border-style: solid; - border-color: #7d7d7d; - color: #414141; - background: white linear-gradient(rgba(255,255,255,0.2) 0, rgba(215,215,215,0.5) 18px, rgba(115,115,115,0.5) 100%); -} - -input[type="checkbox"] { - background-color: white; -} - -input[type="radio"] { - background-color: white; -} - -select { - border-width: 1px; - padding: 1px; -} - -select:not([size]):not([multiple]), -select[size="0"], -select[size="1"] { - padding: 0 1px 0 1px; -} - -* > input:not([type="image"]) { - border-width: 1px; - padding: 1px; -} - -textarea { - resize: none; - border-width: 1px; - padding-inline-start: 1px; - padding-inline-end: 1px; - padding-block-start: 2px; - padding-block-end: 2px; -} - -input[type="button"], -input[type="submit"], -input[type="reset"], -button { - border-width: 1px; - padding-inline-start: 7px; - padding-inline-end: 7px; - padding-block-start: 0; - padding-block-end: 0; -} - -input[type="radio"], -input[type="checkbox"] { - border: 1px solid #a7a7a7 !important; - padding-inline-start: 1px; - padding-inline-end: 1px; - padding-block-start: 2px; - padding-block-end: 2px; -} - -select > button { - border-width: 0px !important; - margin: 0px !important; - padding: 0px !important; - border-radius: 0; - color: #414141; - - background-image: radial-gradient(at bottom left, #bbbbbb 40%, #f5f5f5), url(arrow.svg) !important; - background-color: transparent; - background-position: -15px center, 4px center !important; - background-repeat: no-repeat, no-repeat !important; - background-size: 100% 90%, auto auto; - - -moz-binding: none !important; - position: relative !important; - font-size: inherit; -} - -select[size]:focus, -select[multiple]:focus, -select[size][multiple]:focus, -textarea:focus, -input[type="file"]:focus > input[type="text"], -* > input:not([type="image"]):focus { - outline: 0px !important; - border-style: solid; - border-color: rgb(94,128,153); - background-color: white; -} - -select:not([size]):not([multiple]):focus, -select[size="0"]:focus, -select[size="1"]:focus, -input[type="button"]:focus, -input[type="submit"]:focus, -input[type="reset"]:focus, -button:focus { - outline: 0px !important; - border-style: solid; - border-color: rgb(94,128,153); - background: white linear-gradient(rgba(255,255,255,0.2) 0, rgba(198,225,256,0.2) 18px, rgba(27,113,177,0.5) 100%); -} - -input[type="checkbox"]:focus, -input[type="radio"]:focus { - border-color: #99c6e0 !important; -} - -/* we need to be specific for selects because the above rules are specific too */ -textarea[disabled], -select[size][disabled], -select[multiple][disabled], -select[size][multiple][disabled], -select:not([size]):not([multiple])[disabled], -select[size="0"][disabled], -select[size="1"][disabled], -button[disabled], -* > input:not([type="image"])[disabled] { - color: rgba(0,0,0,0.3); - border-color: rgba(125,125,125,0.4); - border-style: solid; - border-width: 1px; - background-color: #f5f5f5; -} - -select:not([size]):not([multiple])[disabled], -select[size="0"][disabled], -select[size="1"][disabled] { - background-color: #f5f5f5; -} - -input[type="button"][disabled], -input[type="submit"][disabled], -input[type="reset"][disabled], -button[disabled] { - padding-inline-start: 7px; - padding-inline-end: 7px; - padding-block-start: 0; - padding-block-end: 0; - background-color: #f5f5f5; -} - -input[type="radio"][disabled], -input[type="radio"][disabled]:active, -input[type="radio"][disabled]:hover, -input[type="radio"][disabled]:hover:active, -input[type="checkbox"][disabled], -input[type="checkbox"][disabled]:active, -input[type="checkbox"][disabled]:hover, -input[type="checkbox"][disabled]:hover:active { - border:1px solid rgba(125,125,125,0.4) !important; -} - -select[disabled] > button { - opacity: 0.6; - padding: 1px 7px 1px 7px; -} - -*:any-link:active, -*[role=button]:active, -button:active, -option:active, -select:active, -label:active { - background-color: rgba(141, 184, 216, 0.5); -} - -input[type=number] > div > div, /* work around bug 946184 */ -input[type=number]::-moz-number-spin-box { - display: none; -} -%endif - -%ifdef MOZ_WIDGET_GONK -/* This binding only provide key shortcuts that we can't use on devices */ -input, -textarea { --moz-binding: none !important; -} -%endif diff --git a/b2g/chrome/content/desktop.css b/b2g/chrome/content/desktop.css deleted file mode 100644 index 9612d732c..000000000 --- a/b2g/chrome/content/desktop.css +++ /dev/null @@ -1,59 +0,0 @@ -#controls { - position: absolute; - left: 0; - bottom:0; - right: 0; - height: 30px; - background-color: -moz-dialog; -} - -#home-button { - margin: auto; - margin-top: 3px; - width: 24px; - height: 24px; - background: #eee url("images/desktop/home-black.png") center no-repeat; - border: 1px solid #888; - border-radius: 12px; - display: block; -} - -#home-button::-moz-focus-inner { - padding: 0; - border: 0; -} - -#home-button:hover { - background-image: url("images/desktop/home-white.png"); - background-color: #ccc; - border-color: #555; -} - -#home-button.active { - background-image: url("images/desktop/home-white.png"); - background-color: #888; - border-color: black; -} - -#rotate-button { - position: absolute; - top: 3px; - bottom: 3px; - right: 3px; - width: 24px; - height: 24px; - background: #eee url("images/desktop/rotate.png") center no-repeat; - border: 1px solid #888; - border-radius: 12px; - display: block; -} - -#rotate-button:hover { - background-color: #ccc; - border-color: #555; -} - -#rotate-button.active { - background-color: #888; - border-color: black; -} diff --git a/b2g/chrome/content/desktop.js b/b2g/chrome/content/desktop.js deleted file mode 100644 index 5a1e7ff04..000000000 --- a/b2g/chrome/content/desktop.js +++ /dev/null @@ -1,179 +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/. */ - -var browserWindow = Services.wm.getMostRecentWindow("navigator:browser"); -var isMulet = "ResponsiveUI" in browserWindow; - -// Enable touch event shim on desktop that translates mouse events -// into touch ones -function enableTouch() { - let require = Cu.import('resource://devtools/shared/Loader.jsm', {}) - .devtools.require; - let { TouchEventSimulator } = require('devtools/shared/touch/simulator'); - let touchEventSimulator = new TouchEventSimulator(shell.contentBrowser); - touchEventSimulator.start(); -} - -// Some additional buttons are displayed on simulators to fake hardware buttons. -function setupButtons() { - let link = document.createElement('link'); - link.type = 'text/css'; - link.rel = 'stylesheet'; - link.href = 'chrome://b2g/content/desktop.css'; - document.head.appendChild(link); - - let footer = document.createElement('footer'); - footer.id = 'controls'; - document.body.appendChild(footer); - let homeButton = document.createElement('button'); - homeButton.id = 'home-button'; - footer.appendChild(homeButton); - let rotateButton = document.createElement('button'); - rotateButton.id = 'rotate-button'; - footer.appendChild(rotateButton); - - homeButton.addEventListener('mousedown', function() { - let window = shell.contentBrowser.contentWindow; - let e = new window.KeyboardEvent('keydown', {key: 'Home'}); - window.dispatchEvent(e); - homeButton.classList.add('active'); - }); - homeButton.addEventListener('mouseup', function() { - let window = shell.contentBrowser.contentWindow; - let e = new window.KeyboardEvent('keyup', {key: 'Home'}); - window.dispatchEvent(e); - homeButton.classList.remove('active'); - }); - - Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm"); - rotateButton.addEventListener('mousedown', function() { - rotateButton.classList.add('active'); - }); - rotateButton.addEventListener('mouseup', function() { - GlobalSimulatorScreen.flipScreen(); - rotateButton.classList.remove('active'); - }); -} - -function setupStorage() { - let directory = null; - - // Get the --storage-path argument from the command line. - try { - let service = Cc['@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds'].getService(Ci.nsISupports); - let args = service.wrappedJSObject.cmdLine; - if (args) { - let path = args.handleFlagWithParam('storage-path', false); - directory = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); - directory.initWithPath(path); - } - } catch(e) { - directory = null; - } - - // Otherwise, default to 'storage' folder within current profile. - if (!directory) { - directory = Services.dirsvc.get('ProfD', Ci.nsIFile); - directory.append('storage'); - if (!directory.exists()) { - directory.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("755", 8)); - } - } - dump("Set storage path to: " + directory.path + "\n"); - - // This is the magic, where we override the default location for the storages. - Services.prefs.setCharPref('device.storage.overrideRootDir', directory.path); -} - -function checkDebuggerPort() { - // XXX: To be removed once bug 942756 lands. - // We are hacking 'unix-domain-socket' pref by setting a tcp port (number). - // SocketListener.open detects that it isn't a file path (string), and starts - // listening on the tcp port given here as command line argument. - - // Get the command line arguments that were passed to the b2g client - let args; - try { - let service = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"].getService(Ci.nsISupports); - args = service.wrappedJSObject.cmdLine; - } catch(e) {} - - if (!args) { - return; - } - - let dbgport; - try { - dbgport = args.handleFlagWithParam('start-debugger-server', false); - } catch(e) {} - - if (dbgport) { - dump('Opening debugger server on ' + dbgport + '\n'); - Services.prefs.setCharPref('devtools.debugger.unix-domain-socket', dbgport); - navigator.mozSettings.createLock().set( - {'debugger.remote-mode': 'adb-devtools'}); - } -} - - -function initResponsiveDesign() { - Cu.import('resource://devtools/client/responsivedesign/responsivedesign.jsm'); - ResponsiveUIManager.on('on', function(event, {tab:tab}) { - let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab); - let document = tab.ownerDocument; - - // Only tweak reponsive mode for shell.html tabs. - if (tab.linkedBrowser.contentWindow != window) { - return; - } - - // Disable transition as they mess up with screen size handler - responsive.transitionsEnabled = false; - - responsive.buildPhoneUI(); - - responsive.rotatebutton.addEventListener('command', function (evt) { - GlobalSimulatorScreen.flipScreen(); - evt.stopImmediatePropagation(); - evt.preventDefault(); - }, true); - - // Enable touch events - responsive.enableTouch(); - }); - - - let mgr = browserWindow.ResponsiveUI.ResponsiveUIManager; - mgr.toggle(browserWindow, browserWindow.gBrowser.selectedTab); - -} - -function openDevtools() { - // Open devtool panel while maximizing its size according to screen size - Services.prefs.setIntPref('devtools.toolbox.sidebar.width', - browserWindow.outerWidth - 550); - Services.prefs.setCharPref('devtools.toolbox.host', 'side'); - let {gDevTools} = Cu.import('resource://devtools/client/framework/gDevTools.jsm', {}); - let {devtools} = Cu.import("resource://devtools/shared/Loader.jsm", {}); - let target = devtools.TargetFactory.forTab(browserWindow.gBrowser.selectedTab); - gDevTools.showToolbox(target); -} - -window.addEventListener('ContentStart', function() { - // On Firefox Mulet, touch events are enabled within the responsive mode - if (!isMulet) { - enableTouch(); - } - if (Services.prefs.getBoolPref('b2g.software-buttons')) { - setupButtons(); - } - checkDebuggerPort(); - setupStorage(); - // On Firefox mulet, we automagically enable the responsive mode - // and show the devtools - if (isMulet) { - initResponsiveDesign(browserWindow); - openDevtools(); - } -}); diff --git a/b2g/chrome/content/devtools/adb.js b/b2g/chrome/content/devtools/adb.js deleted file mode 100644 index cebc6696b..000000000 --- a/b2g/chrome/content/devtools/adb.js +++ /dev/null @@ -1,233 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -// This file is only loaded on Gonk to manage ADB state - -Components.utils.import("resource://gre/modules/FileUtils.jsm"); - -const DEBUG = false; -var debug = function(str) { - dump("AdbController: " + str + "\n"); -} - -var AdbController = { - locked: undefined, - remoteDebuggerEnabled: undefined, - lockEnabled: undefined, - disableAdbTimer: null, - disableAdbTimeoutHours: 12, - umsActive: false, - - setLockscreenEnabled: function(value) { - this.lockEnabled = value; - DEBUG && debug("setLockscreenEnabled = " + this.lockEnabled); - this.updateState(); - }, - - setLockscreenState: function(value) { - this.locked = value; - DEBUG && debug("setLockscreenState = " + this.locked); - this.updateState(); - }, - - setRemoteDebuggerState: function(value) { - this.remoteDebuggerEnabled = value; - DEBUG && debug("setRemoteDebuggerState = " + this.remoteDebuggerEnabled); - this.updateState(); - }, - - startDisableAdbTimer: function() { - if (this.disableAdbTimer) { - this.disableAdbTimer.cancel(); - } else { - this.disableAdbTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); - try { - this.disableAdbTimeoutHours = - Services.prefs.getIntPref("b2g.adb.timeout-hours"); - } catch (e) { - // This happens if the pref doesn't exist, in which case - // disableAdbTimeoutHours will still be set to the default. - } - } - if (this.disableAdbTimeoutHours <= 0) { - DEBUG && debug("Timer to disable ADB not started due to zero timeout"); - return; - } - - DEBUG && debug("Starting timer to disable ADB in " + - this.disableAdbTimeoutHours + " hours"); - let timeoutMilliseconds = this.disableAdbTimeoutHours * 60 * 60 * 1000; - this.disableAdbTimer.initWithCallback(this, timeoutMilliseconds, - Ci.nsITimer.TYPE_ONE_SHOT); - }, - - stopDisableAdbTimer: function() { - DEBUG && debug("Stopping timer to disable ADB"); - if (this.disableAdbTimer) { - this.disableAdbTimer.cancel(); - this.disableAdbTimer = null; - } - }, - - notify: function(aTimer) { - if (aTimer == this.disableAdbTimer) { - this.disableAdbTimer = null; - // The following dump will be the last thing that shows up in logcat, - // and will at least give the user a clue about why logcat was - // disconnected, if the user happens to be using logcat. - debug("ADB timer expired - disabling ADB\n"); - navigator.mozSettings.createLock().set( - {'debugger.remote-mode': 'disabled'}); - } - }, - - updateState: function() { - this.umsActive = false; - }, - - updateStateInternal: function() { - DEBUG && debug("updateStateInternal: called"); - - if (this.remoteDebuggerEnabled === undefined || - this.lockEnabled === undefined || - this.locked === undefined) { - // Part of initializing the settings database will cause the observers - // to trigger. We want to wait until both have been initialized before - // we start changing ther adb state. Without this then we can wind up - // toggling adb off and back on again (or on and back off again). - // - // For completeness, one scenario which toggles adb is using the unagi. - // The unagi has adb enabled by default (prior to b2g starting). If you - // have the phone lock disabled and remote debugging enabled, then we'll - // receive an unlock event and an rde event. However at the time we - // receive the unlock event we haven't yet received the rde event, so - // we turn adb off momentarily, which disconnects a logcat that might - // be running. Changing the defaults (in AdbController) just moves the - // problem to a different phone, which has adb disabled by default and - // we wind up turning on adb for a short period when we shouldn't. - // - // By waiting until both values are properly initialized, we avoid - // turning adb on or off accidentally. - DEBUG && debug("updateState: Waiting for all vars to be initialized"); - return; - } - - // Check if we have a remote debugging session going on. If so, we won't - // disable adb even if the screen is locked. - let isDebugging = USBRemoteDebugger.isDebugging; - DEBUG && debug("isDebugging=" + isDebugging); - - // If USB Mass Storage, USB tethering, or a debug session is active, - // then we don't want to disable adb in an automatic fashion (i.e. - // when the screen locks or due to timeout). - let sysUsbConfig = libcutils.property_get("sys.usb.config").split(","); - let usbFuncActive = this.umsActive || isDebugging; - usbFuncActive |= (sysUsbConfig.indexOf("rndis") >= 0); - usbFuncActive |= (sysUsbConfig.indexOf("mtp") >= 0); - - let enableAdb = this.remoteDebuggerEnabled && - (!(this.lockEnabled && this.locked) || usbFuncActive); - - let useDisableAdbTimer = true; - try { - if (Services.prefs.getBoolPref("marionette.defaultPrefs.enabled")) { - // Marionette is enabled. Marionette requires that adb be on (and also - // requires that remote debugging be off). The fact that marionette - // is enabled also implies that we're doing a non-production build, so - // we want adb enabled all of the time. - enableAdb = true; - useDisableAdbTimer = false; - } - } catch (e) { - // This means that the pref doesn't exist. Which is fine. We just leave - // enableAdb alone. - } - - // Check wakelock to prevent adb from disconnecting when phone is locked - let lockFile = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); - lockFile.initWithPath('/sys/power/wake_lock'); - if(lockFile.exists()) { - let foStream = Cc["@mozilla.org/network/file-input-stream;1"] - .createInstance(Ci.nsIFileInputStream); - let coStream = Cc["@mozilla.org/intl/converter-input-stream;1"] - .createInstance(Ci.nsIConverterInputStream); - let str = {}; - foStream.init(lockFile, FileUtils.MODE_RDONLY, 0, 0); - coStream.init(foStream, "UTF-8", 0, 0); - coStream.readString(-1, str); - coStream.close(); - foStream.close(); - let wakeLockContents = str.value.replace(/\n/, ""); - let wakeLockList = wakeLockContents.split(" "); - if (wakeLockList.indexOf("adb") >= 0) { - enableAdb = true; - useDisableAdbTimer = false; - DEBUG && debug("Keeping ADB enabled as ADB wakelock is present."); - } else { - DEBUG && debug("ADB wakelock not found."); - } - } else { - DEBUG && debug("Wake_lock file not found."); - } - - DEBUG && debug("updateState: enableAdb = " + enableAdb + - " remoteDebuggerEnabled = " + this.remoteDebuggerEnabled + - " lockEnabled = " + this.lockEnabled + - " locked = " + this.locked + - " usbFuncActive = " + usbFuncActive); - - // Configure adb. - let currentConfig = libcutils.property_get("persist.sys.usb.config"); - let configFuncs = currentConfig.split(","); - if (currentConfig == "" || currentConfig == "none") { - // We want to treat none like the empty string. - // "".split(",") yields [""] and not [] - configFuncs = []; - } - let adbIndex = configFuncs.indexOf("adb"); - - if (enableAdb) { - // Add adb to the list of functions, if not already present - if (adbIndex < 0) { - configFuncs.push("adb"); - } - } else { - // Remove adb from the list of functions, if present - if (adbIndex >= 0) { - configFuncs.splice(adbIndex, 1); - } - } - let newConfig = configFuncs.join(","); - if (newConfig == "") { - // Convert the empty string back into none, since that's what init.rc - // needs. - newConfig = "none"; - } - if (newConfig != currentConfig) { - DEBUG && debug("updateState: currentConfig = " + currentConfig); - DEBUG && debug("updateState: newConfig = " + newConfig); - try { - libcutils.property_set("persist.sys.usb.config", newConfig); - } catch(e) { - Cu.reportError("Error configuring adb: " + e); - } - } - if (useDisableAdbTimer) { - if (enableAdb && !usbFuncActive) { - this.startDisableAdbTimer(); - } else { - this.stopDisableAdbTimer(); - } - } - } -}; - -SettingsListener.observe("lockscreen.locked", false, - AdbController.setLockscreenState.bind(AdbController)); -SettingsListener.observe("lockscreen.enabled", false, - AdbController.setLockscreenEnabled.bind(AdbController)); diff --git a/b2g/chrome/content/devtools/debugger.js b/b2g/chrome/content/devtools/debugger.js deleted file mode 100644 index 11987a839..000000000 --- a/b2g/chrome/content/devtools/debugger.js +++ /dev/null @@ -1,397 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* 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"; - -XPCOMUtils.defineLazyGetter(this, "devtools", function() { - const { devtools } = - Cu.import("resource://devtools/shared/Loader.jsm", {}); - return devtools; -}); - -XPCOMUtils.defineLazyGetter(this, "DebuggerServer", function() { - const { DebuggerServer } = devtools.require("devtools/server/main"); - return DebuggerServer; -}); - -XPCOMUtils.defineLazyGetter(this, "B2GTabList", function() { - const { B2GTabList } = - devtools.require("resource://gre/modules/DebuggerActors.js"); - return B2GTabList; -}); - -// Load the discovery module eagerly, so that it can set a device name at -// startup. This does not cause discovery to start listening for packets, as -// that only happens once DevTools is enabled. -devtools.require("devtools/shared/discovery/discovery"); - -var RemoteDebugger = { - _listening: false, - - /** - * Prompt the user to accept or decline the incoming connection. - * - * @param session object - * The session object will contain at least the following fields: - * { - * authentication, - * client: { - * host, - * port - * }, - * server: { - * host, - * port - * } - * } - * Specific authentication modes may include additional fields. Check - * the different |allowConnection| methods in - * devtools/shared/security/auth.js. - * @return An AuthenticationResult value. - * A promise that will be resolved to the above is also allowed. - */ - allowConnection(session) { - if (this._promptingForAllow) { - // Don't stack connection prompts if one is already open - return DebuggerServer.AuthenticationResult.DENY; - } - this._listen(); - - this._promptingForAllow = new Promise(resolve => { - this._handleAllowResult = detail => { - this._handleAllowResult = null; - this._promptingForAllow = null; - // Newer Gaia supplies |authResult|, which is one of the - // AuthenticationResult values. - if (detail.authResult) { - resolve(detail.authResult); - } else if (detail.value) { - resolve(DebuggerServer.AuthenticationResult.ALLOW); - } else { - resolve(DebuggerServer.AuthenticationResult.DENY); - } - }; - - shell.sendChromeEvent({ - type: "remote-debugger-prompt", - session - }); - }); - - return this._promptingForAllow; - }, - - /** - * During OOB_CERT authentication, the user must transfer some data through some - * out of band mechanism from the client to the server to authenticate the - * devices. - * - * This implementation instructs Gaia to continually capture images which are - * passed back here and run through a QR decoder. - * - * @return An object containing: - * * sha256: hash(ClientCert) - * * k : K(random 128-bit number) - * A promise that will be resolved to the above is also allowed. - */ - receiveOOB() { - if (this._receivingOOB) { - return this._receivingOOB; - } - this._listen(); - - const QR = devtools.require("devtools/shared/qrcode/index"); - this._receivingOOB = new Promise((resolve, reject) => { - this._handleAuthEvent = detail => { - debug(detail.action); - if (detail.action === "abort") { - this._handleAuthEvent = null; - this._receivingOOB = null; - reject(); - return; - } - - if (detail.action !== "capture") { - return; - } - - let url = detail.url; - QR.decodeFromURI(url).then(data => { - debug("Got auth data: " + data); - let oob = JSON.parse(data); - - shell.sendChromeEvent({ - type: "devtools-auth", - action: "stop" - }); - - this._handleAuthEvent = null; - this._receivingOOB = null; - resolve(oob); - }).catch(() => { - debug("No auth data, requesting new capture"); - shell.sendChromeEvent({ - type: "devtools-auth", - action: "capture" - }); - }); - }; - - // Show QR scanning dialog, get an initial capture - shell.sendChromeEvent({ - type: "devtools-auth", - action: "start" - }); - }); - - return this._receivingOOB; - }, - - _listen: function() { - if (this._listening) { - return; - } - - this.handleEvent = this.handleEvent.bind(this); - let content = shell.contentBrowser.contentWindow; - content.addEventListener("mozContentEvent", this, false, true); - this._listening = true; - }, - - handleEvent: function(event) { - let detail = event.detail; - if (detail.type === "remote-debugger-prompt" && this._handleAllowResult) { - this._handleAllowResult(detail); - } - if (detail.type === "devtools-auth" && this._handleAuthEvent) { - this._handleAuthEvent(detail); - } - }, - - initServer: function() { - if (DebuggerServer.initialized) { - return; - } - - // Ask for remote connections. - DebuggerServer.init(); - - // /!\ Be careful when adding a new actor, especially global actors. - // Any new global actor will be exposed and returned by the root actor. - - // Add Firefox-specific actors, but prevent tab actors to be loaded in - // the parent process, unless we enable certified apps debugging. - let restrictPrivileges = Services.prefs.getBoolPref("devtools.debugger.forbid-certified-apps"); - DebuggerServer.addBrowserActors("navigator:browser", restrictPrivileges); - - // Allow debugging of chrome for any process - if (!restrictPrivileges) { - DebuggerServer.allowChromeProcess = true; - } - - /** - * Construct a root actor appropriate for use in a server running in B2G. - * The returned root actor respects the factories registered with - * DebuggerServer.addGlobalActor only if certified apps debugging is on, - * otherwise we used an explicit limited list of global actors - * - * * @param connection DebuggerServerConnection - * The conection to the client. - */ - DebuggerServer.createRootActor = function createRootActor(connection) - { - let parameters = { - tabList: new B2GTabList(connection), - // Use an explicit global actor list to prevent exposing - // unexpected actors - globalActorFactories: restrictPrivileges ? { - webappsActor: DebuggerServer.globalActorFactories.webappsActor, - deviceActor: DebuggerServer.globalActorFactories.deviceActor, - settingsActor: DebuggerServer.globalActorFactories.settingsActor - } : DebuggerServer.globalActorFactories - }; - let { RootActor } = devtools.require("devtools/server/actors/root"); - let root = new RootActor(connection, parameters); - root.applicationType = "operating-system"; - return root; - }; - - if (isGonk) { - DebuggerServer.on("connectionchange", function() { - AdbController.updateState(); - }); - } - } -}; - -RemoteDebugger.allowConnection = - RemoteDebugger.allowConnection.bind(RemoteDebugger); -RemoteDebugger.receiveOOB = - RemoteDebugger.receiveOOB.bind(RemoteDebugger); - -var USBRemoteDebugger = { - - get isDebugging() { - if (!this._listener) { - return false; - } - - return DebuggerServer._connections && - Object.keys(DebuggerServer._connections).length > 0; - }, - - start: function() { - if (this._listener) { - return; - } - - RemoteDebugger.initServer(); - - let portOrPath = - Services.prefs.getCharPref("devtools.debugger.unix-domain-socket") || - "/data/local/debugger-socket"; - - try { - debug("Starting USB debugger on " + portOrPath); - let AuthenticatorType = DebuggerServer.Authenticators.get("PROMPT"); - let authenticator = new AuthenticatorType.Server(); - authenticator.allowConnection = RemoteDebugger.allowConnection; - this._listener = DebuggerServer.createListener(); - this._listener.portOrPath = portOrPath; - this._listener.authenticator = authenticator; - this._listener.open(); - // Temporary event, until bug 942756 lands and offers a way to know - // when the server is up and running. - Services.obs.notifyObservers(null, "debugger-server-started", null); - } catch (e) { - debug("Unable to start USB debugger server: " + e); - } - }, - - stop: function() { - if (!this._listener) { - return; - } - - try { - this._listener.close(); - this._listener = null; - } catch (e) { - debug("Unable to stop USB debugger server: " + e); - } - } - -}; - -var WiFiRemoteDebugger = { - - start: function() { - if (this._listener) { - return; - } - - RemoteDebugger.initServer(); - - try { - debug("Starting WiFi debugger"); - let AuthenticatorType = DebuggerServer.Authenticators.get("OOB_CERT"); - let authenticator = new AuthenticatorType.Server(); - authenticator.allowConnection = RemoteDebugger.allowConnection; - authenticator.receiveOOB = RemoteDebugger.receiveOOB; - this._listener = DebuggerServer.createListener(); - this._listener.portOrPath = -1 /* any available port */; - this._listener.authenticator = authenticator; - this._listener.discoverable = true; - this._listener.encryption = true; - this._listener.open(); - let port = this._listener.port; - debug("Started WiFi debugger on " + port); - } catch (e) { - debug("Unable to start WiFi debugger server: " + e); - } - }, - - stop: function() { - if (!this._listener) { - return; - } - - try { - this._listener.close(); - this._listener = null; - } catch (e) { - debug("Unable to stop WiFi debugger server: " + e); - } - } - -}; - -(function() { - // Track these separately here so we can determine the correct value for the - // pref "devtools.debugger.remote-enabled", which is true when either mode of - // using DevTools is enabled. - let devtoolsUSB = false; - let devtoolsWiFi = false; - - // Keep the old setting to not break people that won't have updated - // gaia and gecko. - SettingsListener.observe("devtools.debugger.remote-enabled", false, - function(value) { - devtoolsUSB = value; - Services.prefs.setBoolPref("devtools.debugger.remote-enabled", - devtoolsUSB || devtoolsWiFi); - // This preference is consulted during startup - Services.prefs.savePrefFile(null); - try { - value ? USBRemoteDebugger.start() : USBRemoteDebugger.stop(); - } catch(e) { - dump("Error while initializing USB devtools: " + - e + "\n" + e.stack + "\n"); - } - }); - - SettingsListener.observe("debugger.remote-mode", "disabled", function(value) { - if (["disabled", "adb-only", "adb-devtools"].indexOf(value) == -1) { - dump("Illegal value for debugger.remote-mode: " + value + "\n"); - return; - } - - devtoolsUSB = value == "adb-devtools"; - Services.prefs.setBoolPref("devtools.debugger.remote-enabled", - devtoolsUSB || devtoolsWiFi); - // This preference is consulted during startup - Services.prefs.savePrefFile(null); - - try { - (value == "adb-devtools") ? USBRemoteDebugger.start() - : USBRemoteDebugger.stop(); - } catch(e) { - dump("Error while initializing USB devtools: " + - e + "\n" + e.stack + "\n"); - } - - isGonk && AdbController.setRemoteDebuggerState(value != "disabled"); - }); - - SettingsListener.observe("devtools.remote.wifi.enabled", false, - function(value) { - devtoolsWiFi = value; - Services.prefs.setBoolPref("devtools.debugger.remote-enabled", - devtoolsUSB || devtoolsWiFi); - // Allow remote debugging on non-local interfaces when WiFi debug is enabled - // TODO: Bug 1034411: Lock down to WiFi interface, instead of all interfaces - Services.prefs.setBoolPref("devtools.debugger.force-local", !value); - // This preference is consulted during startup - Services.prefs.savePrefFile(null); - - try { - value ? WiFiRemoteDebugger.start() : WiFiRemoteDebugger.stop(); - } catch(e) { - dump("Error while initializing WiFi devtools: " + - e + "\n" + e.stack + "\n"); - } - }); -})(); diff --git a/b2g/chrome/content/devtools/hud.js b/b2g/chrome/content/devtools/hud.js deleted file mode 100644 index 64e9d553d..000000000 --- a/b2g/chrome/content/devtools/hud.js +++ /dev/null @@ -1,1017 +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'; - -// settings.js loads this file when the HUD setting is enabled. - -const DEVELOPER_HUD_LOG_PREFIX = 'DeveloperHUD'; -const CUSTOM_HISTOGRAM_PREFIX = 'DEVTOOLS_HUD_CUSTOM_'; -const APPNAME_IDX = 3; -const HISTNAME_IDX = 4; - -XPCOMUtils.defineLazyGetter(this, 'devtools', function() { - const {devtools} = Cu.import('resource://devtools/shared/Loader.jsm', {}); - return devtools; -}); - -XPCOMUtils.defineLazyGetter(this, 'DebuggerClient', function() { - return devtools.require('devtools/shared/client/main').DebuggerClient; -}); - -XPCOMUtils.defineLazyGetter(this, 'WebConsoleUtils', function() { - return devtools.require('devtools/shared/webconsole/utils').Utils; -}); - -XPCOMUtils.defineLazyGetter(this, 'EventLoopLagFront', function() { - return devtools.require('devtools/shared/fronts/eventlooplag').EventLoopLagFront; -}); - -XPCOMUtils.defineLazyGetter(this, 'PerformanceEntriesFront', function() { - return devtools.require('devtools/server/actors/performance-entries').PerformanceEntriesFront; -}); - -XPCOMUtils.defineLazyGetter(this, 'MemoryFront', function() { - return devtools.require('devtools/server/actors/memory').MemoryFront; -}); - -Cu.import('resource://gre/modules/Frames.jsm'); - -var _telemetryDebug = false; - -function telemetryDebug(...args) { - if (_telemetryDebug) { - args.unshift('[AdvancedTelemetry]'); - console.log(...args); - } -} - -/** - * The Developer HUD is an on-device developer tool that displays widgets, - * showing visual debug information about apps. Each widget corresponds to a - * metric as tracked by a metric watcher (e.g. consoleWatcher). - */ -var developerHUD = { - - _targets: new Map(), - _histograms: new Set(), - _customHistograms: new Set(), - _client: null, - _conn: null, - _watchers: [], - _logging: true, - _telemetry: false, - - /** - * This method registers a metric watcher that will watch one or more metrics - * on app frames that are being tracked. A watcher must implement the - * `trackTarget(target)` and `untrackTarget(target)` methods, register - * observed metrics with `target.register(metric)`, and keep them up-to-date - * with `target.update(metric, message)` when necessary. - */ - registerWatcher(watcher) { - this._watchers.unshift(watcher); - }, - - init() { - if (this._client) { - return; - } - - if (!DebuggerServer.initialized) { - RemoteDebugger.initServer(); - } - - // We instantiate a local debugger connection so that watchers can use our - // DebuggerClient to send requests to tab actors (e.g. the consoleActor). - // Note the special usage of the private _serverConnection, which we need - // to call connectToChild and set up child process actors on a frame we - // intend to track. These actors will use the connection to communicate with - // our DebuggerServer in the parent process. - let transport = DebuggerServer.connectPipe(); - this._conn = transport._serverConnection; - this._client = new DebuggerClient(transport); - - for (let w of this._watchers) { - if (w.init) { - w.init(this._client); - } - } - - Frames.addObserver(this); - - let appFrames = Frames.list().filter(frame => frame.getAttribute('mozapp')); - for (let frame of appFrames) { - this.trackFrame(frame); - } - - SettingsListener.observe('hud.logging', this._logging, enabled => { - this._logging = enabled; - }); - - SettingsListener.observe('hud.telemetry.logging', _telemetryDebug, enabled => { - _telemetryDebug = enabled; - }); - - SettingsListener.observe('metrics.selectedMetrics.level', "", level => { - this._telemetry = (level === 'Enhanced'); - }); - }, - - uninit() { - if (!this._client) { - return; - } - - for (let frame of this._targets.keys()) { - this.untrackFrame(frame); - } - - Frames.removeObserver(this); - - this._client.close(); - delete this._client; - }, - - /** - * This method will ask all registered watchers to track and update metrics - * on an app frame. - */ - trackFrame(frame) { - if (this._targets.has(frame)) { - return; - } - - DebuggerServer.connectToChild(this._conn, frame).then(actor => { - let target = new Target(frame, actor); - this._targets.set(frame, target); - - for (let w of this._watchers) { - w.trackTarget(target); - } - }); - }, - - untrackFrame(frame) { - let target = this._targets.get(frame); - if (target) { - for (let w of this._watchers) { - w.untrackTarget(target); - } - - target.destroy(); - this._targets.delete(frame); - } - }, - - onFrameCreated(frame, isFirstAppFrame) { - let mozapp = frame.getAttribute('mozapp'); - if (!mozapp) { - return; - } - this.trackFrame(frame); - }, - - onFrameDestroyed(frame, isLastAppFrame) { - let mozapp = frame.getAttribute('mozapp'); - if (!mozapp) { - return; - } - this.untrackFrame(frame); - }, - - log(message) { - if (this._logging) { - dump(DEVELOPER_HUD_LOG_PREFIX + ': ' + message + '\n'); - } - } - -}; - - -/** - * A Target object represents all there is to know about a Firefox OS app frame - * that is being tracked, e.g. a pointer to the frame, current values of watched - * metrics, and how to notify the front-end when metrics have changed. - */ -function Target(frame, actor) { - this.frame = frame; - this.actor = actor; - this.metrics = new Map(); - this._appName = null; -} - -Target.prototype = { - - get manifest() { - return this.frame.appManifestURL; - }, - - get appName() { - - if (this._appName) { - return this._appName; - } - - let manifest = this.manifest; - if (!manifest) { - let msg = DEVELOPER_HUD_LOG_PREFIX + ': Unable to determine app for telemetry metric. src: ' + - this.frame.src; - console.error(msg); - return null; - } - - // "communications" apps are a special case - if (manifest.indexOf('communications') === -1) { - let start = manifest.indexOf('/') + 2; - let end = manifest.indexOf('.', start); - this._appName = manifest.substring(start, end).toLowerCase(); - } else { - let src = this.frame.src; - if (src) { - // e.g., `app://communications.gaiamobile.org/contacts/index.html` - let parts = src.split('/'); - let APP = 3; - let EXPECTED_PARTS_LENGTH = 5; - if (parts.length === EXPECTED_PARTS_LENGTH) { - this._appName = parts[APP]; - } - } - } - - return this._appName; - }, - - /** - * Register a metric that can later be updated. Does not update the front-end. - */ - register(metric) { - this.metrics.set(metric, 0); - }, - - /** - * Modify one of a target's metrics, and send out an event to notify relevant - * parties (e.g. the developer HUD, automated tests, etc). - */ - update(metric, message) { - if (!metric.name) { - throw new Error('Missing metric.name'); - } - - if (!metric.value) { - metric.value = 0; - } - - let metrics = this.metrics; - if (metrics) { - metrics.set(metric.name, metric.value); - } - - let data = { - metrics: [], // FIXME(Bug 982066) Remove this field. - manifest: this.manifest, - metric: metric, - message: message - }; - - // FIXME(Bug 982066) Remove this loop. - if (metrics && metrics.size > 0) { - for (let name of metrics.keys()) { - data.metrics.push({name: name, value: metrics.get(name)}); - } - } - - if (message) { - developerHUD.log('[' + data.manifest + '] ' + data.message); - } - - this._send(data); - }, - - /** - * Nicer way to call update() when the metric value is a number that needs - * to be incremented. - */ - bump(metric, message) { - metric.value = (this.metrics.get(metric.name) || 0) + 1; - this.update(metric, message); - }, - - /** - * Void a metric value and make sure it isn't displayed on the front-end - * anymore. - */ - clear(metric) { - metric.value = 0; - this.update(metric); - }, - - /** - * Tear everything down, including the front-end by sending a message without - * widgets. - */ - destroy() { - delete this.metrics; - this._send({metric: {skipTelemetry: true}}); - }, - - _send(data) { - let frame = this.frame; - - shell.sendEvent(frame, 'developer-hud-update', Cu.cloneInto(data, frame)); - this._logHistogram(data.metric); - }, - - _getAddonHistogram(item) { - let appName = this._getAddonHistogramName(item, APPNAME_IDX); - let histName = this._getAddonHistogramName(item, HISTNAME_IDX); - - return Services.telemetry.getAddonHistogram(appName, CUSTOM_HISTOGRAM_PREFIX - + histName); - }, - - _getAddonHistogramName(item, index) { - let array = item.split('_'); - return array[index].toUpperCase(); - }, - - _clearTelemetryData() { - developerHUD._histograms.forEach(function(item) { - Services.telemetry.getKeyedHistogramById(item).clear(); - }); - - developerHUD._customHistograms.forEach(item => { - this._getAddonHistogram(item).clear(); - }); - }, - - _sendTelemetryData() { - if (!developerHUD._telemetry) { - return; - } - telemetryDebug('calling sendTelemetryData'); - let frame = this.frame; - let payload = { - keyedHistograms: {}, - addonHistograms: {} - }; - // Package the hud histograms. - developerHUD._histograms.forEach(function(item) { - payload.keyedHistograms[item] = - Services.telemetry.getKeyedHistogramById(item).snapshot(); - }); - - // Package the registered hud custom histograms - developerHUD._customHistograms.forEach(item => { - let appName = this._getAddonHistogramName(item, APPNAME_IDX); - let histName = CUSTOM_HISTOGRAM_PREFIX + - this._getAddonHistogramName(item, HISTNAME_IDX); - let addonHist = Services.telemetry.getAddonHistogram(appName, histName).snapshot(); - if (!(appName in payload.addonHistograms)) { - payload.addonHistograms[appName] = {}; - } - // Do not include histograms with sum of 0. - if (addonHist.sum > 0) { - payload.addonHistograms[appName][histName] = addonHist; - } - }); - shell.sendEvent(frame, 'advanced-telemetry-update', Cu.cloneInto(payload, frame)); - }, - - _logHistogram(metric) { - if (!developerHUD._telemetry || metric.skipTelemetry) { - return; - } - - metric.appName = this.appName; - if (!metric.appName) { - return; - } - - let metricName = metric.name.toUpperCase(); - let metricAppName = metric.appName.toUpperCase(); - if (!metric.custom) { - let keyedMetricName = 'DEVTOOLS_HUD_' + metricName; - try { - let keyed = Services.telemetry.getKeyedHistogramById(keyedMetricName); - if (keyed) { - keyed.add(metric.appName, parseInt(metric.value, 10)); - developerHUD._histograms.add(keyedMetricName); - telemetryDebug(keyedMetricName, metric.value, metric.appName); - } - } catch(err) { - console.error('Histogram error is metricname added to histograms.json:' - + keyedMetricName); - } - } else { - let histogramName = CUSTOM_HISTOGRAM_PREFIX + metricAppName + '_' - + metricName; - // This is a call to add a value to an existing histogram. - if (typeof metric.value !== 'undefined') { - Services.telemetry.getAddonHistogram(metricAppName, - CUSTOM_HISTOGRAM_PREFIX + metricName).add(parseInt(metric.value, 10)); - telemetryDebug(histogramName, metric.value); - return; - } - - // The histogram already exists and are not adding data to it. - if (developerHUD._customHistograms.has(histogramName)) { - return; - } - - // This is a call to create a new histogram. - try { - let metricType = parseInt(metric.type, 10); - if (metricType === Services.telemetry.HISTOGRAM_COUNT) { - Services.telemetry.registerAddonHistogram(metricAppName, - CUSTOM_HISTOGRAM_PREFIX + metricName, metricType); - } else { - Services.telemetry.registerAddonHistogram(metricAppName, - CUSTOM_HISTOGRAM_PREFIX + metricName, metricType, metric.min, - metric.max, metric.buckets); - } - developerHUD._customHistograms.add(histogramName); - } catch (err) { - console.error('Histogram error: ' + err); - } - } - } -}; - - -/** - * The Console Watcher tracks the following metrics in apps: reflows, warnings, - * and errors, with security errors reported separately. - */ -var consoleWatcher = { - - _client: null, - _targets: new Map(), - _watching: { - reflows: false, - warnings: false, - errors: false, - security: false - }, - _security: [ - 'Mixed Content Blocker', - 'Mixed Content Message', - 'CSP', - 'Invalid HSTS Headers', - 'Invalid HPKP Headers', - 'Insecure Password Field', - 'SSL', - 'CORS' - ], - _reflowThreshold: 0, - - init(client) { - this._client = client; - this.consoleListener = this.consoleListener.bind(this); - - let watching = this._watching; - - for (let key in watching) { - let metric = key; - SettingsListener.observe('hud.' + metric, watching[metric], watch => { - // Watch or unwatch the metric. - if (watching[metric] = watch) { - return; - } - - // If unwatched, remove any existing widgets for that metric. - for (let target of this._targets.values()) { - target.clear({name: metric}); - } - }); - } - - SettingsListener.observe('hud.reflows.duration', this._reflowThreshold, threshold => { - this._reflowThreshold = threshold; - }); - - client.addListener('logMessage', this.consoleListener); - client.addListener('pageError', this.consoleListener); - client.addListener('consoleAPICall', this.consoleListener); - client.addListener('reflowActivity', this.consoleListener); - }, - - trackTarget(target) { - target.register('reflows'); - target.register('warnings'); - target.register('errors'); - target.register('security'); - - this._client.request({ - to: target.actor.consoleActor, - type: 'startListeners', - listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity'] - }, (res) => { - this._targets.set(target.actor.consoleActor, target); - }); - }, - - untrackTarget(target) { - this._client.request({ - to: target.actor.consoleActor, - type: 'stopListeners', - listeners: ['LogMessage', 'PageError', 'ConsoleAPI', 'ReflowActivity'] - }, (res) => { }); - - this._targets.delete(target.actor.consoleActor); - }, - - consoleListener(type, packet) { - let target = this._targets.get(packet.from); - let metric = {}; - let output = ''; - - switch (packet.type) { - - case 'pageError': - let pageError = packet.pageError; - - if (pageError.warning || pageError.strict) { - metric.name = 'warnings'; - output += 'Warning ('; - } else { - metric.name = 'errors'; - output += 'Error ('; - } - - if (this._security.indexOf(pageError.category) > -1) { - metric.name = 'security'; - - // Telemetry sends the security error category not the - // count of security errors. - target._logHistogram({ - name: 'security_category', - value: pageError.category - }); - - // Indicate that the 'hud' security metric (the count of security - // errors) should not be sent as a telemetry metric since the - // security error category is being sent instead. - metric.skipTelemetry = true; - } - - let {errorMessage, sourceName, category, lineNumber, columnNumber} = pageError; - output += category + '): "' + (errorMessage.initial || errorMessage) + - '" in ' + sourceName + ':' + lineNumber + ':' + columnNumber; - break; - - case 'consoleAPICall': - switch (packet.message.level) { - - case 'error': - metric.name = 'errors'; - output += 'Error (console)'; - break; - - case 'warn': - metric.name = 'warnings'; - output += 'Warning (console)'; - break; - - case 'info': - this.handleTelemetryMessage(target, packet); - - // Currently, informational log entries are tracked only by - // telemetry. Nonetheless, for consistency, we continue here - // and let the function return normally, when it concludes 'info' - // entries are not being watched. - metric.name = 'info'; - break; - - default: - return; - } - break; - - case 'reflowActivity': - metric.name = 'reflows'; - - let {start, end, sourceURL, interruptible} = packet; - metric.interruptible = interruptible; - let duration = Math.round((end - start) * 100) / 100; - - // Record the reflow if the duration exceeds the threshold. - if (duration < this._reflowThreshold) { - return; - } - - output += 'Reflow: ' + duration + 'ms'; - if (sourceURL) { - output += ' ' + this.formatSourceURL(packet); - } - - // Telemetry also records reflow duration. - target._logHistogram({ - name: 'reflow_duration', - value: Math.round(duration) - }); - break; - - default: - return; - } - - if (developerHUD._telemetry) { - // Always record telemetry for these metrics. - if (metric.name === 'errors' || metric.name === 'warnings' || metric.name === 'reflows') { - let value = target.metrics.get(metric.name); - metric.value = (value || 0) + 1; - target._logHistogram(metric); - - // Telemetry has already been recorded. - metric.skipTelemetry = true; - - // If the metric is not being watched, persist the incremented value. - // If the metric is being watched, `target.bump` will increment the value - // of the metric and will persist the incremented value. - if (!this._watching[metric.name]) { - target.metrics.set(metric.name, metric.value); - } - } - } - - if (!this._watching[metric.name]) { - return; - } - - target.bump(metric, output); - }, - - formatSourceURL(packet) { - // Abbreviate source URL - let source = WebConsoleUtils.abbreviateSourceURL(packet.sourceURL); - - // Add function name and line number - let {functionName, sourceLine} = packet; - source = 'in ' + (functionName || '<anonymousFunction>') + - ', ' + source + ':' + sourceLine; - - return source; - }, - - handleTelemetryMessage(target, packet) { - if (!developerHUD._telemetry) { - return; - } - - // If this is a 'telemetry' log entry, create a telemetry metric from - // the log content. - let separator = '|'; - let logContent = packet.message.arguments.toString(); - - if (logContent.indexOf('telemetry') < 0) { - return; - } - - let telemetryData = logContent.split(separator); - - // Positions of the components of a telemetry log entry. - let TELEMETRY_IDENTIFIER_IDX = 0; - let NAME_IDX = 1; - let VALUE_IDX = 2; - let TYPE_IDX = 2; - let MIN_IDX = 3; - let MAX_IDX = 4; - let BUCKETS_IDX = 5; - let MAX_CUSTOM_ARGS = 6; - let MIN_CUSTOM_ARGS = 3; - - if (telemetryData[TELEMETRY_IDENTIFIER_IDX] != 'telemetry' || - telemetryData.length < MIN_CUSTOM_ARGS || - telemetryData.length > MAX_CUSTOM_ARGS) { - return; - } - - let metric = { - name: telemetryData[NAME_IDX] - }; - - if (metric.name === 'MGMT') { - metric.value = telemetryData[VALUE_IDX]; - if (metric.value === 'TIMETOSHIP') { - telemetryDebug('Received a Ship event'); - target._sendTelemetryData(); - } else if (metric.value === 'CLEARMETRICS') { - target._clearTelemetryData(); - } - } else { - if (telemetryData.length === MIN_CUSTOM_ARGS) { - metric.value = telemetryData[VALUE_IDX]; - } else if (telemetryData.length === MAX_CUSTOM_ARGS) { - metric.type = telemetryData[TYPE_IDX]; - metric.min = telemetryData[MIN_IDX]; - metric.max = telemetryData[MAX_IDX]; - metric.buckets = telemetryData[BUCKETS_IDX]; - } - metric.custom = true; - target._logHistogram(metric); - } - } -}; -developerHUD.registerWatcher(consoleWatcher); - - -var eventLoopLagWatcher = { - _client: null, - _fronts: new Map(), - _active: false, - - init(client) { - this._client = client; - - SettingsListener.observe('hud.jank', false, this.settingsListener.bind(this)); - }, - - settingsListener(value) { - if (this._active == value) { - return; - } - - this._active = value; - - // Toggle the state of existing fronts. - let fronts = this._fronts; - for (let target of fronts.keys()) { - if (value) { - fronts.get(target).start(); - } else { - fronts.get(target).stop(); - target.clear({name: 'jank'}); - } - } - }, - - trackTarget(target) { - target.register('jank'); - - let front = new EventLoopLagFront(this._client, target.actor); - this._fronts.set(target, front); - - front.on('event-loop-lag', time => { - target.update({name: 'jank', value: time}, 'Jank: ' + time + 'ms'); - }); - - if (this._active) { - front.start(); - } - }, - - untrackTarget(target) { - let fronts = this._fronts; - if (fronts.has(target)) { - fronts.get(target).destroy(); - fronts.delete(target); - } - } -}; -developerHUD.registerWatcher(eventLoopLagWatcher); - -/* - * The performanceEntriesWatcher determines the delta between the epoch - * of an app's launch time and the epoch of the app's performance entry marks. - * When it receives an "appLaunch" performance entry mark it records the - * name of the app being launched and the epoch of when the launch ocurred. - * When it receives subsequent performance entry events for the app being - * launched, it records the delta of the performance entry opoch compared - * to the app-launch epoch and emits an "app-start-time-<performance mark name>" - * event containing the delta. - * - * Additionally, while recording the "app-start-time" for a performance mark, - * USS memory at the time of the performance mark is also recorded. - */ -var performanceEntriesWatcher = { - _client: null, - _fronts: new Map(), - _appLaunch: new Map(), - _supported: [ - 'contentInteractive', - 'navigationInteractive', - 'navigationLoaded', - 'visuallyLoaded', - 'fullyLoaded', - 'mediaEnumerated', - 'scanEnd' - ], - - init(client) { - this._client = client; - let setting = 'devtools.telemetry.supported_performance_marks'; - let defaultValue = this._supported.join(','); - - SettingsListener.observe(setting, defaultValue, supported => { - this._supported = supported.split(','); - }); - }, - - trackTarget(target) { - // The performanceEntries watcher doesn't register a metric because - // currently the metrics generated are not displayed in - // in the front-end. - - let front = new PerformanceEntriesFront(this._client, target.actor); - this._fronts.set(target, front); - - // User timings are always gathered; there is no setting to enable/ - // disable. - front.start(); - - front.on('entry', detail => { - - // Only process performance marks. - if (detail.type !== 'mark') { - return; - } - - let name = detail.name; - let epoch = detail.epoch; - - // If this is an "app launch" mark, record the app that was - // launched and the epoch of when it was launched. - if (name.indexOf('appLaunch') !== -1) { - let CHARS_UNTIL_APP_NAME = 7; // '@app://' - let startPos = name.indexOf('@app') + CHARS_UNTIL_APP_NAME; - let endPos = name.indexOf('.'); - let appName = name.slice(startPos, endPos); - this._appLaunch.set(appName, epoch); - return; - } - - // Only process supported performance marks - if (this._supported.indexOf(name) === -1) { - return; - } - - let origin = detail.origin; - origin = origin.slice(0, origin.indexOf('.')); - - let appLaunchTime = this._appLaunch.get(origin); - - // Sanity check: ensure we have an app launch time for the app - // corresponding to this performance mark. - if (!appLaunchTime) { - return; - } - - let time = epoch - appLaunchTime; - let eventName = 'app_startup_time_' + name; - - // Events based on performance marks are for telemetry only, they are - // not displayed in the HUD front end. - target._logHistogram({name: eventName, value: time}); - - memoryWatcher.front(target).residentUnique().then(value => { - // bug 1215277, need 'v2' for app-memory histograms - eventName = 'app_memory_' + name + '_v2'; - target._logHistogram({name: eventName, value: value}); - }, err => { - console.error(err); - }); - }); - }, - - untrackTarget(target) { - let fronts = this._fronts; - if (fronts.has(target)) { - fronts.get(target).destroy(); - fronts.delete(target); - } - } -}; -developerHUD.registerWatcher(performanceEntriesWatcher); - -/** - * The Memory Watcher uses devtools actors to track memory usage. - */ -var memoryWatcher = { - - _client: null, - _fronts: new Map(), - _timers: new Map(), - _watching: { - uss: false, - appmemory: false, - jsobjects: false, - jsstrings: false, - jsother: false, - dom: false, - style: false, - other: false - }, - _active: false, - - init(client) { - this._client = client; - let watching = this._watching; - - for (let key in watching) { - let category = key; - SettingsListener.observe('hud.' + category, false, watch => { - watching[category] = watch; - this.update(); - }); - } - }, - - update() { - let watching = this._watching; - let active = watching.appmemory || watching.uss; - - if (this._active) { - for (let target of this._fronts.keys()) { - if (!watching.appmemory) target.clear({name: 'memory'}); - if (!watching.uss) target.clear({name: 'uss'}); - if (!active) clearTimeout(this._timers.get(target)); - } - } else if (active) { - for (let target of this._fronts.keys()) { - this.measure(target); - } - } - this._active = active; - }, - - measure(target) { - let watch = this._watching; - let format = this.formatMemory; - - if (watch.uss) { - this.front(target).residentUnique().then(value => { - target.update({name: 'uss', value: value}, 'USS: ' + format(value)); - }, err => { - console.error(err); - }); - } - - if (watch.appmemory) { - front.measure().then(data => { - let total = 0; - let details = []; - - function item(name, condition, value) { - if (!condition) { - return; - } - - let v = parseInt(value); - total += v; - details.push(name + ': ' + format(v)); - } - - item('JS objects', watch.jsobjects, data.jsObjectsSize); - item('JS strings', watch.jsstrings, data.jsStringsSize); - item('JS other', watch.jsother, data.jsOtherSize); - item('DOM', watch.dom, data.domSize); - item('Style', watch.style, data.styleSize); - item('Other', watch.other, data.otherSize); - // TODO Also count images size (bug #976007). - - target.update({name: 'memory', value: total}, - 'App Memory: ' + format(total) + ' (' + details.join(', ') + ')'); - }, err => { - console.error(err); - }); - } - - let timer = setTimeout(() => this.measure(target), 2000); - this._timers.set(target, timer); - }, - - formatMemory(bytes) { - var prefix = ['','K','M','G','T','P','E','Z','Y']; - var i = 0; - for (; bytes > 1024 && i < prefix.length; ++i) { - bytes /= 1024; - } - return (Math.round(bytes * 100) / 100) + ' ' + prefix[i] + 'B'; - }, - - trackTarget(target) { - target.register('uss'); - target.register('memory'); - this._fronts.set(target, MemoryFront(this._client, target.actor)); - if (this._active) { - this.measure(target); - } - }, - - untrackTarget(target) { - let front = this._fronts.get(target); - if (front) { - front.destroy(); - clearTimeout(this._timers.get(target)); - this._fronts.delete(target); - this._timers.delete(target); - } - }, - - front(target) { - return this._fronts.get(target); - } -}; -developerHUD.registerWatcher(memoryWatcher); diff --git a/b2g/chrome/content/identity.js b/b2g/chrome/content/identity.js deleted file mode 100644 index 9c0ad50a2..000000000 --- a/b2g/chrome/content/identity.js +++ /dev/null @@ -1,166 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* 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/. */ - -// This JS shim contains the callbacks to fire DOMRequest events for -// navigator.pay API within the payment processor's scope. - -"use strict"; - -var { classes: Cc, interfaces: Ci, utils: Cu } = Components; -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyServiceGetter(this, "cpmm", - "@mozilla.org/childprocessmessagemanager;1", - "nsIMessageSender"); - -XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -XPCOMUtils.defineLazyModuleGetter(this, "Logger", - "resource://gre/modules/identity/LogUtils.jsm"); - -function log(...aMessageArgs) { - Logger.log.apply(Logger, ["injected identity.js"].concat(aMessageArgs)); -} - -log("\n\n======================= identity.js =======================\n\n"); - -// This script may be injected more than once into an iframe. -// It's hard to do this with |const| like we should, so use var instead. -if (typeof kIdentityJSLoaded === 'undefined') { - var kIdentityDelegateWatch = "identity-delegate-watch"; - var kIdentityDelegateRequest = "identity-delegate-request"; - var kIdentityDelegateLogout = "identity-delegate-logout"; - var kIdentityDelegateReady = "identity-delegate-ready"; - var kIdentityDelegateFinished = "identity-delegate-finished"; - var kIdentityControllerDoMethod = "identity-controller-doMethod"; - var kIdentktyJSLoaded = true; -} - -var showUI = false; -var options = {}; -var isLoaded = false; -var func = null; - -/* - * Message back to the SignInToWebsite pipe. Message should be an - * object with the following keys: - * - * method: one of 'login', 'logout', 'ready' - * assertion: optional assertion - */ -function identityCall(message) { - if (options._internal) { - message._internal = options._internal; - } - sendAsyncMessage(kIdentityControllerDoMethod, message); -} - -/* - * To close the dialog, we first tell the gecko SignInToWebsite manager that it - * can clean up. Then we tell the gaia component that we are finished. It is - * necessary to notify gecko first, so that the message can be sent before gaia - * destroys our context. - */ -function closeIdentityDialog() { - // tell gecko we're done. - func = null; options = null; - sendAsyncMessage(kIdentityDelegateFinished); -} - -/* - * doInternalWatch - call the internal.watch api and relay the results - * up to the controller. - */ -function doInternalWatch() { - log("doInternalWatch:", options, isLoaded); - if (options && isLoaded) { - let BrowserID = content.wrappedJSObject.BrowserID; - BrowserID.internal.watch(function(aParams, aInternalParams) { - identityCall(aParams); - if (aParams.method === "ready") { - closeIdentityDialog(); - } - }, - JSON.stringify(options), - function(...things) { - // internal watch log callback - log("(watch) internal: ", things); - } - ); - } -} - -function doInternalRequest() { - log("doInternalRequest:", options && isLoaded); - if (options && isLoaded) { - var stringifiedOptions = JSON.stringify(options); - content.wrappedJSObject.BrowserID.internal.get( - options.origin, - function(assertion, internalParams) { - internalParams = internalParams || {}; - if (assertion) { - identityCall({ - method: 'login', - assertion: assertion, - _internalParams: internalParams}); - } else { - identityCall({ - method: 'cancel' - }); - } - closeIdentityDialog(); - }, - stringifiedOptions); - } -} -function doInternalLogout(aOptions) { - log("doInternalLogout:", (options && isLoaded)); - if (options && isLoaded) { - let BrowserID = content.wrappedJSObject.BrowserID; - BrowserID.internal.logout(options.origin, function() { - identityCall({method:'logout'}); - closeIdentityDialog(); - }); - } -} - -addEventListener("DOMContentLoaded", function(e) { - content.addEventListener("load", function(e) { - isLoaded = true; - // bring da func - if (func) func(); - }); -}); - -// listen for request -addMessageListener(kIdentityDelegateRequest, function(aMessage) { - log("injected identity.js received", kIdentityDelegateRequest); - options = aMessage.json; - showUI = true; - func = doInternalRequest; - func(); -}); - -// listen for watch -addMessageListener(kIdentityDelegateWatch, function(aMessage) { - log("injected identity.js received", kIdentityDelegateWatch); - options = aMessage.json; - showUI = false; - func = doInternalWatch; - func(); -}); - -// listen for logout -addMessageListener(kIdentityDelegateLogout, function(aMessage) { - log("injected identity.js received", kIdentityDelegateLogout); - options = aMessage.json; - showUI = false; - func = doInternalLogout; - func(); -}); diff --git a/b2g/chrome/content/images/arrowdown-16.png b/b2g/chrome/content/images/arrowdown-16.png Binary files differdeleted file mode 100644 index c982426f2..000000000 --- a/b2g/chrome/content/images/arrowdown-16.png +++ /dev/null diff --git a/b2g/chrome/content/images/arrowright-16.png b/b2g/chrome/content/images/arrowright-16.png Binary files differdeleted file mode 100644 index 859e98ba6..000000000 --- a/b2g/chrome/content/images/arrowright-16.png +++ /dev/null diff --git a/b2g/chrome/content/images/desktop/home-black.png b/b2g/chrome/content/images/desktop/home-black.png Binary files differdeleted file mode 100644 index c51187ed4..000000000 --- a/b2g/chrome/content/images/desktop/home-black.png +++ /dev/null diff --git a/b2g/chrome/content/images/desktop/home-white.png b/b2g/chrome/content/images/desktop/home-white.png Binary files differdeleted file mode 100644 index 43379d0e9..000000000 --- a/b2g/chrome/content/images/desktop/home-white.png +++ /dev/null diff --git a/b2g/chrome/content/images/desktop/rotate.png b/b2g/chrome/content/images/desktop/rotate.png Binary files differdeleted file mode 100644 index 9da1b5674..000000000 --- a/b2g/chrome/content/images/desktop/rotate.png +++ /dev/null diff --git a/b2g/chrome/content/images/error.png b/b2g/chrome/content/images/error.png Binary files differdeleted file mode 100644 index 58e37283a..000000000 --- a/b2g/chrome/content/images/error.png +++ /dev/null diff --git a/b2g/chrome/content/images/errorpage-larry-black.png b/b2g/chrome/content/images/errorpage-larry-black.png Binary files differdeleted file mode 100644 index 9f2e4a6e7..000000000 --- a/b2g/chrome/content/images/errorpage-larry-black.png +++ /dev/null diff --git a/b2g/chrome/content/images/errorpage-larry-white.png b/b2g/chrome/content/images/errorpage-larry-white.png Binary files differdeleted file mode 100644 index fc153c731..000000000 --- a/b2g/chrome/content/images/errorpage-larry-white.png +++ /dev/null diff --git a/b2g/chrome/content/images/errorpage-warning.png b/b2g/chrome/content/images/errorpage-warning.png Binary files differdeleted file mode 100644 index 8bf9d8e7d..000000000 --- a/b2g/chrome/content/images/errorpage-warning.png +++ /dev/null diff --git a/b2g/chrome/content/images/exitfullscreen-hdpi.png b/b2g/chrome/content/images/exitfullscreen-hdpi.png Binary files differdeleted file mode 100644 index 826e53408..000000000 --- a/b2g/chrome/content/images/exitfullscreen-hdpi.png +++ /dev/null diff --git a/b2g/chrome/content/images/fullscreen-hdpi.png b/b2g/chrome/content/images/fullscreen-hdpi.png Binary files differdeleted file mode 100644 index 980e78731..000000000 --- a/b2g/chrome/content/images/fullscreen-hdpi.png +++ /dev/null diff --git a/b2g/chrome/content/images/mute-hdpi.png b/b2g/chrome/content/images/mute-hdpi.png Binary files differdeleted file mode 100644 index 6daf7cf71..000000000 --- a/b2g/chrome/content/images/mute-hdpi.png +++ /dev/null diff --git a/b2g/chrome/content/images/pause-hdpi.png b/b2g/chrome/content/images/pause-hdpi.png Binary files differdeleted file mode 100644 index c7837f822..000000000 --- a/b2g/chrome/content/images/pause-hdpi.png +++ /dev/null diff --git a/b2g/chrome/content/images/play-hdpi.png b/b2g/chrome/content/images/play-hdpi.png Binary files differdeleted file mode 100644 index fd64f9697..000000000 --- a/b2g/chrome/content/images/play-hdpi.png +++ /dev/null diff --git a/b2g/chrome/content/images/scrubber-hdpi.png b/b2g/chrome/content/images/scrubber-hdpi.png Binary files differdeleted file mode 100644 index b965b73d5..000000000 --- a/b2g/chrome/content/images/scrubber-hdpi.png +++ /dev/null diff --git a/b2g/chrome/content/images/throbber.png b/b2g/chrome/content/images/throbber.png Binary files differdeleted file mode 100644 index c601ec80b..000000000 --- a/b2g/chrome/content/images/throbber.png +++ /dev/null diff --git a/b2g/chrome/content/images/unmute-hdpi.png b/b2g/chrome/content/images/unmute-hdpi.png Binary files differdeleted file mode 100644 index 5de342bda..000000000 --- a/b2g/chrome/content/images/unmute-hdpi.png +++ /dev/null diff --git a/b2g/chrome/content/netError.css b/b2g/chrome/content/netError.css deleted file mode 100644 index 59d06a00c..000000000 --- a/b2g/chrome/content/netError.css +++ /dev/null @@ -1,131 +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/. */ - -/* - * This defines the look-and-feel styling of the error pages. - * (see: netError.xhtml) - * - * Original styling by William Price <bugzilla@mob.rice.edu> - * Updated for mobile by: Wes Johnston <wjohnston@mozilla.com> - */ - -body { - margin: 0; - padding: 0 8px 8px; - font-family: "Nokia Sans", Tahoma, sans-serif !important; -} - -h1 { - font-size: 22px; -} - -h2 { - font-size: 16px; -} - -ul { - margin: 0px; - padding: 0px 0px 0px 1em; -} - -li { - margin: 0px; - padding: 8px 0px; -} - -#errorPage { - background-color: #CEE6F4; -} - -#errorPage.certerror { - background-color: #EFD400; -} - -#errorPage.blockedsite { - background-color: #BF0000; -} - -#errorTitle { - background: url("chrome://b2g/content/images/errorpage-warning.png") left center no-repeat; - /* Scaled by .666 of their actual size */ - background-size: 40px 40px; - background-origin: content-box; - min-height: 60px; - margin-left: auto; - margin-right: auto; - max-width: 500px; - margin-left: auto; - margin-right: auto; -} - -#errorPage.certerror #errorTitle { - background-image: url("chrome://b2g/content/images/errorpage-larry-black.png"); -} - -#errorPage.blockedsite #errorTitle { - background-image: url("chrome://b2g/content/images/errorpage-larry-white.png"); - color: white; -} - -.errorTitleText { - padding: 0px 0px 0px 50px; - display: inline-block; - vertical-align: middle -} - -#errorPageContainer { - background-color: white; - border: 1px solid #999999; - border-radius: 6px; - padding: 6px 20px 20px; - font-size: 14px; - max-width: 500px; - margin-left: auto; - margin-right: auto; -} - -#errorShortDesc > p:empty { - display: none; -} - -#errorShortDesc > p { - overflow: auto; - border-bottom: 1px solid #999999; - padding-bottom: 1em; -} - -#errorPage.blockedsite #errorShortDesc > p { - font-weight: bold; - border-bottom: none; - padding-bottom: 0px; -} - -#securityOverrideDiv { - padding-top: 10px; -} - -div[collapsed] { - padding-left: 15px; - background-image: url("chrome://b2g/content/images/arrowright-16.png"); - background-size: 11px 11px; - background-repeat: no-repeat; - background-position: left 0.3em; -} - -div[collapsed="true"] { - background-image: url("chrome://b2g/content/images/arrowright-16.png"); -} - -div[collapsed="false"] { - background-image: url("chrome://b2g/content/images/arrowdown-16.png"); -} - -div[collapsed="true"] > p, -div[collapsed="true"] > div { - display: none; -} - -button { - padding: 0.3em !important; -} diff --git a/b2g/chrome/content/screen.js b/b2g/chrome/content/screen.js deleted file mode 100644 index a893e8844..000000000 --- a/b2g/chrome/content/screen.js +++ /dev/null @@ -1,276 +0,0 @@ -// screen.js: -// Set the screen size, pixel density and scaling of the b2g client screen -// based on the --screen command-line option, if there is one. -// -// TODO: support multiple device pixels per CSS pixel -// - -var browserWindow = Services.wm.getMostRecentWindow("navigator:browser"); -var isMulet = "ResponsiveUI" in browserWindow; -Cu.import("resource://gre/modules/GlobalSimulatorScreen.jsm"); - -window.addEventListener('ContentStart', onStart); -window.addEventListener('SafeModeStart', onStart); - -// We do this on ContentStart and SafeModeStart because querying the -// displayDPI fails otherwise. -function onStart() { - // This is the toplevel <window> element - let shell = document.getElementById('shell'); - - // The <browser> element inside it - let browser = document.getElementById('systemapp'); - - // Figure out the native resolution of the screen - let windowUtils = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Components.interfaces.nsIDOMWindowUtils); - let hostDPI = windowUtils.displayDPI; - - let DEFAULT_SCREEN = '320x480'; - - // This is a somewhat random selection of named screens. - // Add more to this list when we support more hardware. - // Data from: http://en.wikipedia.org/wiki/List_of_displays_by_pixel_density - let screens = { - iphone: { - name: 'Apple iPhone', width:320, height:480, dpi:163 - }, - ipad: { - name: 'Apple iPad', width:1024, height:768, dpi:132 - }, - nexus_s: { - name: 'Samsung Nexus S', width:480, height:800, dpi:235 - }, - galaxy_s2: { - name: 'Samsung Galaxy SII (I9100)', width:480, height:800, dpi:219 - }, - galaxy_nexus: { - name: 'Samsung Galaxy Nexus', width:720, height:1280, dpi:316 - }, - galaxy_tab: { - name: 'Samsung Galaxy Tab 10.1', width:800, height:1280, dpi:149 - }, - wildfire: { - name: 'HTC Wildfire', width:240, height:320, dpi:125 - }, - tattoo: { - name: 'HTC Tattoo', width:240, height:320, dpi:143 - }, - salsa: { - name: 'HTC Salsa', width:320, height:480, dpi:170 - }, - chacha: { - name: 'HTC ChaCha', width:320, height:480, dpi:222 - }, - }; - - // Get the command line arguments that were passed to the b2g client - let args; - try { - let service = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"].getService(Ci.nsISupports); - args = service.wrappedJSObject.cmdLine; - } catch(e) {} - - let screenarg = null; - - // Get the --screen argument from the command line - try { - if (args) { - screenarg = args.handleFlagWithParam('screen', false); - } - - // Override default screen size with a pref - if (screenarg === null && Services.prefs.prefHasUserValue('b2g.screen.size')) { - screenarg = Services.prefs.getCharPref('b2g.screen.size'); - } - - // If there isn't one, use the default screen - if (screenarg === null) - screenarg = DEFAULT_SCREEN; - - // With no value, tell the user how to use it - if (screenarg == '') - usage(); - } - catch(e) { - // If getting the argument value fails, its an error - usage(); - } - - // Special case --screen=full goes into fullscreen mode - if (screenarg === 'full') { - shell.setAttribute('sizemode', 'fullscreen'); - return; - } - - let width, height, ratio = 1.0; - let lastResizedWidth; - - if (screenarg in screens) { - // If this is a named screen, get its data - let screen = screens[screenarg]; - width = screen.width; - height = screen.height; - ratio = screen.ratio; - } else { - // Otherwise, parse the resolution and density from the --screen value. - // The supported syntax is WIDTHxHEIGHT[@DPI] - let match = screenarg.match(/^(\d+)x(\d+)(@(\d+(\.\d+)?))?$/); - - // Display usage information on syntax errors - if (match == null) - usage(); - - // Convert strings to integers - width = parseInt(match[1], 10); - height = parseInt(match[2], 10); - if (match[4]) - ratio = parseFloat(match[4], 10); - - // If any of the values came out 0 or NaN or undefined, display usage - if (!width || !height || !ratio) { - usage(); - } - } - - Services.prefs.setCharPref('layout.css.devPixelsPerPx', - ratio == 1 ? -1 : ratio); - let defaultOrientation = width < height ? 'portrait' : 'landscape'; - GlobalSimulatorScreen.mozOrientation = GlobalSimulatorScreen.screenOrientation = defaultOrientation; - - function resize() { - GlobalSimulatorScreen.width = width; - GlobalSimulatorScreen.height = height; - - // Set the window width and height to desired size plus chrome - // Include the size of the toolbox displayed under the system app - let controls = document.getElementById('controls'); - let controlsHeight = controls ? controls.getBoundingClientRect().height : 0; - - if (isMulet) { - let tab = browserWindow.gBrowser.selectedTab; - let responsive = ResponsiveUIManager.getResponsiveUIForTab(tab); - responsive.setSize(width + 16*2, - height + controlsHeight + 61); - } else { - let chromewidth = window.outerWidth - window.innerWidth; - let chromeheight = window.outerHeight - window.innerHeight + controlsHeight; - - if (lastResizedWidth == width) { - return; - } - lastResizedWidth = width; - - window.resizeTo(width + chromewidth, - height + chromeheight); - } - - let frameWidth = width, frameHeight = height; - - // If the current app doesn't supports the current screen orientation - // still resize the window, but rotate its frame so that - // it is displayed rotated on the side - let shouldFlip = GlobalSimulatorScreen.mozOrientation != GlobalSimulatorScreen.screenOrientation; - - if (shouldFlip) { - frameWidth = height; - frameHeight = width; - } - - // Set the browser element to the full unscaled size of the screen - let style = browser.style; - style.transform = ''; - style.height = 'calc(100% - ' + controlsHeight + 'px)'; - style.bottom = controlsHeight; - - style.width = frameWidth + "px"; - style.height = frameHeight + "px"; - - if (shouldFlip) { - // Display the system app with a 90° clockwise rotation - let shift = Math.floor(Math.abs(frameWidth - frameHeight) / 2); - style.transform += - ' rotate(0.25turn) translate(-' + shift + 'px, -' + shift + 'px)'; - } - } - - // Resize on startup - resize(); - - // Catch manual resizes to update the internal device size. - window.onresize = function() { - let controls = document.getElementById('controls'); - let controlsHeight = controls ? controls.getBoundingClientRect().height : 0; - - width = window.innerWidth; - height = window.innerHeight - controlsHeight; - - queueResize(); - }; - - // Then resize on each rotation button click, - // or when the system app lock/unlock the orientation - Services.obs.addObserver(function orientationChangeListener(subject) { - let screen = subject.wrappedJSObject; - let { mozOrientation, screenOrientation } = screen; - - // If we have an orientation different than the current one, - // we switch the sizes - if (screenOrientation != defaultOrientation) { - let w = width; - width = height; - height = w; - } - defaultOrientation = screenOrientation; - - queueResize(); - }, 'simulator-adjust-window-size', false); - - // Queue resize request in order to prevent race and slowdowns - // by requesting resize multiple times per loop - let resizeTimeout; - function queueResize() { - if (resizeTimeout) { - clearTimeout(resizeTimeout); - } - resizeTimeout = setTimeout(function () { - resizeTimeout = null; - resize(); - }, 0); - } - - // A utility function like console.log() for printing to the terminal window - // Uses dump(), but enables it first, if necessary - function print() { - let dump_enabled = - Services.prefs.getBoolPref('browser.dom.window.dump.enabled'); - - if (!dump_enabled) - Services.prefs.setBoolPref('browser.dom.window.dump.enabled', true); - - dump(Array.prototype.join.call(arguments, ' ') + '\n'); - - if (!dump_enabled) - Services.prefs.setBoolPref('browser.dom.window.dump.enabled', false); - } - - // Print usage info for --screen and exit - function usage() { - // Documentation for the --screen argument - let msg = - 'The --screen argument specifies the desired resolution and\n' + - 'pixel density of the simulated device screen. Use it like this:\n' + - '\t--screen=WIDTHxHEIGHT\t\t\t// E.g.: --screen=320x480\n' + - '\t--screen=WIDTHxHEIGHT@DOTS_PER_INCH\t// E.g.: --screen=480x800@250\n' + - '\t--screen=full\t\t\t\t// run in fullscreen mode\n' + - '\nYou can also specify certain device names:\n'; - for(let p in screens) - msg += '\t--screen=' + p + '\t// ' + screens[p].name + '\n'; - - // Display the usage message - print(msg); - - // Exit the b2g client - Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit); - } -} diff --git a/b2g/chrome/content/settings.js b/b2g/chrome/content/settings.js deleted file mode 100644 index 95921da4c..000000000 --- a/b2g/chrome/content/settings.js +++ /dev/null @@ -1,698 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* 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"; - -window.performance.mark('gecko-settings-loadstart'); - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; -var Cr = Components.results; - -// The load order is important here SettingsRequestManager _must_ be loaded -// prior to using SettingsListener otherwise there is a race in acquiring the -// lock and fulfilling it. If we ever move SettingsListener or this file down in -// the load order of shell.html things will likely break. -Cu.import('resource://gre/modules/SettingsRequestManager.jsm'); -Cu.import('resource://gre/modules/XPCOMUtils.jsm'); -Cu.import('resource://gre/modules/Services.jsm'); -Cu.import('resource://gre/modules/AppConstants.jsm'); - -const isGonk = AppConstants.platform === 'gonk'; - -if (isGonk) { - XPCOMUtils.defineLazyGetter(this, "libcutils", function () { - Cu.import("resource://gre/modules/systemlibs.js"); - return libcutils; - }); -} - -XPCOMUtils.defineLazyServiceGetter(this, "uuidgen", - "@mozilla.org/uuid-generator;1", - "nsIUUIDGenerator"); - -// Once Bug 731746 - Allow chrome JS object to implement nsIDOMEventTarget -// is resolved this helper could be removed. -var SettingsListener = { - _callbacks: {}, - - init: function sl_init() { - if ('mozSettings' in navigator && navigator.mozSettings) { - navigator.mozSettings.onsettingchange = this.onchange.bind(this); - } - }, - - onchange: function sl_onchange(evt) { - var callback = this._callbacks[evt.settingName]; - if (callback) { - callback(evt.settingValue); - } - }, - - observe: function sl_observe(name, defaultValue, callback) { - var settings = window.navigator.mozSettings; - if (!settings) { - window.setTimeout(function() { callback(defaultValue); }); - return; - } - - if (!callback || typeof callback !== 'function') { - throw new Error('Callback is not a function'); - } - - var req = settings.createLock().get(name); - req.addEventListener('success', (function onsuccess() { - callback(typeof(req.result[name]) != 'undefined' ? - req.result[name] : defaultValue); - })); - - this._callbacks[name] = callback; - } -}; - -SettingsListener.init(); - -// =================== Mono Audio ====================== - -SettingsListener.observe('accessibility.monoaudio.enable', false, function(value) { - Services.prefs.setBoolPref('accessibility.monoaudio.enable', value); -}); - -// =================== Console ====================== - -SettingsListener.observe('debug.console.enabled', true, function(value) { - Services.prefs.setBoolPref('consoleservice.enabled', value); - Services.prefs.setBoolPref('layout.css.report_errors', value); -}); - -SettingsListener.observe('homescreen.manifestURL', 'Sentinel Value' , function(value) { - Services.prefs.setCharPref('dom.mozApps.homescreenURL', value); -}); - -// =================== Languages ==================== -SettingsListener.observe('language.current', 'en-US', function(value) { - Services.prefs.setCharPref('general.useragent.locale', value); - - let prefName = 'intl.accept_languages'; - let defaultBranch = Services.prefs.getDefaultBranch(null); - - let intl = ''; - try { - intl = defaultBranch.getComplexValue(prefName, - Ci.nsIPrefLocalizedString).data; - } catch(e) {} - - // Bug 830782 - Homescreen is in English instead of selected locale after - // the first run experience. - // In order to ensure the current intl value is reflected on the child - // process let's always write a user value, even if this one match the - // current localized pref value. - if (!((new RegExp('^' + value + '[^a-z-_] *[,;]?', 'i')).test(intl))) { - value = value + ', ' + intl; - } else { - value = intl; - } - Services.prefs.setCharPref(prefName, value); - - if (shell.hasStarted() == false) { - shell.bootstrap(); - } -}); - -// =================== RIL ==================== -(function RILSettingsToPrefs() { - // DSDS default service IDs - ['mms', 'sms', 'telephony'].forEach(function(key) { - SettingsListener.observe('ril.' + key + '.defaultServiceId', 0, - function(value) { - if (value != null) { - Services.prefs.setIntPref('dom.' + key + '.defaultServiceId', value); - } - }); - }); -})(); - -//=================== DeviceInfo ==================== -Components.utils.import('resource://gre/modules/XPCOMUtils.jsm'); -Components.utils.import('resource://gre/modules/ctypes.jsm'); -(function DeviceInfoToSettings() { - // MOZ_B2G_VERSION is set in b2g/confvars.sh, and is output as a #define value - // from configure.in, defaults to 1.0.0 if this value is not exist. - let os_version = AppConstants.MOZ_B2G_VERSION; - let os_name = AppConstants.MOZ_B2G_OS_NAME; - - let appInfo = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsIXULAppInfo); - - // Get the hardware info and firmware revision from device properties. - let hardware_info = null; - let firmware_revision = null; - let product_manufacturer = null; - let product_model = null; - let product_device = null; - let build_number = null; - if (isGonk) { - hardware_info = libcutils.property_get('ro.hardware'); - firmware_revision = libcutils.property_get('ro.firmware_revision'); - product_manufacturer = libcutils.property_get('ro.product.manufacturer'); - product_model = libcutils.property_get('ro.product.model'); - product_device = libcutils.property_get('ro.product.device'); - build_number = libcutils.property_get('ro.build.version.incremental'); - } - - // Populate deviceinfo settings, - // copying any existing deviceinfo.os into deviceinfo.previous_os - let lock = window.navigator.mozSettings.createLock(); - let req = lock.get('deviceinfo.os'); - req.onsuccess = req.onerror = () => { - let previous_os = req.result && req.result['deviceinfo.os'] || ''; - let software = os_name + ' ' + os_version; - let setting = { - 'deviceinfo.build_number': build_number, - 'deviceinfo.os': os_version, - 'deviceinfo.previous_os': previous_os, - 'deviceinfo.software': software, - 'deviceinfo.platform_version': appInfo.platformVersion, - 'deviceinfo.platform_build_id': appInfo.platformBuildID, - 'deviceinfo.hardware': hardware_info, - 'deviceinfo.firmware_revision': firmware_revision, - 'deviceinfo.product_manufacturer': product_manufacturer, - 'deviceinfo.product_model': product_model, - 'deviceinfo.product_device': product_device - } - lock.set(setting); - } -})(); - -// =================== DevTools ==================== - -var developerHUD; -SettingsListener.observe('devtools.overlay', false, (value) => { - if (value) { - if (!developerHUD) { - let scope = {}; - Services.scriptloader.loadSubScript('chrome://b2g/content/devtools/hud.js', scope); - developerHUD = scope.developerHUD; - } - developerHUD.init(); - } else { - if (developerHUD) { - developerHUD.uninit(); - } - } -}); - -if (isGonk) { - var LogShake; - (function() { - let scope = {}; - Cu.import('resource://gre/modules/LogShake.jsm', scope); - LogShake = scope.LogShake; - LogShake.init(); - })(); - - SettingsListener.observe('devtools.logshake.enabled', false, value => { - if (value) { - LogShake.enableDeviceMotionListener(); - } else { - LogShake.disableDeviceMotionListener(); - } - }); - - SettingsListener.observe('devtools.logshake.qa_enabled', false, value => { - if (value) { - LogShake.enableQAMode(); - } else { - LogShake.disableQAMode(); - } - }); -} - -// =================== Device Storage ==================== -SettingsListener.observe('device.storage.writable.name', 'sdcard', function(value) { - if (Services.prefs.getPrefType('device.storage.writable.name') != Ci.nsIPrefBranch.PREF_STRING) { - // We clear the pref because it used to be erroneously written as a bool - // and we need to clear it before we can change it to have the correct type. - Services.prefs.clearUserPref('device.storage.writable.name'); - } - Services.prefs.setCharPref('device.storage.writable.name', value); -}); - -// =================== Privacy ==================== -SettingsListener.observe('privacy.donottrackheader.value', 1, function(value) { - Services.prefs.setIntPref('privacy.donottrackheader.value', value); - // If the user specifically disallows tracking, we set the value of - // app.update.custom (update tracking ID) to an empty string. - if (value == 1) { - Services.prefs.setCharPref('app.update.custom', ''); - return; - } - // Otherwise, we assure that the update tracking ID exists. - setUpdateTrackingId(); -}); - -// =================== Crash Reporting ==================== -SettingsListener.observe('app.reportCrashes', 'ask', function(value) { - if (value == 'always') { - Services.prefs.setBoolPref('app.reportCrashes', true); - } else if (value == 'never') { - Services.prefs.setBoolPref('app.reportCrashes', false); - } else { - Services.prefs.clearUserPref('app.reportCrashes'); - } - // This preference is consulted during startup. - Services.prefs.savePrefFile(null); -}); - -// ================ Updates ================ -/** - * For tracking purposes some partners require us to add an UUID to the - * update URL. The update tracking ID will be an empty string if the - * do-not-track feature specifically disallows tracking and it is reseted - * to a different ID if the do-not-track value changes from disallow to allow. - */ -function setUpdateTrackingId() { - try { - let dntEnabled = Services.prefs.getBoolPref('privacy.donottrackheader.enabled'); - let dntValue = Services.prefs.getIntPref('privacy.donottrackheader.value'); - // If the user specifically decides to disallow tracking (1), we just bail out. - if (dntEnabled && (dntValue == 1)) { - return; - } - - let trackingId = - Services.prefs.getPrefType('app.update.custom') == - Ci.nsIPrefBranch.PREF_STRING && - Services.prefs.getCharPref('app.update.custom'); - - // If there is no previous registered tracking ID, we generate a new one. - // This should only happen on first usage or after changing the - // do-not-track value from disallow to allow. - if (!trackingId) { - trackingId = uuidgen.generateUUID().toString().replace(/[{}]/g, ""); - Services.prefs.setCharPref('app.update.custom', trackingId); - } - } catch(e) { - dump('Error getting tracking ID ' + e + '\n'); - } -} -setUpdateTrackingId(); - -(function syncUpdatePrefs() { - // The update service reads the prefs from the default branch. This is by - // design, as explained in bug 302721 comment 43. If we are to successfully - // modify them, that's where we need to make our changes. - let defaultBranch = Services.prefs.getDefaultBranch(null); - - function syncPrefDefault(prefName) { - // The pref value at boot-time will serve as default for the setting. - let defaultValue = defaultBranch.getCharPref(prefName); - let defaultSetting = {}; - defaultSetting[prefName] = defaultValue; - - // We back up that value in order to detect pref changes across reboots. - // Such a change can happen e.g. when the user installs an OTA update that - // changes the update URL format. - let backupName = prefName + '.old'; - try { - // Everything relies on the comparison below: When pushing a new Gecko - // that changes app.update.url or app.update.channel, we overwrite any - // existing setting with the new pref value. - let backupValue = Services.prefs.getCharPref(backupName); - if (defaultValue !== backupValue) { - // If the pref has changed since our last backup, overwrite the setting. - navigator.mozSettings.createLock().set(defaultSetting); - } - } catch(e) { - // There was no backup: Overwrite the setting and create a backup below. - navigator.mozSettings.createLock().set(defaultSetting); - } - - // Initialize or update the backup value. - Services.prefs.setCharPref(backupName, defaultValue); - - // Propagate setting changes to the pref. - SettingsListener.observe(prefName, defaultValue, value => { - if (!value) { - // If the setting value is invalid, reset it to its default. - navigator.mozSettings.createLock().set(defaultSetting); - return; - } - // Here we will overwrite the pref with the setting value. - defaultBranch.setCharPref(prefName, value); - }); - } - - syncPrefDefault('app.update.url'); - syncPrefDefault('app.update.channel'); -})(); - -// ================ Debug ================ -(function Composer2DSettingToPref() { - //layers.composer.enabled can be enabled in three ways - //In order of precedence they are: - // - //1. mozSettings "layers.composer.enabled" - //2. a gecko pref "layers.composer.enabled" - //3. presence of ro.display.colorfill at the Gonk level - - var req = navigator.mozSettings.createLock().get('layers.composer2d.enabled'); - req.onsuccess = function() { - if (typeof(req.result['layers.composer2d.enabled']) === 'undefined') { - var enabled = false; - if (Services.prefs.getPrefType('layers.composer2d.enabled') == Ci.nsIPrefBranch.PREF_BOOL) { - enabled = Services.prefs.getBoolPref('layers.composer2d.enabled'); - } else if (isGonk) { - let androidVersion = libcutils.property_get("ro.build.version.sdk"); - if (androidVersion >= 17 ) { - enabled = true; - } else { - enabled = (libcutils.property_get('ro.display.colorfill') === '1'); - } - } - navigator.mozSettings.createLock().set({'layers.composer2d.enabled': enabled }); - } - - SettingsListener.observe("layers.composer2d.enabled", true, function(value) { - Services.prefs.setBoolPref("layers.composer2d.enabled", value); - }); - }; - req.onerror = function() { - dump("Error configuring layers.composer2d.enabled setting"); - }; - -})(); - -// ================ Accessibility ============ -(function setupAccessibility() { - let accessibilityScope = {}; - SettingsListener.observe("accessibility.screenreader", false, function(value) { - if (!value) { - return; - } - if (!('AccessFu' in accessibilityScope)) { - Cu.import('resource://gre/modules/accessibility/AccessFu.jsm', - accessibilityScope); - accessibilityScope.AccessFu.attach(window); - } - }); -})(); - -// ================ Theming ============ -(function themingSettingsListener() { - let themingPrefs = ['ui.menu', 'ui.menutext', 'ui.infobackground', 'ui.infotext', - 'ui.window', 'ui.windowtext', 'ui.highlight']; - - themingPrefs.forEach(function(pref) { - SettingsListener.observe('gaia.' + pref, null, function(value) { - if (value) { - Services.prefs.setCharPref(pref, value); - } - }); - }); -})(); - -// =================== Telemetry ====================== -(function setupTelemetrySettings() { - let gaiaSettingName = 'debug.performance_data.shared'; - let geckoPrefName = 'toolkit.telemetry.enabled'; - SettingsListener.observe(gaiaSettingName, null, function(value) { - if (value !== null) { - // Gaia setting has been set; update Gecko pref to that. - Services.prefs.setBoolPref(geckoPrefName, value); - return; - } - // Gaia setting has not been set; set the gaia setting to default. - let prefValue = AppConstants.MOZ_TELEMETRY_ON_BY_DEFAULT; - try { - prefValue = Services.prefs.getBoolPref(geckoPrefName); - } catch (e) { - // Pref not set; use default value. - } - let setting = {}; - setting[gaiaSettingName] = prefValue; - window.navigator.mozSettings.createLock().set(setting); - }); -})(); - -// =================== Low-precision buffer ====================== -(function setupLowPrecisionSettings() { - // The gaia setting layers.low-precision maps to two gecko prefs - SettingsListener.observe('layers.low-precision', null, function(value) { - if (value !== null) { - // Update gecko from the new Gaia setting - Services.prefs.setBoolPref('layers.low-precision-buffer', value); - Services.prefs.setBoolPref('layers.progressive-paint', value); - } else { - // Update gaia setting from gecko value - try { - let prefValue = Services.prefs.getBoolPref('layers.low-precision-buffer'); - let setting = { 'layers.low-precision': prefValue }; - window.navigator.mozSettings.createLock().set(setting); - } catch (e) { - console.log('Unable to read pref layers.low-precision-buffer: ' + e); - } - } - }); - - // The gaia setting layers.low-opacity maps to a string gecko pref (0.5/1.0) - SettingsListener.observe('layers.low-opacity', null, function(value) { - if (value !== null) { - // Update gecko from the new Gaia setting - Services.prefs.setCharPref('layers.low-precision-opacity', value ? '0.5' : '1.0'); - } else { - // Update gaia setting from gecko value - try { - let prefValue = Services.prefs.getCharPref('layers.low-precision-opacity'); - let setting = { 'layers.low-opacity': (prefValue == '0.5') }; - window.navigator.mozSettings.createLock().set(setting); - } catch (e) { - console.log('Unable to read pref layers.low-precision-opacity: ' + e); - } - } - }); -})(); - -// ======================= Dogfooders FOTA ========================== -if (AppConstants.MOZ_B2G_RIL) { - XPCOMUtils.defineLazyModuleGetter(this, "AppsUtils", - "resource://gre/modules/AppsUtils.jsm"); - - SettingsListener.observe('debug.performance_data.dogfooding', false, - isDogfooder => { - if (!isDogfooder) { - dump('AUS:Settings: Not a dogfooder!\n'); - return; - } - - if (!('mozTelephony' in navigator)) { - dump('AUS:Settings: There is no mozTelephony!\n'); - return; - } - - if (!('mozMobileConnections' in navigator)) { - dump('AUS:Settings: There is no mozMobileConnections!\n'); - return; - } - - let conn = navigator.mozMobileConnections[0]; - conn.addEventListener('radiostatechange', function onradiostatechange() { - if (conn.radioState !== 'enabled') { - return; - } - - conn.removeEventListener('radiostatechange', onradiostatechange); - navigator.mozTelephony.dial('*#06#').then(call => { - return call.result.then(res => { - if (res.success && res.statusMessage - && (res.serviceCode === 'scImei')) { - Services.prefs.setCharPref("app.update.imei_hash", - AppsUtils.computeHash(res.statusMessage, "SHA512")); - } - }); - }); - }); - }); -} - -// =================== Various simple mapping ====================== -var settingsToObserve = { - 'accessibility.screenreader_quicknav_modes': { - prefName: 'accessibility.accessfu.quicknav_modes', - resetToPref: true, - defaultValue: '' - }, - 'accessibility.screenreader_quicknav_index': { - prefName: 'accessibility.accessfu.quicknav_index', - resetToPref: true, - defaultValue: 0 - }, - 'app.update.interval': 86400, - 'apz.overscroll.enabled': true, - 'browser.safebrowsing.phishing.enabled': true, - 'browser.safebrowsing.malware.enabled': true, - 'debug.fps.enabled': { - prefName: 'layers.acceleration.draw-fps', - defaultValue: false - }, - 'debug.log-animations.enabled': { - prefName: 'layers.offmainthreadcomposition.log-animations', - defaultValue: false - }, - 'debug.paint-flashing.enabled': { - prefName: 'nglayout.debug.paint_flashing', - defaultValue: false - }, - // FIXME: Bug 1185806 - Provide a common device name setting. - // Borrow device name from developer's menu to avoid multiple name settings. - 'devtools.discovery.device': { - prefName: 'dom.presentation.device.name', - defaultValue: 'Firefox OS' - }, - 'devtools.eventlooplag.threshold': 100, - 'devtools.remote.wifi.visible': { - resetToPref: true - }, - 'devtools.telemetry.supported_performance_marks': { - resetToPref: true - }, - - 'dom.presentation.discovery.enabled': false, - 'dom.presentation.discoverable': false, - 'dom.serviceWorkers.testing.enabled': false, - 'gfx.layerscope.enabled': false, - 'layers.draw-borders': false, - 'layers.draw-tile-borders': false, - 'layers.dump': false, - 'layers.enable-tiles': AppConstants.platform !== "win", - 'layers.enable-tiles': true, - 'layers.effect.invert': false, - 'layers.effect.grayscale': false, - 'layers.effect.contrast': '0.0', - 'layout.display-list.dump': false, - 'mms.debugging.enabled': false, - 'network.debugging.enabled': false, - 'privacy.donottrackheader.enabled': false, - 'privacy.trackingprotection.enabled': false, - 'ril.debugging.enabled': false, - 'ril.radio.disabled': false, - 'ril.mms.requestReadReport.enabled': { - prefName: 'dom.mms.requestReadReport', - defaultValue: true - }, - 'ril.mms.requestStatusReport.enabled': { - prefName: 'dom.mms.requestStatusReport', - defaultValue: false - }, - 'ril.mms.retrieval_mode': { - prefName: 'dom.mms.retrieval_mode', - defaultValue: 'manual' - }, - 'ril.sms.requestStatusReport.enabled': { - prefName: 'dom.sms.requestStatusReport', - defaultValue: false - }, - 'ril.sms.strict7BitEncoding.enabled': { - prefName: 'dom.sms.strict7BitEncoding', - defaultValue: false - }, - 'ril.sms.maxReadAheadEntries': { - prefName: 'dom.sms.maxReadAheadEntries', - defaultValue: 7 - }, - 'services.sync.enabled': { - defaultValue: false, - notifyChange: true - }, - 'ui.touch.radius.leftmm': { - resetToPref: true - }, - 'ui.touch.radius.topmm': { - resetToPref: true - }, - 'ui.touch.radius.rightmm': { - resetToPref: true - }, - 'ui.touch.radius.bottommm': { - resetToPref: true - }, - 'ui.click_hold_context_menus.delay': { - resetToPref: true - }, - 'wap.UAProf.tagname': 'x-wap-profile', - 'wap.UAProf.url': '' -}; - -if (AppConstants.MOZ_GRAPHENE) { - // Restart required - settingsToObserve['layers.async-pan-zoom.enabled'] = false; -} - -function settingObserver(setPref, prefName, setting) { - return value => { - setPref(prefName, value); - if (setting.notifyChange) { - SystemAppProxy._sendCustomEvent('mozPrefChromeEvent', { - prefName: prefName, - value: value - }); - } - }; -} - -for (let key in settingsToObserve) { - let setting = settingsToObserve[key]; - - // Allow setting to contain flags redefining prefName and defaultValue. - let prefName = setting.prefName || key; - let defaultValue = setting.defaultValue; - if (defaultValue === undefined) { - defaultValue = setting; - } - - let prefs = Services.prefs; - - // If requested, reset setting value and defaultValue to the pref value. - if (setting.resetToPref) { - switch (prefs.getPrefType(prefName)) { - case Ci.nsIPrefBranch.PREF_BOOL: - defaultValue = prefs.getBoolPref(prefName); - break; - - case Ci.nsIPrefBranch.PREF_INT: - defaultValue = prefs.getIntPref(prefName); - break; - - case Ci.nsIPrefBranch.PREF_STRING: - defaultValue = prefs.getCharPref(prefName); - break; - } - - let setting = {}; - setting[key] = defaultValue; - window.navigator.mozSettings.createLock().set(setting); - } - - // Figure out the right setter function for this type of pref. - let setPref; - switch (typeof defaultValue) { - case 'boolean': - setPref = prefs.setBoolPref.bind(prefs); - break; - - case 'number': - setPref = prefs.setIntPref.bind(prefs); - break; - - case 'string': - setPref = prefs.setCharPref.bind(prefs); - break; - } - - SettingsListener.observe(key, defaultValue, - settingObserver(setPref, prefName, setting)); -}; diff --git a/b2g/chrome/content/shell.css b/b2g/chrome/content/shell.css deleted file mode 100644 index 34daafd99..000000000 --- a/b2g/chrome/content/shell.css +++ /dev/null @@ -1,81 +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/. */ - -html { - background: black; - overflow: hidden; - width: 100%; - height: 100%; - padding: 0 !important; -} -body { - margin: 0; - width: 100%; - height: 100%; - overflow: hidden; -} -iframe { - overflow: hidden; - height: 100%; - width: 100%; - border: none; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - z-index: 1; - -moz-user-select: none; -} - -%ifdef MOZ_GRAPHENE - -body.content-loaded > #installing { - display: none; -} - -#installing { - z-index: 2; - position: absolute; - left: 0; - top: 0; - right: 0; - bottom: 0; - width: 100%; - height: 100%; - display: flex; - justify-content: center; - align-items: center; - background-color: #F1C40F; - color: #FFF; -} - -.throbber { - width: 3px; - height: 3px; - border-radius: 100px; - background-color: #FFF; - animation-name: throbber; - animation-duration: 1500ms; - animation-iteration-count: infinite; - animation-timing-function: linear; -} - -#titlebar-buttonbox { - margin: 6px 7px; - -moz-appearance: -moz-window-button-box; -} - -@keyframes throbber{ - from { - transform: scale(0); - opacity: 0.4; - } - to { - transform: scale(400); - opacity: 0; - } -} - -%endif diff --git a/b2g/chrome/content/shell.html b/b2g/chrome/content/shell.html deleted file mode 100644 index 5507a65aa..000000000 --- a/b2g/chrome/content/shell.html +++ /dev/null @@ -1,66 +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 -#ifdef MOZ_GRAPHENE - macanimationtype="document" - fullscreenbutton="true" - chromemargin="0,0,0,0" -#endif - > - -<head> - <link rel="stylesheet" href="shell.css" type="text/css"> - <script type="text/javascript"> - <!-- Add raptor performance marker --> - window.performance.mark('gecko-shell-html-load'); - </script> - <script type="application/javascript;version=1.8" - src="chrome://b2g/content/settings.js"> </script> - <script type="application/javascript;version=1.8" - src="chrome://b2g/content/shell.js"> </script> - -#ifndef ANDROID -#ifndef MOZ_GRAPHENE - <!-- various task that has to happen only on desktop --> - <script type="application/javascript;version=1.8" - src="chrome://b2g/content/desktop.js"> </script> - <!-- this script handles the screen argument for desktop builds --> - <script type="application/javascript;version=1.8" - src="chrome://b2g/content/screen.js"> </script> -#endif -#else - <!-- this file is only loaded on Gonk to manage ADB state --> - <script type="application/javascript;version=1.8" - src="chrome://b2g/content/devtools/adb.js"> </script> -#endif - <!-- manages DevTools server state --> - <script type="application/javascript;version=1.8" - src="chrome://b2g/content/devtools/debugger.js"> </script> -</head> - <body id="container"> -#ifndef MOZ_GRAPHENE -#ifdef MOZ_WIDGET_COCOA - <!-- - If the document is empty at startup, we don't display the window - at all on Mac OS... - --> - <h1 id="placeholder">wtf mac os!</h1> -#endif -#else - <div id="titlebar-buttonbox"></div> - <div id="installing"> - <div class="throbber"></div> - <div class="message"></div> - </div> -#endif - <!-- The html:iframe containing the UI is created here. --> - </body> -</html> diff --git a/b2g/chrome/content/shell.js b/b2g/chrome/content/shell.js deleted file mode 100644 index d483f9a64..000000000 --- a/b2g/chrome/content/shell.js +++ /dev/null @@ -1,1308 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* 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.performance.mark('gecko-shell-loadstart'); - -Cu.import('resource://gre/modules/NotificationDB.jsm'); -Cu.import("resource://gre/modules/AppsUtils.jsm"); -Cu.import('resource://gre/modules/UserAgentOverrides.jsm'); -Cu.import('resource://gre/modules/Keyboard.jsm'); -Cu.import('resource://gre/modules/ErrorPage.jsm'); -Cu.import('resource://gre/modules/AlertsHelper.jsm'); -Cu.import('resource://gre/modules/SystemUpdateService.jsm'); - -if (isGonk) { - Cu.import('resource://gre/modules/NetworkStatsService.jsm'); - Cu.import('resource://gre/modules/ResourceStatsService.jsm'); -} - -// Identity -Cu.import('resource://gre/modules/SignInToWebsite.jsm'); -SignInToWebsiteController.init(); - -Cu.import('resource://gre/modules/FxAccountsMgmtService.jsm'); -Cu.import('resource://gre/modules/DownloadsAPI.jsm'); -Cu.import('resource://gre/modules/PresentationDeviceInfoManager.jsm'); -Cu.import('resource://gre/modules/AboutServiceWorkers.jsm'); - -XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", - "resource://gre/modules/SystemAppProxy.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "Screenshot", - "resource://gre/modules/Screenshot.jsm"); - -XPCOMUtils.defineLazyServiceGetter(Services, 'env', - '@mozilla.org/process/environment;1', - 'nsIEnvironment'); - -XPCOMUtils.defineLazyServiceGetter(Services, 'ss', - '@mozilla.org/content/style-sheet-service;1', - 'nsIStyleSheetService'); - -XPCOMUtils.defineLazyServiceGetter(this, 'gSystemMessenger', - '@mozilla.org/system-message-internal;1', - 'nsISystemMessagesInternal'); - -XPCOMUtils.defineLazyGetter(this, "ppmm", function() { - return Cc["@mozilla.org/parentprocessmessagemanager;1"] - .getService(Ci.nsIMessageListenerManager); -}); - -if (isGonk) { - XPCOMUtils.defineLazyGetter(this, "libcutils", function () { - Cu.import("resource://gre/modules/systemlibs.js"); - return libcutils; - }); -} - -XPCOMUtils.defineLazyServiceGetter(Services, 'captivePortalDetector', - '@mozilla.org/toolkit/captive-detector;1', - 'nsICaptivePortalDetector'); - -XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing", - "resource://gre/modules/SafeBrowsing.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "SafeMode", - "resource://gre/modules/SafeMode.jsm"); - -window.performance.measure('gecko-shell-jsm-loaded', 'gecko-shell-loadstart'); - -function debug(str) { - dump(' -*- Shell.js: ' + str + '\n'); -} - -const once = event => { - let target = shell.contentBrowser; - return new Promise((resolve, reject) => { - target.addEventListener(event, function gotEvent(evt) { - target.removeEventListener(event, gotEvent, false); - resolve(evt); - }, false); - }); -} - -function clearCache() { - let cache = Cc["@mozilla.org/netwerk/cache-storage-service;1"] - .getService(Ci.nsICacheStorageService); - cache.clear(); -} - -function clearCacheAndReload() { - // Reload the main frame with a cleared cache. - debug('Reloading ' + shell.contentBrowser.contentWindow.location); - clearCache(); - shell.contentBrowser.contentWindow.location.reload(true); - once('mozbrowserlocationchange').then( - evt => { - shell.sendEvent(window, "ContentStart"); - }); -} - -function restart() { - let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'] - .getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eForceQuit | Ci.nsIAppStartup.eRestart); -} - -function debugCrashReport(aStr) { - AppConstants.MOZ_CRASHREPORTER && dump('Crash reporter : ' + aStr); -} - -var shell = { - - get CrashSubmit() { - delete this.CrashSubmit; - if (AppConstants.MOZ_CRASHREPORTER) { - Cu.import("resource://gre/modules/CrashSubmit.jsm", this); - return this.CrashSubmit; - } else { - dump('Crash reporter : disabled at build time.'); - return this.CrashSubmit = null; - } - }, - - onlineForCrashReport: function shell_onlineForCrashReport() { - let wifiManager = navigator.mozWifiManager; - let onWifi = (wifiManager && - (wifiManager.connection.status == 'connected')); - return !Services.io.offline && onWifi; - }, - - reportCrash: function shell_reportCrash(isChrome, aCrashID) { - let crashID = aCrashID; - try { - // For chrome crashes, we want to report the lastRunCrashID. - if (isChrome) { - crashID = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsIXULRuntime).lastRunCrashID; - } - } catch(e) { - debugCrashReport('Failed to fetch crash id. Crash ID is "' + crashID - + '" Exception: ' + e); - } - - // Bail if there isn't a valid crashID. - if (!this.CrashSubmit || !crashID && !this.CrashSubmit.pendingIDs().length) { - return; - } - - // purge the queue. - this.CrashSubmit.pruneSavedDumps(); - - // check for environment affecting crash reporting - let env = Cc["@mozilla.org/process/environment;1"] - .getService(Ci.nsIEnvironment); - let shutdown = env.get("MOZ_CRASHREPORTER_SHUTDOWN"); - if (shutdown) { - let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] - .getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eForceQuit); - } - - let noReport = env.get("MOZ_CRASHREPORTER_NO_REPORT"); - if (noReport) { - return; - } - - try { - // Check if we should automatically submit this crash. - if (Services.prefs.getBoolPref('app.reportCrashes')) { - this.submitCrash(crashID); - } else { - this.deleteCrash(crashID); - } - } catch (e) { - debugCrashReport('Can\'t fetch app.reportCrashes. Exception: ' + e); - } - - // We can get here if we're just submitting old pending crashes. - // Check that there's a valid crashID so that we only notify the - // user if a crash just happened and not when we OOM. Bug 829477 - if (crashID) { - this.sendChromeEvent({ - type: "handle-crash", - crashID: crashID, - chrome: isChrome - }); - } - }, - - deleteCrash: function shell_deleteCrash(aCrashID) { - if (aCrashID) { - debugCrashReport('Deleting pending crash: ' + aCrashID); - shell.CrashSubmit.delete(aCrashID); - } - }, - - // this function submit the pending crashes. - // make sure you are online. - submitQueuedCrashes: function shell_submitQueuedCrashes() { - // submit the pending queue. - let pending = shell.CrashSubmit.pendingIDs(); - for (let crashid of pending) { - debugCrashReport('Submitting crash: ' + crashid); - shell.CrashSubmit.submit(crashid); - } - }, - - // This function submits a crash when we're online. - submitCrash: function shell_submitCrash(aCrashID) { - if (this.onlineForCrashReport()) { - this.submitQueuedCrashes(); - return; - } - - debugCrashReport('Not online, postponing.'); - - Services.obs.addObserver(function observer(subject, topic, state) { - let network = subject.QueryInterface(Ci.nsINetworkInfo); - if (network.state == Ci.nsINetworkInfo.NETWORK_STATE_CONNECTED - && network.type == Ci.nsINetworkInfo.NETWORK_TYPE_WIFI) { - shell.submitQueuedCrashes(); - - Services.obs.removeObserver(observer, topic); - } - }, "network-connection-state-changed", false); - }, - - get homeURL() { - try { - let homeSrc = Services.env.get('B2G_HOMESCREEN'); - if (homeSrc) - return homeSrc; - } catch (e) {} - - return Services.prefs.getCharPref('b2g.system_startup_url'); - }, - - get manifestURL() { - return Services.prefs.getCharPref('b2g.system_manifest_url'); - }, - - _started: false, - hasStarted: function shell_hasStarted() { - return this._started; - }, - - bootstrap: function() { - window.performance.mark('gecko-shell-bootstrap'); - - // Before anything, check if we want to start in safe mode. - SafeMode.check(window).then(() => { - let startManifestURL = - Cc['@mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap'] - .getService(Ci.nsISupports).wrappedJSObject.startManifestURL; - - // If --start-manifest hasn't been specified, we re-use the latest specified manifest. - // If it's the first launch, we will fallback to b2g.default.start_manifest_url - if (AppConstants.MOZ_GRAPHENE && !startManifestURL) { - try { - startManifestURL = Services.prefs.getCharPref("b2g.system_manifest_url"); - } catch(e) {} - } - - if (!startManifestURL) { - try { - startManifestURL = Services.prefs.getCharPref("b2g.default.start_manifest_url"); - } catch(e) {} - } - - if (startManifestURL) { - Cu.import('resource://gre/modules/Bootstraper.jsm'); - - if (AppConstants.MOZ_GRAPHENE && Bootstraper.isInstallRequired(startManifestURL)) { - // Installing the app my take some time. We don't want to keep the - // native window hidden. - showInstallScreen(); - } - - Bootstraper.ensureSystemAppInstall(startManifestURL) - .then(this.start.bind(this)) - .catch(Bootstraper.bailout); - } else { - this.start(); - } - }); - }, - - start: function shell_start() { - window.performance.mark('gecko-shell-start'); - this._started = true; - - // This forces the initialization of the cookie service before we hit the - // network. - // See bug 810209 - let cookies = Cc["@mozilla.org/cookieService;1"]; - - try { - let cr = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsICrashReporter); - // Dogfood id. We might want to remove it in the future. - // see bug 789466 - try { - let dogfoodId = Services.prefs.getCharPref('prerelease.dogfood.id'); - if (dogfoodId != "") { - cr.annotateCrashReport("Email", dogfoodId); - } - } - catch (e) { } - - if (isGonk) { - // Annotate crash report - let annotations = [ [ "Android_Hardware", "ro.hardware" ], - [ "Android_Device", "ro.product.device" ], - [ "Android_CPU_ABI2", "ro.product.cpu.abi2" ], - [ "Android_CPU_ABI", "ro.product.cpu.abi" ], - [ "Android_Manufacturer", "ro.product.manufacturer" ], - [ "Android_Brand", "ro.product.brand" ], - [ "Android_Model", "ro.product.model" ], - [ "Android_Board", "ro.product.board" ], - ]; - - annotations.forEach(function (element) { - cr.annotateCrashReport(element[0], libcutils.property_get(element[1])); - }); - - let androidVersion = libcutils.property_get("ro.build.version.sdk") + - "(" + libcutils.property_get("ro.build.version.codename") + ")"; - cr.annotateCrashReport("Android_Version", androidVersion); - - SettingsListener.observe("deviceinfo.os", "", function(value) { - try { - let cr = Cc["@mozilla.org/xre/app-info;1"] - .getService(Ci.nsICrashReporter); - cr.annotateCrashReport("B2G_OS_Version", value); - } catch(e) { } - }); - } - } catch(e) { - debugCrashReport('exception: ' + e); - } - - let homeURL = this.homeURL; - if (!homeURL) { - let msg = 'Fatal error during startup: No homescreen found: try setting B2G_HOMESCREEN'; - alert(msg); - return; - } - - let manifestURL = this.manifestURL; - // <html:iframe id="systemapp" - // mozbrowser="true" allowfullscreen="true" - // style="overflow: hidden; height: 100%; width: 100%; border: none;" - // src="data:text/html;charset=utf-8,%3C!DOCTYPE html>%3Cbody style='background:black;'>"/> - let systemAppFrame = - document.createElementNS('http://www.w3.org/1999/xhtml', 'html:iframe'); - systemAppFrame.setAttribute('id', 'systemapp'); - systemAppFrame.setAttribute('mozbrowser', 'true'); - systemAppFrame.setAttribute('mozapp', manifestURL); - systemAppFrame.setAttribute('allowfullscreen', 'true'); - systemAppFrame.setAttribute('src', 'blank.html'); - let container = document.getElementById('container'); - - if (AppConstants.platform == 'macosx') { - // See shell.html - let hotfix = document.getElementById('placeholder'); - if (hotfix) { - container.removeChild(hotfix); - } - } - - this.contentBrowser = container.appendChild(systemAppFrame); - - let webNav = systemAppFrame.contentWindow - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation); - webNav.sessionHistory = Cc["@mozilla.org/browser/shistory;1"].createInstance(Ci.nsISHistory); - - if (AppConstants.MOZ_GRAPHENE) { - webNav.QueryInterface(Ci.nsIDocShell).windowDraggingAllowed = true; - } - - let audioChannels = systemAppFrame.allowedAudioChannels; - audioChannels && audioChannels.forEach(function(audioChannel) { - // Set all audio channels as unmuted by default - // because some audio in System app will be played - // before AudioChannelService[1] is Gaia is loaded. - // [1]: https://github.com/mozilla-b2g/gaia/blob/master/apps/system/js/audio_channel_service.js - audioChannel.setMuted(false); - }); - - // On firefox mulet, shell.html is loaded in a tab - // and we have to listen on the chrome event handler - // to catch key events - let chromeEventHandler = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShell) - .chromeEventHandler || window; - // Capture all key events so we can filter out hardware buttons - // And send them to Gaia via mozChromeEvents. - // Ideally, hardware buttons wouldn't generate key events at all, or - // if they did, they would use keycodes that conform to DOM 3 Events. - // See discussion in https://bugzilla.mozilla.org/show_bug.cgi?id=762362 - chromeEventHandler.addEventListener('keydown', this, true); - chromeEventHandler.addEventListener('keyup', this, true); - - window.addEventListener('MozApplicationManifest', this); - window.addEventListener('MozAfterPaint', this); - window.addEventListener('sizemodechange', this); - window.addEventListener('unload', this); - this.contentBrowser.addEventListener('mozbrowserloadstart', this, true); - this.contentBrowser.addEventListener('mozbrowserscrollviewchange', this, true); - this.contentBrowser.addEventListener('mozbrowsercaretstatechanged', this); - - CustomEventManager.init(); - UserAgentOverrides.init(); - CaptivePortalLoginHelper.init(); - - this.contentBrowser.src = homeURL; - - this._isEventListenerReady = false; - - window.performance.mark('gecko-shell-system-frame-set'); - - ppmm.addMessageListener("content-handler", this); - ppmm.addMessageListener("dial-handler", this); - ppmm.addMessageListener("sms-handler", this); - ppmm.addMessageListener("mail-handler", this); - ppmm.addMessageListener("file-picker", this); - - setTimeout(function() { - SafeBrowsing.init(); - }, 5000); - }, - - stop: function shell_stop() { - window.removeEventListener('unload', this); - window.removeEventListener('keydown', this, true); - window.removeEventListener('keyup', this, true); - window.removeEventListener('MozApplicationManifest', this); - window.removeEventListener('sizemodechange', this); - this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true); - this.contentBrowser.removeEventListener('mozbrowserscrollviewchange', this, true); - this.contentBrowser.removeEventListener('mozbrowsercaretstatechanged', this); - ppmm.removeMessageListener("content-handler", this); - - UserAgentOverrides.uninit(); - }, - - // If this key event represents a hardware button which needs to be send as - // a message, broadcasts it with the message set to 'xxx-button-press' or - // 'xxx-button-release'. - broadcastHardwareKeys: function shell_broadcastHardwareKeys(evt) { - let type; - let message; - - let mediaKeys = { - 'MediaTrackNext': 'media-next-track-button', - 'MediaTrackPrevious': 'media-previous-track-button', - 'MediaPause': 'media-pause-button', - 'MediaPlay': 'media-play-button', - 'MediaPlayPause': 'media-play-pause-button', - 'MediaStop': 'media-stop-button', - 'MediaRewind': 'media-rewind-button', - 'MediaFastForward': 'media-fast-forward-button' - }; - - if (evt.keyCode == evt.DOM_VK_F1) { - type = 'headset-button'; - message = 'headset-button'; - } else if (mediaKeys[evt.key]) { - type = 'media-button'; - message = mediaKeys[evt.key]; - } else { - return; - } - - switch (evt.type) { - case 'keydown': - message = message + '-press'; - break; - case 'keyup': - message = message + '-release'; - break; - } - - // Let applications receive the headset button and media key press/release message. - if (message !== this.lastHardwareButtonMessage) { - this.lastHardwareButtonMessage = message; - gSystemMessenger.broadcastMessage(type, message); - } - }, - - lastHardwareButtonMessage: null, // property for the hack above - visibleNormalAudioActive: false, - - handleEvent: function shell_handleEvent(evt) { - function checkReloadKey() { - if (evt.type !== 'keyup') { - return false; - } - - try { - let key = JSON.parse(Services.prefs.getCharPref('b2g.reload_key')); - return (evt.keyCode == key.key && - evt.ctrlKey == key.ctrl && - evt.altKey == key.alt && - evt.shiftKey == key.shift && - evt.metaKey == key.meta); - } catch(e) { - debug('Failed to get key: ' + e); - } - - return false; - } - - let content = this.contentBrowser.contentWindow; - switch (evt.type) { - case 'keydown': - case 'keyup': - if (checkReloadKey()) { - clearCacheAndReload(); - } else { - this.broadcastHardwareKeys(evt); - } - break; - case 'sizemodechange': - if (window.windowState == window.STATE_MINIMIZED && !this.visibleNormalAudioActive) { - this.contentBrowser.setVisible(false); - } else { - this.contentBrowser.setVisible(true); - } - break; - case 'load': - if (content.document.location == 'about:blank') { - return; - } - content.removeEventListener('load', this, true); - this.notifyContentWindowLoaded(); - break; - case 'mozbrowserloadstart': - if (content.document.location == 'about:blank') { - this.contentBrowser.addEventListener('mozbrowserlocationchange', this, true); - return; - } - - this.notifyContentStart(); - break; - case 'mozbrowserlocationchange': - if (content.document.location == 'about:blank') { - return; - } - - this.notifyContentStart(); - break; - case 'mozbrowserscrollviewchange': - this.sendChromeEvent({ - type: 'scrollviewchange', - detail: evt.detail, - }); - break; - case 'mozbrowsercaretstatechanged': - { - let elt = evt.target; - let win = elt.ownerDocument.defaultView; - let offsetX = win.mozInnerScreenX - window.mozInnerScreenX; - let offsetY = win.mozInnerScreenY - window.mozInnerScreenY; - - let rect = elt.getBoundingClientRect(); - offsetX += rect.left; - offsetY += rect.top; - - let data = evt.detail; - data.offsetX = offsetX; - data.offsetY = offsetY; - data.sendDoCommandMsg = null; - - shell.sendChromeEvent({ - type: 'caretstatechanged', - detail: data, - }); - } - break; - - case 'MozApplicationManifest': - try { - if (!Services.prefs.getBoolPref('browser.cache.offline.enable')) - return; - - let contentWindow = evt.originalTarget.defaultView; - let documentElement = contentWindow.document.documentElement; - if (!documentElement) - return; - - let manifest = documentElement.getAttribute('manifest'); - if (!manifest) - return; - - let principal = contentWindow.document.nodePrincipal; - if (Services.perms.testPermissionFromPrincipal(principal, 'offline-app') == Ci.nsIPermissionManager.UNKNOWN_ACTION) { - if (Services.prefs.getBoolPref('browser.offline-apps.notify')) { - // FIXME Bug 710729 - Add a UI for offline cache notifications - return; - } - return; - } - - Services.perms.addFromPrincipal(principal, 'offline-app', - Ci.nsIPermissionManager.ALLOW_ACTION); - - let documentURI = Services.io.newURI(contentWindow.document.documentURI, - null, - null); - let manifestURI = Services.io.newURI(manifest, null, documentURI); - let updateService = Cc['@mozilla.org/offlinecacheupdate-service;1'] - .getService(Ci.nsIOfflineCacheUpdateService); - updateService.scheduleUpdate(manifestURI, documentURI, principal, window); - } catch (e) { - dump('Error while creating offline cache: ' + e + '\n'); - } - break; - case 'MozAfterPaint': - window.removeEventListener('MozAfterPaint', this); - // This event should be sent before System app returns with - // system-message-listener-ready mozContentEvent, because it's on - // the critical launch path of the app. - SystemAppProxy._sendCustomEvent('mozChromeEvent', { - type: 'system-first-paint' - }, /* noPending */ true); - break; - case 'unload': - this.stop(); - break; - } - }, - - // Send an event to a specific window, document or element. - sendEvent: function shell_sendEvent(target, type, details) { - if (target === this.contentBrowser) { - // We must ask SystemAppProxy to send the event in this case so - // that event would be dispatched from frame.contentWindow instead of - // on the System app frame. - SystemAppProxy._sendCustomEvent(type, details); - return; - } - - let doc = target.document || target.ownerDocument || target; - let event = doc.createEvent('CustomEvent'); - event.initCustomEvent(type, true, true, details ? details : {}); - target.dispatchEvent(event); - }, - - sendCustomEvent: function shell_sendCustomEvent(type, details) { - SystemAppProxy._sendCustomEvent(type, details); - }, - - sendChromeEvent: function shell_sendChromeEvent(details) { - this.sendCustomEvent("mozChromeEvent", details); - }, - - receiveMessage: function shell_receiveMessage(message) { - var activities = { 'content-handler': { name: 'view', response: null }, - 'dial-handler': { name: 'dial', response: null }, - 'mail-handler': { name: 'new', response: null }, - 'sms-handler': { name: 'new', response: null }, - 'file-picker': { name: 'pick', response: 'file-picked' } }; - - if (!(message.name in activities)) - return; - - let data = message.data; - let activity = activities[message.name]; - - let a = new MozActivity({ - name: activity.name, - data: data - }); - - if (activity.response) { - a.onsuccess = function() { - let sender = message.target.QueryInterface(Ci.nsIMessageSender); - sender.sendAsyncMessage(activity.response, { success: true, - result: a.result }); - } - a.onerror = function() { - let sender = message.target.QueryInterface(Ci.nsIMessageSender); - sender.sendAsyncMessage(activity.response, { success: false }); - } - } - }, - - notifyContentStart: function shell_notifyContentStart() { - window.performance.mark('gecko-shell-notify-content-start'); - this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true); - this.contentBrowser.removeEventListener('mozbrowserlocationchange', this, true); - - let content = this.contentBrowser.contentWindow; - content.addEventListener('load', this, true); - - this.reportCrash(true); - - SystemAppProxy.registerFrame(shell.contentBrowser); - - this.sendEvent(window, 'ContentStart'); - - Services.obs.notifyObservers(null, 'content-start', null); - - if (AppConstants.MOZ_GRAPHENE && - Services.prefs.getBoolPref("b2g.nativeWindowGeometry.fullscreen")) { - window.fullScreen = true; - } - - shell.handleCmdLine(); - }, - - handleCmdLine: function() { - // This isn't supported on devices. - if (!isGonk) { - let b2gcmds = Cc["@mozilla.org/commandlinehandler/general-startup;1?type=b2gcmds"] - .getService(Ci.nsISupports); - let args = b2gcmds.wrappedJSObject.cmdLine; - try { - // Returns null if -url is not present. - let url = args.handleFlagWithParam("url", false); - if (url) { - this.sendChromeEvent({type: "mozbrowseropenwindow", url}); - args.preventDefault = true; - } - } catch(e) { - // Throws if -url is present with no params. - } - } - }, - - // This gets called when window.onload fires on the System app content window, - // which means things in <html> are parsed and statically referenced <script>s - // and <script defer>s are loaded and run. - notifyContentWindowLoaded: function shell_notifyContentWindowLoaded() { - isGonk && libcutils.property_set('sys.boot_completed', '1'); - - // This will cause Gonk Widget to remove boot animation from the screen - // and reveals the page. - Services.obs.notifyObservers(null, "browser-ui-startup-complete", ""); - - SystemAppProxy.setIsLoaded(); - }, - - // This gets called when the content sends us system-message-listener-ready - // mozContentEvent, OR when an observer message tell us we should consider - // the content as ready. - notifyEventListenerReady: function shell_notifyEventListenerReady() { - if (this._isEventListenerReady) { - Cu.reportError('shell.js: SystemApp has already been declared as being ready.'); - return; - } - this._isEventListenerReady = true; - - if (Services.prefs.getBoolPref('b2g.orientation.animate')) { - Cu.import('resource://gre/modules/OrientationChangeHandler.jsm'); - } - - SystemAppProxy.setIsReady(); - } -}; - -Services.obs.addObserver(function onFullscreenOriginChange(subject, topic, data) { - shell.sendChromeEvent({ type: "fullscreenoriginchange", - fullscreenorigin: data }); -}, "fullscreen-origin-change", false); - -Services.obs.addObserver(function onBluetoothVolumeChange(subject, topic, data) { - shell.sendChromeEvent({ - type: "bluetooth-volumeset", - value: data - }); -}, 'bluetooth-volume-change', false); - -Services.obs.addObserver(function(subject, topic, data) { - shell.sendCustomEvent('mozmemorypressure'); -}, 'memory-pressure', false); - -Services.obs.addObserver(function(subject, topic, data) { - shell.notifyEventListenerReady(); -}, 'system-message-listener-ready', false); - -var permissionMap = new Map([ - ['unknown', Services.perms.UNKNOWN_ACTION], - ['allow', Services.perms.ALLOW_ACTION], - ['deny', Services.perms.DENY_ACTION], - ['prompt', Services.perms.PROMPT_ACTION], -]); -var permissionMapRev = new Map(Array.from(permissionMap.entries()).reverse()); - -var CustomEventManager = { - init: function custevt_init() { - window.addEventListener("ContentStart", (function(evt) { - let content = shell.contentBrowser.contentWindow; - content.addEventListener("mozContentEvent", this, false, true); - }).bind(this), false); - }, - - handleEvent: function custevt_handleEvent(evt) { - let detail = evt.detail; - dump('XXX FIXME : Got a mozContentEvent: ' + detail.type + "\n"); - - switch(detail.type) { - case 'system-message-listener-ready': - Services.obs.notifyObservers(null, 'system-message-listener-ready', null); - break; - case 'captive-portal-login-cancel': - CaptivePortalLoginHelper.handleEvent(detail); - break; - case 'inputmethod-update-layouts': - case 'inputregistry-add': - case 'inputregistry-remove': - KeyboardHelper.handleEvent(detail); - break; - case 'copypaste-do-command': - Services.obs.notifyObservers({ wrappedJSObject: shell.contentBrowser }, - 'ask-children-to-execute-copypaste-command', detail.cmd); - break; - case 'add-permission': - Services.perms.add(Services.io.newURI(detail.uri, null, null), - detail.permissionType, permissionMap.get(detail.permission)); - break; - case 'remove-permission': - Services.perms.remove(Services.io.newURI(detail.uri, null, null), - detail.permissionType); - break; - case 'test-permission': - let result = Services.perms.testExactPermission( - Services.io.newURI(detail.uri, null, null), detail.permissionType); - // Not equal check here because we want to prevent default only if it's not set - if (result !== permissionMapRev.get(detail.permission)) { - evt.preventDefault(); - } - break; - case 'shutdown-application': - let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'] - .getService(Ci.nsIAppStartup); - appStartup.quit(appStartup.eAttemptQuit); - break; - case 'toggle-fullscreen-native-window': - window.fullScreen = !window.fullScreen; - Services.prefs.setBoolPref("b2g.nativeWindowGeometry.fullscreen", - window.fullScreen); - break; - case 'minimize-native-window': - window.minimize(); - break; - case 'clear-cache-and-reload': - clearCacheAndReload(); - break; - case 'clear-cache-and-restart': - clearCache(); - restart(); - break; - case 'restart': - restart(); - break; - } - } -} - -var KeyboardHelper = { - handleEvent: function keyboard_handleEvent(detail) { - switch (detail.type) { - case 'inputmethod-update-layouts': - Keyboard.setLayouts(detail.layouts); - - break; - case 'inputregistry-add': - case 'inputregistry-remove': - Keyboard.inputRegistryGlue.returnMessage(detail); - - break; - } - } -}; - -// This is the backend for Gaia's screenshot feature. Gaia requests a -// screenshot by sending a mozContentEvent with detail.type set to -// 'take-screenshot'. Then we take a screenshot and send a -// mozChromeEvent with detail.type set to 'take-screenshot-success' -// and detail.file set to the an image/png blob -window.addEventListener('ContentStart', function ss_onContentStart() { - let content = shell.contentBrowser.contentWindow; - content.addEventListener('mozContentEvent', function ss_onMozContentEvent(e) { - if (e.detail.type !== 'take-screenshot') - return; - - try { - shell.sendChromeEvent({ - type: 'take-screenshot-success', - file: Screenshot.get() - }); - } catch (e) { - dump('exception while creating screenshot: ' + e + '\n'); - shell.sendChromeEvent({ - type: 'take-screenshot-error', - error: String(e) - }); - } - }); -}); - -(function contentCrashTracker() { - Services.obs.addObserver(function(aSubject, aTopic, aData) { - let props = aSubject.QueryInterface(Ci.nsIPropertyBag2); - if (props.hasKey("abnormal") && props.hasKey("dumpID")) { - shell.reportCrash(false, props.getProperty("dumpID")); - } - }, - "ipc:content-shutdown", false); -})(); - -var CaptivePortalLoginHelper = { - init: function init() { - Services.obs.addObserver(this, 'captive-portal-login', false); - Services.obs.addObserver(this, 'captive-portal-login-abort', false); - Services.obs.addObserver(this, 'captive-portal-login-success', false); - }, - handleEvent: function handleEvent(detail) { - Services.captivePortalDetector.cancelLogin(detail.id); - }, - observe: function observe(subject, topic, data) { - shell.sendChromeEvent(JSON.parse(data)); - } -} - -// Listen for crashes submitted through the crash reporter UI. -window.addEventListener('ContentStart', function cr_onContentStart() { - let content = shell.contentBrowser.contentWindow; - content.addEventListener("mozContentEvent", function cr_onMozContentEvent(e) { - if (e.detail.type == "submit-crash" && e.detail.crashID) { - debugCrashReport("submitting crash at user request ", e.detail.crashID); - shell.submitCrash(e.detail.crashID); - } else if (e.detail.type == "delete-crash" && e.detail.crashID) { - debugCrashReport("deleting crash at user request ", e.detail.crashID); - shell.deleteCrash(e.detail.crashID); - } - }); -}); - -window.addEventListener('ContentStart', function update_onContentStart() { - if (!AppConstants.MOZ_UPDATER) { - return; - } - - let promptCc = Cc["@mozilla.org/updates/update-prompt;1"]; - if (!promptCc) { - return; - } - - let updatePrompt = promptCc.createInstance(Ci.nsIUpdatePrompt); - if (!updatePrompt) { - return; - } - - updatePrompt.wrappedJSObject.handleContentStart(shell); -}); -/* The "GPSChipOn" is to indicate that GPS engine is turned ON by the modem. - During this GPS engine is turned ON by the modem, we make the location tracking icon visible to user. - Once GPS engine is turned OFF, the location icon will disappear. - If GPS engine is not turned ON by the modem or GPS location service is triggered, - we let GPS service take over the control of showing the location tracking icon. - The regular sequence of the geolocation-device-events is: starting-> GPSStarting-> shutdown-> GPSShutdown -*/ - - -(function geolocationStatusTracker() { - let gGeolocationActive = false; - let GPSChipOn = false; - - Services.obs.addObserver(function(aSubject, aTopic, aData) { - let oldState = gGeolocationActive; - let promptWarning = false; - switch (aData) { - case "GPSStarting": - if (!gGeolocationActive) { - gGeolocationActive = true; - GPSChipOn = true; - promptWarning = true; - } - break; - case "GPSShutdown": - if (GPSChipOn) { - gGeolocationActive = false; - GPSChipOn = false; - } - break; - case "starting": - gGeolocationActive = true; - GPSChipOn = false; - break; - case "shutdown": - gGeolocationActive = false; - break; - } - - if (gGeolocationActive != oldState) { - shell.sendChromeEvent({ - type: 'geolocation-status', - active: gGeolocationActive, - prompt: promptWarning - }); - } -}, "geolocation-device-events", false); -})(); - -(function headphonesStatusTracker() { - Services.obs.addObserver(function(aSubject, aTopic, aData) { - shell.sendChromeEvent({ - type: 'headphones-status-changed', - state: aData - }); -}, "headphones-status-changed", false); -})(); - -(function audioChannelChangedTracker() { - Services.obs.addObserver(function(aSubject, aTopic, aData) { - shell.sendChromeEvent({ - type: 'audio-channel-changed', - channel: aData - }); -}, "audio-channel-changed", false); -})(); - -(function defaultVolumeChannelChangedTracker() { - Services.obs.addObserver(function(aSubject, aTopic, aData) { - shell.sendChromeEvent({ - type: 'default-volume-channel-changed', - channel: aData - }); -}, "default-volume-channel-changed", false); -})(); - -(function visibleAudioChannelChangedTracker() { - Services.obs.addObserver(function(aSubject, aTopic, aData) { - shell.sendChromeEvent({ - type: 'visible-audio-channel-changed', - channel: aData - }); - shell.visibleNormalAudioActive = (aData == 'normal'); -}, "visible-audio-channel-changed", false); -})(); - -(function recordingStatusTracker() { - // Recording status is tracked per process with following data structure: - // {<processId>: {<requestURL>: {isApp: <isApp>, - // count: <N>, - // audioCount: <N>, - // videoCount: <N>}} - let gRecordingActiveProcesses = {}; - - let recordingHandler = function(aSubject, aTopic, aData) { - let props = aSubject.QueryInterface(Ci.nsIPropertyBag2); - let processId = (props.hasKey('childID')) ? props.get('childID') - : 'main'; - if (processId && !gRecordingActiveProcesses.hasOwnProperty(processId)) { - gRecordingActiveProcesses[processId] = {}; - } - - let commandHandler = function (requestURL, command) { - let currentProcess = gRecordingActiveProcesses[processId]; - let currentActive = currentProcess[requestURL]; - let wasActive = (currentActive['count'] > 0); - let wasAudioActive = (currentActive['audioCount'] > 0); - let wasVideoActive = (currentActive['videoCount'] > 0); - - switch (command.type) { - case 'starting': - currentActive['count']++; - currentActive['audioCount'] += (command.isAudio) ? 1 : 0; - currentActive['videoCount'] += (command.isVideo) ? 1 : 0; - break; - case 'shutdown': - currentActive['count']--; - currentActive['audioCount'] -= (command.isAudio) ? 1 : 0; - currentActive['videoCount'] -= (command.isVideo) ? 1 : 0; - break; - case 'content-shutdown': - currentActive['count'] = 0; - currentActive['audioCount'] = 0; - currentActive['videoCount'] = 0; - break; - } - - if (currentActive['count'] > 0) { - currentProcess[requestURL] = currentActive; - } else { - delete currentProcess[requestURL]; - } - - // We need to track changes if any active state is changed. - let isActive = (currentActive['count'] > 0); - let isAudioActive = (currentActive['audioCount'] > 0); - let isVideoActive = (currentActive['videoCount'] > 0); - if ((isActive != wasActive) || - (isAudioActive != wasAudioActive) || - (isVideoActive != wasVideoActive)) { - shell.sendChromeEvent({ - type: 'recording-status', - active: isActive, - requestURL: requestURL, - isApp: currentActive['isApp'], - isAudio: isAudioActive, - isVideo: isVideoActive - }); - } - }; - - switch (aData) { - case 'starting': - case 'shutdown': - // create page record if it is not existed yet. - let requestURL = props.get('requestURL'); - if (requestURL && - !gRecordingActiveProcesses[processId].hasOwnProperty(requestURL)) { - gRecordingActiveProcesses[processId][requestURL] = {isApp: props.get('isApp'), - count: 0, - audioCount: 0, - videoCount: 0}; - } - commandHandler(requestURL, { type: aData, - isAudio: props.get('isAudio'), - isVideo: props.get('isVideo')}); - break; - case 'content-shutdown': - // iterate through all the existing active processes - Object.keys(gRecordingActiveProcesses[processId]).forEach(function(requestURL) { - commandHandler(requestURL, { type: aData, - isAudio: true, - isVideo: true}); - }); - break; - } - - // clean up process record if no page record in it. - if (Object.keys(gRecordingActiveProcesses[processId]).length == 0) { - delete gRecordingActiveProcesses[processId]; - } - }; - Services.obs.addObserver(recordingHandler, 'recording-device-events', false); - Services.obs.addObserver(recordingHandler, 'recording-device-ipc-events', false); - - Services.obs.addObserver(function(aSubject, aTopic, aData) { - // send additional recording events if content process is being killed - let processId = aSubject.QueryInterface(Ci.nsIPropertyBag2).get('childID'); - if (gRecordingActiveProcesses.hasOwnProperty(processId)) { - Services.obs.notifyObservers(aSubject, 'recording-device-ipc-events', 'content-shutdown'); - } - }, 'ipc:content-shutdown', false); -})(); - -(function volumeStateTracker() { - Services.obs.addObserver(function(aSubject, aTopic, aData) { - shell.sendChromeEvent({ - type: 'volume-state-changed', - active: (aData == 'Shared') - }); -}, 'volume-state-changed', false); -})(); - -if (isGonk) { - // Devices don't have all the same partition size for /cache where we - // store the http cache. - (function setHTTPCacheSize() { - let path = Services.prefs.getCharPref("browser.cache.disk.parent_directory"); - let volumeService = Cc["@mozilla.org/telephony/volume-service;1"] - .getService(Ci.nsIVolumeService); - - let stats = volumeService.createOrGetVolumeByPath(path).getStats(); - - // We must set the size in KB, and keep a bit of free space. - let size = Math.floor(stats.totalBytes / 1024) - 1024; - - // keep the default value if it is smaller than the physical partition size. - let oldSize = Services.prefs.getIntPref("browser.cache.disk.capacity"); - if (size < oldSize) { - Services.prefs.setIntPref("browser.cache.disk.capacity", size); - } - })(); - - try { - let gmpService = Cc["@mozilla.org/gecko-media-plugin-service;1"] - .getService(Ci.mozIGeckoMediaPluginChromeService); - gmpService.addPluginDirectory("/system/b2g/gmp-clearkey/0.1"); - } catch(e) { - dump("Failed to add clearkey path! " + e + "\n"); - } -} - -// Calling this observer will cause a shutdown an a profile reset. -// Use eg. : Services.obs.notifyObservers(null, 'b2g-reset-profile', null); -Services.obs.addObserver(function resetProfile(subject, topic, data) { - Services.obs.removeObserver(resetProfile, topic); - - // Listening for 'profile-before-change-telemetry' which is late in the - // shutdown sequence, but still has xpcom access. - Services.obs.addObserver(function clearProfile(subject, topic, data) { - Services.obs.removeObserver(clearProfile, topic); - if (isGonk) { - let json = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); - json.initWithPath('/system/b2g/webapps/webapps.json'); - let toRemove = json.exists() - // This is a user build, just rm -r /data/local /data/b2g/mozilla - ? ['/data/local', '/data/b2g/mozilla'] - // This is an eng build. We clear the profile and a set of files - // under /data/local. - : ['/data/b2g/mozilla', - '/data/local/permissions.sqlite', - '/data/local/storage', - '/data/local/OfflineCache']; - - toRemove.forEach(function(dir) { - try { - let file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile); - file.initWithPath(dir); - file.remove(true); - } catch(e) { dump(e); } - }); - } else { - // Desktop builds. - let profile = Services.dirsvc.get('ProfD', Ci.nsIFile); - - // We don't want to remove everything from the profile, since this - // would prevent us from starting up. - let whitelist = ['defaults', 'extensions', 'settings.json', - 'user.js', 'webapps']; - let enumerator = profile.directoryEntries; - while (enumerator.hasMoreElements()) { - let file = enumerator.getNext().QueryInterface(Ci.nsIFile); - if (whitelist.indexOf(file.leafName) == -1) { - file.remove(true); - } - } - } - }, - 'profile-before-change-telemetry', false); - - let appStartup = Cc['@mozilla.org/toolkit/app-startup;1'] - .getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eForceQuit); -}, 'b2g-reset-profile', false); - -var showInstallScreen; - -if (AppConstants.MOZ_GRAPHENE) { - const restoreWindowGeometry = () => { - let screenX = Services.prefs.getIntPref("b2g.nativeWindowGeometry.screenX"); - let screenY = Services.prefs.getIntPref("b2g.nativeWindowGeometry.screenY"); - let width = Services.prefs.getIntPref("b2g.nativeWindowGeometry.width"); - let height = Services.prefs.getIntPref("b2g.nativeWindowGeometry.height"); - - if (screenX == -1) { - // Center - screenX = (screen.width - width) / 2; - screenY = (screen.height - height) / 2; - } - - moveTo(screenX, screenY); - resizeTo(width, height); - } - restoreWindowGeometry(); - - const saveWindowGeometry = () => { - window.removeEventListener("unload", saveWindowGeometry); - Services.prefs.setIntPref("b2g.nativeWindowGeometry.screenX", screenX); - Services.prefs.setIntPref("b2g.nativeWindowGeometry.screenY", screenY); - Services.prefs.setIntPref("b2g.nativeWindowGeometry.width", outerWidth); - Services.prefs.setIntPref("b2g.nativeWindowGeometry.height", outerHeight); - } - window.addEventListener("unload", saveWindowGeometry); - - var baseWindow = window.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIDocShellTreeItem) - .treeOwner - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIBaseWindow); - - const showNativeWindow = () => baseWindow.visibility = true; - const hideNativeWindow = () => baseWindow.visibility = false; - - showInstallScreen = () => { - const grapheneStrings = - Services.strings.createBundle('chrome://b2g-l10n/locale/graphene.properties'); - document.querySelector('#installing > .message').textContent = - grapheneStrings.GetStringFromName('installing'); - showNativeWindow(); - } - - const hideInstallScreen = () => { - document.body.classList.add('content-loaded'); - } - - window.addEventListener('ContentStart', () => { - shell.contentBrowser.contentWindow.addEventListener('load', () => { - hideInstallScreen(); - showNativeWindow(); - }); - }); - - hideNativeWindow(); -} diff --git a/b2g/chrome/content/shell_remote.html b/b2g/chrome/content/shell_remote.html deleted file mode 100644 index 4f3f6efc8..000000000 --- a/b2g/chrome/content/shell_remote.html +++ /dev/null @@ -1,19 +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="shellRemote" - windowtype="navigator:remote-browser" - sizemode="fullscreen" - > - -<head> - <link rel="stylesheet" href="shell.css" type="text/css"> - <script type="application/javascript;version=1.8" - src="chrome://b2g/content/shell_remote.js"> </script> -</head> - <body id="container"> - </body> -</html> diff --git a/b2g/chrome/content/shell_remote.js b/b2g/chrome/content/shell_remote.js deleted file mode 100644 index 1f1115ef0..000000000 --- a/b2g/chrome/content/shell_remote.js +++ /dev/null @@ -1,139 +0,0 @@ -/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- / -/* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */ -/* 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"; - -var {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/SystemAppProxy.jsm"); - -function debug(aStr) { - // dump(" -*- ShellRemote.js: " + aStr + "\n"); -} - -var remoteShell = { - - _started: false, - - get homeURL() { - let systemAppManifestURL = Services.io.newURI(this.systemAppManifestURL, null, null); - let shellRemoteURL = Services.prefs.getCharPref("b2g.multiscreen.system_remote_url"); - shellRemoteURL = Services.io.newURI(shellRemoteURL, null, systemAppManifestURL); - return shellRemoteURL.spec; - }, - - get systemAppManifestURL() { - return Services.prefs.getCharPref("b2g.system_manifest_url"); - }, - - hasStarted: function () { - return this._started; - }, - - start: function () { - this._started = true; - this._isEventListenerReady = false; - this.id = window.location.hash.substring(1); - - let homeURL = this.homeURL; - if (!homeURL) { - debug("ERROR! Remote home URL undefined."); - return; - } - let manifestURL = this.systemAppManifestURL; - // <html:iframe id="this.id" - // mozbrowser="true" - // allowfullscreen="true" - // src="blank.html"/> - let systemAppFrame = - document.createElementNS("http://www.w3.org/1999/xhtml", "html:iframe"); - systemAppFrame.setAttribute("id", this.id); - systemAppFrame.setAttribute("mozbrowser", "true"); - systemAppFrame.setAttribute("mozapp", manifestURL); - systemAppFrame.setAttribute("allowfullscreen", "true"); - systemAppFrame.setAttribute("src", "blank.html"); - - let container = document.getElementById("container"); - this.contentBrowser = container.appendChild(systemAppFrame); - this.contentBrowser.src = homeURL + window.location.hash; - - window.addEventListener("unload", this); - this.contentBrowser.addEventListener("mozbrowserloadstart", this); - }, - - stop: function () { - window.removeEventListener("unload", this); - this.contentBrowser.removeEventListener("mozbrowserloadstart", this); - this.contentBrowser.removeEventListener("mozbrowserlocationchange", this, true); - SystemAppProxy.unregisterFrameWithId(this.id); - }, - - notifyContentStart: function(evt) { - this.contentBrowser.removeEventListener("mozbrowserloadstart", this); - this.contentBrowser.removeEventListener("mozbrowserlocationchange", this, true); - - SystemAppProxy.registerFrameWithId(remoteShell.id, remoteShell.contentBrowser); - SystemAppProxy.addEventListenerWithId(this.id, "mozContentEvent", this); - - let content = this.contentBrowser.contentWindow; - content.addEventListener("load", this, true); - }, - - notifyContentWindowLoaded: function () { - SystemAppProxy.setIsLoadedWithId(this.id); - }, - - notifyEventListenerReady: function () { - if (this._isEventListenerReady) { - Cu.reportError("shell_remote.js: SystemApp has already been declared as being ready."); - return; - } - this._isEventListenerReady = true; - SystemAppProxy.setIsReadyWithId(this.id); - }, - - handleEvent: function(evt) { - debug("Got an event: " + evt.type); - let content = this.contentBrowser.contentWindow; - - switch(evt.type) { - case "mozContentEvent": - if (evt.detail.type === "system-message-listener-ready") { - this.notifyEventListenerReady(); - } - break; - case "load": - if (content.document.location == "about:blank") { - return; - } - content.removeEventListener("load", this, true); - this.notifyContentWindowLoaded(); - break; - case "mozbrowserloadstart": - if (content.document.location == "about:blank") { - this.contentBrowser.addEventListener("mozbrowserlocationchange", this, true); - return; - } - case "mozbrowserlocationchange": - if (content.document.location == "about:blank") { - return; - } - this.notifyContentStart(); - break; - case "unload": - this.stop(); - break; - } - } -}; - -window.onload = function() { - if (remoteShell.hasStarted() == false) { - remoteShell.start(); - } -}; - diff --git a/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js b/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js deleted file mode 100644 index 1a5ed8274..000000000 --- a/b2g/chrome/content/test/mochitest/RecordingStatusChromeScript.js +++ /dev/null @@ -1,40 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; -const { Services } = Cu.import('resource://gre/modules/Services.jsm'); -const { SystemAppProxy } = Cu.import('resource://gre/modules/SystemAppProxy.jsm'); - -var processId; - -function peekChildId(aSubject, aTopic, aData) { - Services.obs.removeObserver(peekChildId, 'recording-device-events'); - Services.obs.removeObserver(peekChildId, 'recording-device-ipc-events'); - let props = aSubject.QueryInterface(Ci.nsIPropertyBag2); - if (props.hasKey('childID')) { - processId = props.get('childID'); - } -} - -addMessageListener('init-chrome-event', function(message) { - // listen mozChromeEvent and forward to content process. - let type = message.type; - SystemAppProxy.addEventListener('mozChromeEvent', function(event) { - let details = event.detail; - if (details.type === type) { - sendAsyncMessage('chrome-event', details); - } - }, true); - - Services.obs.addObserver(peekChildId, 'recording-device-events', false); - Services.obs.addObserver(peekChildId, 'recording-device-ipc-events', false); -}); - -addMessageListener('fake-content-shutdown', function(message) { - let props = Cc["@mozilla.org/hash-property-bag;1"] - .createInstance(Ci.nsIWritablePropertyBag2); - if (processId) { - props.setPropertyAsUint64('childID', processId); - } - Services.obs.notifyObservers(props, 'recording-device-ipc-events', 'content-shutdown'); -}); diff --git a/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js b/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js deleted file mode 100644 index 5e3e6814e..000000000 --- a/b2g/chrome/content/test/mochitest/RecordingStatusHelper.js +++ /dev/null @@ -1,82 +0,0 @@ -'use strict'; - -// resolve multiple promise in parallel -function expectAll(aValue) { - let deferred = new Promise(function(resolve, reject) { - let countdown = aValue.length; - let resolutionValues = new Array(countdown); - - for (let i = 0; i < aValue.length; i++) { - let index = i; - aValue[i].then(function(val) { - resolutionValues[index] = val; - if (--countdown === 0) { - resolve(resolutionValues); - } - }, reject); - } - }); - - return deferred; -} - -function TestInit() { - let url = SimpleTest.getTestFileURL("RecordingStatusChromeScript.js") - let script = SpecialPowers.loadChromeScript(url); - - let helper = { - finish: function () { - script.destroy(); - }, - fakeShutdown: function () { - script.sendAsyncMessage('fake-content-shutdown', {}); - } - }; - - script.addMessageListener('chrome-event', function (message) { - if (helper.hasOwnProperty('onEvent')) { - helper.onEvent(message); - } else { - ok(false, 'unexpected message: ' + JSON.stringify(message)); - } - }); - - script.sendAsyncMessage("init-chrome-event", { - type: 'recording-status' - }); - - return Promise.resolve(helper); -} - -function expectEvent(expected, eventHelper) { - return new Promise(function(resolve, reject) { - eventHelper.onEvent = function(message) { - delete eventHelper.onEvent; - ok(message, JSON.stringify(message)); - is(message.type, 'recording-status', 'event type: ' + message.type); - is(message.active, expected.active, 'recording active: ' + message.active); - is(message.isAudio, expected.isAudio, 'audio recording active: ' + message.isAudio); - is(message.isVideo, expected.isVideo, 'video recording active: ' + message.isVideo); - resolve(eventHelper); - }; - info('waiting for recording-status'); - }); -} - -function expectStream(params, callback) { - return new Promise(function(resolve, reject) { - var req = navigator.mozGetUserMedia( - params, - function(stream) { - ok(true, 'create media stream'); - callback(stream); - resolve(); - }, - function(err) { - ok(false, 'fail to create media stream'); - reject(err); - } - ); - info('waiting for gUM result'); - }); -} diff --git a/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html b/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html deleted file mode 100644 index f2b18eab3..000000000 --- a/b2g/chrome/content/test/mochitest/file_getusermedia_iframe.html +++ /dev/null @@ -1,36 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Iframe for Recording Status</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> - -var localStream; - -window.addEventListener('message', function(event) { - switch (event.data) { - case 'start': - let gumDeferred = expectStream({ audio: true, - fake: true - }, function(stream) { - localStream = stream; - event.source.postMessage('start-finished', window.location.origin); - }); - break; - case 'stop': - localStream.stop(); - localStream = null; - break; - } -}, false); - -</script> -</pre> -</body> -</html> diff --git a/b2g/chrome/content/test/mochitest/mochitest.ini b/b2g/chrome/content/test/mochitest/mochitest.ini deleted file mode 100644 index d18a20401..000000000 --- a/b2g/chrome/content/test/mochitest/mochitest.ini +++ /dev/null @@ -1,11 +0,0 @@ -[DEFAULT] -skip-if = ((buildapp == 'mulet' || buildapp == 'b2g') && toolkit != 'gonk') #require OOP support for mochitest-b2g-desktop, Bug 957554 -support-files = - RecordingStatusChromeScript.js - RecordingStatusHelper.js - file_getusermedia_iframe.html - -[test_recordingStatus_basic.html] -[test_recordingStatus_multiple_requests.html] -[test_recordingStatus_iframe.html] -[test_recordingStatus_kill_content_process.html] diff --git a/b2g/chrome/content/test/mochitest/moz.build b/b2g/chrome/content/test/mochitest/moz.build deleted file mode 100644 index 3b13ba431..000000000 --- a/b2g/chrome/content/test/mochitest/moz.build +++ /dev/null @@ -1,7 +0,0 @@ -# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- -# vim: set filetype=python: -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -MOCHITEST_MANIFESTS += ['mochitest.ini'] diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html deleted file mode 100644 index 21f746d33..000000000 --- a/b2g/chrome/content/test/mochitest/test_recordingStatus_basic.html +++ /dev/null @@ -1,119 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for Recording Status</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> -'use strict'; - -SimpleTest.waitForExplicitFinish(); - -function test() { - let localStreams = []; - TestInit().then(function(eventHelper) { - /* step 1: create one audio stream - * expect: see one mozChromeEvent for audio recording start. - */ - let eventDeferred = expectEvent({ active: true, - isAudio: true, - isVideo: false - }, eventHelper); - - let gumDeferred = expectStream({ audio: true, - fake: true - }, function(stream) { - localStreams.push(stream); - }); - - return expectAll([eventDeferred, gumDeferred]); - }).then(function([eventHelper]) { - /* step 2: close the audio stream - * expect: see one mozChromeEvent for recording stop. - */ - let eventDeferred = expectEvent({ active: false, - isAudio: false, - isVideo: false, - }, eventHelper); - - localStreams.shift().stop(); - info('stop audio stream'); - return eventDeferred; - }).then(function(eventHelper) { - /* step 3: create one video stream - * expect: see one mozChromeEvent for video recording start - */ - let eventDeferred = expectEvent({ active: true, - isAudio: false, - isVideo: true - }, eventHelper); - - let gumDeferred = expectStream({ video: true, - fake: true - }, function(stream) { - localStreams.push(stream); - }); - - return expectAll([eventDeferred, gumDeferred]); - }).then(function([eventHelper]) { - /* step 4: close the audio stream - * expect: see one mozChromeEvent for recording stop. - */ - let eventDeferred = expectEvent({ active: false, - isAudio: false, - isVideo: false, - }, eventHelper); - - localStreams.shift().stop(); - info('stop video stream'); - return eventDeferred; - }).then(function(eventHelper) { - /* step 3: create one audio/video stream - * expect: see one mozChromeEvent for audio/video recording start - */ - let eventDeferred = expectEvent({ active: true, - isAudio: true, - isVideo: true - }, eventHelper); - - let gumDeferred = expectStream({ audio: true, - video: true, - fake: true - }, function(stream) { - localStreams.push(stream); - }); - - return expectAll([eventDeferred, gumDeferred]); - }).then(function([eventHelper]) { - /* step 4: close the audio stream - * expect: see one mozChromeEvent for recording stop. - */ - let eventDeferred = expectEvent({ active: false, - isAudio: false, - isVideo: false, - }, eventHelper); - - localStreams.shift().stop(); - info('stop audio/video stream'); - return eventDeferred; - }).then(function(eventHelper) { - eventHelper.finish(); - SimpleTest.finish(); - }); -} - -SpecialPowers.pushPrefEnv({ - "set": [ - ['media.navigator.permission.disabled', true] - ] -}, test); - -</script> -</pre> -</body> -</html> diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html deleted file mode 100644 index 88c33c897..000000000 --- a/b2g/chrome/content/test/mochitest/test_recordingStatus_iframe.html +++ /dev/null @@ -1,71 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for Recording Status in iframe</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<pre id="test"> -<iframe id="gum-iframe"></iframe> -<script class="testbody" type="text/javascript;version=1.7"> -SimpleTest.waitForExplicitFinish(); - -function test() { - TestInit().then(function(eventHelper) { - /* step 1: load iframe whilch creates audio stream - * expect: see one mozChromeEvent for audio recording start. - */ - let eventDeferred = expectEvent({ active: true, - isAudio: true, - isVideo: false - }, eventHelper); - - let loadDeferred = new Promise(function(resolve, reject) { - let gumIframe = document.getElementById('gum-iframe'); - gumIframe.src = 'file_getusermedia_iframe.html'; - - window.addEventListener('message', function(event) { - if (event.data === 'start-finished') { - resolve(); - } - }, false); - - gumIframe.onload = function() { - info('start audio stream in iframe'); - gumIframe.contentWindow.postMessage('start', window.location.origin); - }; - }); - - return expectAll([eventDeferred, loadDeferred]); - }).then(function([eventHelper]) { - /* step 2: close the audio stream - * expect: see one mozChromeEvent for recording stop. - */ - let eventDeferred = expectEvent({ active: false, - isAudio: false, - isVideo: false - }, eventHelper); - - let win = document.getElementById('gum-iframe').contentWindow; - win.postMessage('stop', window.location.origin); - info('stop audio stream in iframe'); - return eventDeferred; - }).then(function(eventHelper) { - eventHelper.finish(); - SimpleTest.finish(); - }); -} - -SpecialPowers.pushPrefEnv({ - "set": [ - ['media.navigator.permission.disabled', true] - ] -}, test); - -</script> -</pre> -</body> -</html> diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html deleted file mode 100644 index 239c2c2d5..000000000 --- a/b2g/chrome/content/test/mochitest/test_recordingStatus_kill_content_process.html +++ /dev/null @@ -1,72 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for Recording Status after process shutdown</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> -SimpleTest.waitForExplicitFinish(); - -function test() { - let localStreams = []; - TestInit().then(function(eventHelper) { - /* step 1: load iframe whilch creates audio stream - * expect: see one mozChromeEvent for audio recording start. - */ - let eventDeferred = expectEvent({ active: true, - isAudio: true, - isVideo: false - }, eventHelper); - - let gumDeferred = expectStream({ audio: true, - fake: true - }, function(stream) { localStreams.push(stream); }); - - return expectAll([eventDeferred, gumDeferred]); - }).then(function([eventHelper]) { - /* step 2: create video stream - * expect: see one mozChromeEvent for audio recording start. - */ - let eventDeferred = expectEvent({ active: true, - isAudio: true, - isVideo: true - }, eventHelper); - - let gumDeferred = expectStream({ video: true, - fake: true - }, function(stream) { localStreams.push(stream); }); - - return expectAll([eventDeferred, gumDeferred]); - }).then(function([eventHelper]) { - /* step 3: close the audio stream - * expect: see one mozChromeEvent for recording stop. - */ - let eventDeferred = expectEvent({ active: false, - isAudio: false, - isVideo: false - }, eventHelper); - - eventHelper.fakeShutdown(); - info('simulate content process been killed'); - return eventDeferred; - }).then(function(eventHelper) { - eventHelper.finish(); - SimpleTest.finish(); - }); -} - -SpecialPowers.pushPrefEnv({ - "set": [ - ['media.navigator.permission.disabled', true] - ] -}, test); - -</script> -</pre> -</body> -</html> diff --git a/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html b/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html deleted file mode 100644 index 7d31a94f8..000000000 --- a/b2g/chrome/content/test/mochitest/test_recordingStatus_multiple_requests.html +++ /dev/null @@ -1,108 +0,0 @@ -<!DOCTYPE HTML> -<html> -<head> - <title>Test for Recording Status with multiple gUM requests</title> - <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> - <script type="text/javascript;version=1.7" src="RecordingStatusHelper.js"></script> - <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> -</head> -<body> - -<pre id="test"> -<script class="testbody" type="text/javascript;version=1.7"> -'use strict'; - -SimpleTest.waitForExplicitFinish(); - -function test() { - let localStreams = []; - TestInit().then(function(eventHelper) { - /* step 1: create one audio stream - * expect: see one mozChromeEvent for recording start. - */ - let eventDeferred = expectEvent({ active: true, - isAudio: true, - isVideo: false - }, eventHelper); - - let gumDeferred = expectStream({ audio: true, - fake: true - }, function(stream) { - localStreams.push(stream); - }); - - return expectAll([eventDeferred, gumDeferred]); - }).then(function([eventHelper]) { - /* step 2: create another audio stream - * expect: no mozChromeEvent after audio stream is created - */ - let gumDeferred = expectStream({ audio: true, - fake: true - }, function(stream) { - localStreams.push(stream); - }); - - return expectAll([Promise.resolve(eventHelper), gumDeferred]); - }).then(function([eventHelper]) { - /* step 3: create video stream - * expect: see one mozChromeEvent for recording start - */ - let eventDeferred = expectEvent({ active: true, - isAudio: true, - isVideo: true - }, eventHelper); - - let gumDeferred = expectStream({ video: true, - fake: true - }, function(stream) { - localStreams.push(stream); - }); - - return expectAll([eventDeferred, gumDeferred]); - }).then(function([eventHelper]) { - /* step 4: stop first audio stream - * expect: no mozChromeEvent after first audio stream is stopped - */ - localStreams.shift().stop(); - info('stop the first audio stream'); - return Promise.resolve(eventHelper); - }).then(function(eventHelper) { - /* step 5: stop the second audio stream - * expect: see one mozChromeEvent for audio recording stop. - */ - let eventDeferred = expectEvent({ active: true, - isAudio: false, - isVideo: true - }, eventHelper); - - localStreams.shift().stop(); - info('stop the second audio stream'); - return eventDeferred; - }).then(function(eventHelper) { - /* step 6: stop the video stream - * expect: see one mozChromeEvent for video recording stop. - */ - let eventDeferred = expectEvent({ active: false, - isAudio: false, - isVideo: false - }, eventHelper); - - localStreams.shift().stop(); - info('stop the video stream'); - return eventDeferred; - }).then(function(eventHelper) { - eventHelper.finish(); - SimpleTest.finish(); - }); -} - -SpecialPowers.pushPrefEnv({ - "set": [ - ['media.navigator.permission.disabled', true] - ] -}, test); - -</script> -</pre> -</body> -</html> diff --git a/b2g/chrome/content/touchcontrols.css b/b2g/chrome/content/touchcontrols.css deleted file mode 100644 index 7c407c331..000000000 --- a/b2g/chrome/content/touchcontrols.css +++ /dev/null @@ -1,233 +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/. */ - -@namespace url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul); - -/* video controls */ -.controlsOverlay { - -moz-box-pack: center; - -moz-box-align: end; - -moz-box-flex: 1; - -moz-box-orient: horizontal; -} - -.controlsOverlay[scaled] { - /* scaled attribute in videocontrols.css causes conflict - due to different -moz-box-orient values */ - -moz-box-align: end; -} - -.controlBar { - -moz-box-flex: 1; - background-color: rgba(50,50,50,0.8); - width: 100%; -} - -.buttonsBar { - -moz-box-flex: 1; - -moz-box-align: center; -} - -.controlsSpacer { - display: none; - -moz-box-flex: 0; -} - -.fullscreenButton, -.playButton, -.castingButton, -.muteButton { - -moz-appearance: none; - padding: 2px; - border: none !important; - min-height: 24px; - min-width: 24px; -} - -.fullscreenButton { - background: url("chrome://b2g/content/images/fullscreen-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -.fullscreenButton[fullscreened="true"] { - background: url("chrome://b2g/content/images/exitfullscreen-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -.controlBar[fullscreen-unavailable] .fullscreenButton { - display: none; -} - -.playButton { - background: url("chrome://b2g/content/images/pause-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -/* - * Normally the button bar has fullscreen spacer play spacer mute, but if - * this is an audio control rather than a video control, the fullscreen button - * is hidden by videocontrols.xml, and that alters the position of the - * play button. This workaround moves it back to center. - */ -.controlBar[fullscreen-unavailable] .playButton { - transform: translateX(28px); -} - -.playButton[paused="true"] { - background: url("chrome://b2g/content/images/play-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -.castingButton { - display: none; -} - -.muteButton { - background: url("chrome://b2g/content/images/mute-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -.muteButton[muted="true"] { - background: url("chrome://b2g/content/images/unmute-hdpi.png") no-repeat center; - background-size: contain; - background-origin: content-box; -} - -/* bars */ -.scrubberStack { - -moz-box-flex: 1; - padding: 0px 18px; -} - -.flexibleBar, -.flexibleBar .progress-bar, -.bufferBar, -.bufferBar .progress-bar, -.progressBar, -.progressBar .progress-bar, -.scrubber, -.scrubber .scale-slider, -.scrubber .scale-thumb { - -moz-appearance: none; - border: none; - padding: 0px; - margin: 0px; - background-color: transparent; -} - -.flexibleBar, -.bufferBar, -.progressBar { - height: 24px; - padding: 11px 0px; -} - -.flexibleBar { - padding: 12px 0px; -} - -.flexibleBar .progress-bar { - border: 1px #777777 solid; - border-radius: 1px; -} - -.bufferBar .progress-bar { - border: 2px #AFB1B3 solid; - border-radius: 2px; -} - -.progressBar .progress-bar { - border: 2px #FF9500 solid; - border-radius: 2px; -} - - -.scrubber { - margin-left: -8px; - margin-right: -8px; -} - -.positionLabel, .durationLabel { - font-family: 'Roboto', Helvetica, Arial, sans-serif; - font-size: 12px; - color: white; -} - -.scrubber .scale-thumb { - display: -moz-box; - margin: 0px !important; - padding: 0px !important; - background: url("chrome://b2g/content/images/scrubber-hdpi.png") no-repeat; - background-size: 12px 12px; - height: 12px; - width: 12px; -} - -.statusOverlay { - -moz-box-align: center; - -moz-box-pack: center; - background-color: rgb(50,50,50); -} - -.statusIcon { - margin-bottom: 28px; - width: 36px; - height: 36px; -} - -.statusIcon[type="throbber"] { - background: url("chrome://b2g/content/images/throbber.png") no-repeat center; -} - -.statusIcon[type="error"] { - background: url("chrome://b2g/content/images/error.png") no-repeat center; -} - -/* CSS Transitions */ -.controlBar:not([immediate]) { - transition-property: opacity; - transition-duration: 200ms; -} - -.controlBar[fadeout] { - opacity: 0; -} - -.statusOverlay:not([immediate]) { - transition-property: opacity; - transition-duration: 300ms; - transition-delay: 750ms; -} - -.statusOverlay[fadeout] { - opacity: 0; -} - -.volumeStack, -.controlBar[firstshow="true"] .fullscreenButton, -.controlBar[firstshow="true"] .muteButton, -.controlBar[firstshow="true"] .scrubberStack, -.controlBar[firstshow="true"] .durationBox, -.timeLabel { - display: none; -} - -/* Error description formatting */ -.errorLabel { - font-family: Helvetica, Arial, sans-serif; - font-size: 11px; - color: #bbb; - text-shadow: - -1px -1px 0 #000, - 1px -1px 0 #000, - -1px 1px 0 #000, - 1px 1px 0 #000; - padding: 0 10px; - text-align: center; -} |