Merge m-c to a CLOSED TREE m-i
@ -803,3 +803,6 @@ pref("gfx.canvas.azure.accelerated", true);
|
||||
|
||||
// Enable Telephony API
|
||||
pref("dom.telephony.enabled", true);
|
||||
|
||||
// The url of the page used to display network error details.
|
||||
pref("b2g.neterror.url", "app://system.gaiamobile.org/net_error.html");
|
||||
|
@ -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://browser/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://browser/content/images/errorpage-larry-black.png");
|
||||
}
|
||||
|
||||
#errorPage.blockedsite #errorTitle {
|
||||
background-image: url("chrome://browser/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://browser/skin/images/arrowright-16.png");
|
||||
background-size: 11px 11px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: left 0.3em;
|
||||
}
|
||||
|
||||
div[collapsed="true"] {
|
||||
background-image: url("chrome://browser/skin/images/arrowright-16.png");
|
||||
}
|
||||
|
||||
div[collapsed="false"] {
|
||||
background-image: url("chrome://browser/skin/images/arrowdown-16.png");
|
||||
}
|
||||
|
||||
div[collapsed="true"] > p,
|
||||
div[collapsed="true"] > div {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0.3em !important;
|
||||
}
|
@ -1,364 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<!DOCTYPE html [
|
||||
<!ENTITY % htmlDTD
|
||||
PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
|
||||
"DTD/xhtml1-strict.dtd">
|
||||
%htmlDTD;
|
||||
<!ENTITY % netErrorDTD
|
||||
SYSTEM "chrome://global/locale/netError.dtd">
|
||||
%netErrorDTD;
|
||||
<!ENTITY % globalDTD
|
||||
SYSTEM "chrome://global/locale/global.dtd">
|
||||
%globalDTD;
|
||||
]>
|
||||
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width; user-scalable=false;" />
|
||||
<title>&loadError.label;</title>
|
||||
<link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all" />
|
||||
<!-- If the location of the favicon is changed here, the FAVICON_ERRORPAGE_URL symbol in
|
||||
toolkit/components/places/src/nsFaviconService.h should be updated. -->
|
||||
<link rel="icon" type="image/png" id="favicon" href="chrome://global/skin/icons/warning-16.png"/>
|
||||
|
||||
<script type="application/javascript"><![CDATA[
|
||||
// Error url MUST be formatted like this:
|
||||
// moz-neterror:page?e=error&u=url&d=desc
|
||||
//
|
||||
// or optionally, to specify an alternate CSS class to allow for
|
||||
// custom styling and favicon:
|
||||
//
|
||||
// moz-neterror:page?e=error&u=url&s=classname&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 getErrorCode()
|
||||
{
|
||||
var url = document.documentURI;
|
||||
var error = url.search(/e\=/);
|
||||
var duffUrl = url.search(/\&u\=/);
|
||||
return decodeURIComponent(url.slice(error + 2, duffUrl));
|
||||
}
|
||||
|
||||
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 retryThis(buttonEl)
|
||||
{
|
||||
// Note: The application may wish to handle switching off "offline mode"
|
||||
// before this event handler runs, by using a capturing event handler.
|
||||
|
||||
// Session history has the URL of the page that failed
|
||||
// to load, not the one of the error page. So, just call
|
||||
// reload(), which will also repost POST data correctly.
|
||||
try {
|
||||
location.reload();
|
||||
} catch (e) {
|
||||
// We probably tried to reload a URI that caused an exception to
|
||||
// occur; e.g. a nonexistent file.
|
||||
}
|
||||
|
||||
buttonEl.disabled = true;
|
||||
}
|
||||
|
||||
function initPage()
|
||||
{
|
||||
var err = getErrorCode();
|
||||
|
||||
// if it's an unknown error or there's no title or description
|
||||
// defined, get the generic message
|
||||
var errTitle = document.getElementById("et_" + err);
|
||||
var errDesc = document.getElementById("ed_" + err);
|
||||
if (!errTitle || !errDesc)
|
||||
{
|
||||
errTitle = document.getElementById("et_generic");
|
||||
errDesc = document.getElementById("ed_generic");
|
||||
}
|
||||
|
||||
var title = document.getElementsByClassName("errorTitleText")[0];
|
||||
if (title)
|
||||
{
|
||||
title.parentNode.replaceChild(errTitle, title);
|
||||
// change id to the replaced child's id so styling works
|
||||
errTitle.classList.add("errorTitleText");
|
||||
}
|
||||
|
||||
var sd = document.getElementById("errorShortDescText");
|
||||
if (sd)
|
||||
sd.textContent = getDescription();
|
||||
|
||||
var ld = document.getElementById("errorLongDesc");
|
||||
if (ld)
|
||||
{
|
||||
ld.parentNode.replaceChild(errDesc, ld);
|
||||
// change id to the replaced child's id so styling works
|
||||
errDesc.id = "errorLongDesc";
|
||||
}
|
||||
|
||||
// remove undisplayed errors to avoid bug 39098
|
||||
var errContainer = document.getElementById("errorContainer");
|
||||
errContainer.parentNode.removeChild(errContainer);
|
||||
|
||||
var className = getCSSClass();
|
||||
if (className && className != "expertBadCert") {
|
||||
// Associate a CSS class with the root of the page, if one was passed in,
|
||||
// to allow custom styling.
|
||||
// Not "expertBadCert" though, don't want to deal with the favicon
|
||||
document.documentElement.className = className;
|
||||
|
||||
// Also, if they specified a CSS class, they must supply their own
|
||||
// favicon. In order to trigger the browser to repaint though, we
|
||||
// need to remove/add the link element.
|
||||
var favicon = document.getElementById("favicon");
|
||||
var faviconParent = favicon.parentNode;
|
||||
faviconParent.removeChild(favicon);
|
||||
favicon.setAttribute("href", "chrome://global/skin/icons/" + className + "_favicon.png");
|
||||
faviconParent.appendChild(favicon);
|
||||
}
|
||||
if (className == "expertBadCert") {
|
||||
showSecuritySection();
|
||||
}
|
||||
|
||||
if (err == "remoteXUL") {
|
||||
// Remove the "Try again" button for remote XUL errors given that
|
||||
// it is useless.
|
||||
document.getElementById("errorTryAgain").style.display = "none";
|
||||
}
|
||||
|
||||
if (err == "cspFrameAncestorBlocked") {
|
||||
// Remove the "Try again" button for CSP frame ancestors violation, since it's
|
||||
// almost certainly useless. (Bug 553180)
|
||||
document.getElementById("errorTryAgain").style.display = "none";
|
||||
}
|
||||
|
||||
if (err == "nssBadCert") {
|
||||
// Remove the "Try again" button for security exceptions, since it's
|
||||
// almost certainly useless.
|
||||
document.getElementById("errorTryAgain").style.display = "none";
|
||||
document.getElementById("errorPage").setAttribute("class", "certerror");
|
||||
addDomainErrorLink();
|
||||
}
|
||||
else {
|
||||
// Remove the override block for non-certificate errors. CSS-hiding
|
||||
// isn't good enough here, because of bug 39098
|
||||
var secOverride = document.getElementById("securityOverrideDiv");
|
||||
secOverride.parentNode.removeChild(secOverride);
|
||||
}
|
||||
}
|
||||
|
||||
function showSecuritySection() {
|
||||
// Swap link out, content in
|
||||
document.getElementById('securityOverrideContent').style.display = '';
|
||||
document.getElementById('securityOverrideLink').style.display = 'none';
|
||||
}
|
||||
|
||||
/* 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("errorShortDescText");
|
||||
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;
|
||||
}
|
||||
|
||||
function endsWith(haystack, needle) {
|
||||
return haystack.slice(-needle.length) == needle;
|
||||
}
|
||||
|
||||
]]></script>
|
||||
</head>
|
||||
|
||||
<body id="errorPage" dir="&locale.dir;">
|
||||
<!-- ERROR ITEM CONTAINER (removed during loading to avoid bug 39098) -->
|
||||
<div id="errorContainer">
|
||||
<div id="errorTitlesContainer">
|
||||
<h1 id="et_generic">&generic.title;</h1>
|
||||
<h1 id="et_dnsNotFound">&dnsNotFound.title;</h1>
|
||||
<h1 id="et_fileNotFound">&fileNotFound.title;</h1>
|
||||
<h1 id="et_malformedURI">&malformedURI.title;</h1>
|
||||
<h1 id="et_protocolNotFound">&protocolNotFound.title;</h1>
|
||||
<h1 id="et_connectionFailure">&connectionFailure.title;</h1>
|
||||
<h1 id="et_netTimeout">&netTimeout.title;</h1>
|
||||
<h1 id="et_redirectLoop">&redirectLoop.title;</h1>
|
||||
<h1 id="et_unknownSocketType">&unknownSocketType.title;</h1>
|
||||
<h1 id="et_netReset">&netReset.title;</h1>
|
||||
<h1 id="et_notCached">¬Cached.title;</h1>
|
||||
<h1 id="et_netOffline">&netOffline.title;</h1>
|
||||
<h1 id="et_netInterrupt">&netInterrupt.title;</h1>
|
||||
<h1 id="et_deniedPortAccess">&deniedPortAccess.title;</h1>
|
||||
<h1 id="et_proxyResolveFailure">&proxyResolveFailure.title;</h1>
|
||||
<h1 id="et_proxyConnectFailure">&proxyConnectFailure.title;</h1>
|
||||
<h1 id="et_contentEncodingError">&contentEncodingError.title;</h1>
|
||||
<h1 id="et_unsafeContentType">&unsafeContentType.title;</h1>
|
||||
<h1 id="et_nssFailure2">&nssFailure2.title;</h1>
|
||||
<h1 id="et_nssBadCert">&nssBadCert.title;</h1>
|
||||
<h1 id="et_cspFrameAncestorBlocked">&cspFrameAncestorBlocked.title;</h1>
|
||||
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
|
||||
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
|
||||
</div>
|
||||
<div id="errorDescriptionsContainer">
|
||||
<div id="ed_generic">&generic.longDesc;</div>
|
||||
<div id="ed_dnsNotFound">&dnsNotFound.longDesc2;</div>
|
||||
<div id="ed_fileNotFound">&fileNotFound.longDesc;</div>
|
||||
<div id="ed_malformedURI">&malformedURI.longDesc;</div>
|
||||
<div id="ed_protocolNotFound">&protocolNotFound.longDesc;</div>
|
||||
<div id="ed_connectionFailure">&connectionFailure.longDesc;</div>
|
||||
<div id="ed_netTimeout">&netTimeout.longDesc;</div>
|
||||
<div id="ed_redirectLoop">&redirectLoop.longDesc;</div>
|
||||
<div id="ed_unknownSocketType">&unknownSocketType.longDesc;</div>
|
||||
<div id="ed_netReset">&netReset.longDesc;</div>
|
||||
<div id="ed_notCached">¬Cached.longDesc;</div>
|
||||
<div id="ed_netOffline">&netOffline.longDesc2;</div>
|
||||
<div id="ed_netInterrupt">&netInterrupt.longDesc;</div>
|
||||
<div id="ed_deniedPortAccess">&deniedPortAccess.longDesc;</div>
|
||||
<div id="ed_proxyResolveFailure">&proxyResolveFailure.longDesc2;</div>
|
||||
<div id="ed_proxyConnectFailure">&proxyConnectFailure.longDesc;</div>
|
||||
<div id="ed_contentEncodingError">&contentEncodingError.longDesc;</div>
|
||||
<div id="ed_unsafeContentType">&unsafeContentType.longDesc;</div>
|
||||
<div id="ed_nssFailure2">&nssFailure2.longDesc;</div>
|
||||
<div id="ed_nssBadCert">&nssBadCert.longDesc2;</div>
|
||||
<div id="ed_cspFrameAncestorBlocked">&cspFrameAncestorBlocked.longDesc;</div>
|
||||
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
|
||||
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Error Title -->
|
||||
<div id="errorTitle">
|
||||
<h1 class="errorTitleText" />
|
||||
</div>
|
||||
|
||||
<!-- PAGE CONTAINER (for styling purposes only) -->
|
||||
<div id="errorPageContainer">
|
||||
|
||||
<!-- LONG CONTENT (the section most likely to require scrolling) -->
|
||||
<div id="errorLongContent">
|
||||
|
||||
<!-- Short Description -->
|
||||
<div id="errorShortDesc">
|
||||
<p id="errorShortDescText" />
|
||||
</div>
|
||||
|
||||
<!-- Long Description (Note: See netError.dtd for used XHTML tags) -->
|
||||
<div id="errorLongDesc" />
|
||||
|
||||
<!-- Override section - For ssl errors only. Removed on init for other
|
||||
error types. -->
|
||||
<div id="securityOverrideDiv">
|
||||
<a id="securityOverrideLink" href="javascript:showSecuritySection();" >&securityOverride.linkText;</a>
|
||||
<div id="securityOverrideContent" style="display: none;">&securityOverride.warningContent;</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Retry Button -->
|
||||
<button id="errorTryAgain" onclick="retryThis(this);">&retry.label;</button>
|
||||
|
||||
</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>
|
@ -24,14 +24,10 @@ chrome.jar:
|
||||
* content/payment.js (content/payment.js)
|
||||
content/identity.js (content/identity.js)
|
||||
|
||||
% override chrome://global/content/netError.xhtml chrome://browser/content/netError.xhtml
|
||||
% override chrome://global/skin/netError.css chrome://browser/content/netError.css
|
||||
% override chrome://global/skin/media/videocontrols.css chrome://browser/content/touchcontrols.css
|
||||
% override chrome://global/content/aboutCertError.xhtml chrome://browser/content/aboutCertError.xhtml
|
||||
|
||||
content/ErrorPage.js (content/ErrorPage.js)
|
||||
content/netError.xhtml (content/netError.xhtml)
|
||||
content/netError.css (content/netError.css)
|
||||
content/aboutCertError.xhtml (content/aboutCertError.xhtml)
|
||||
content/images/errorpage-larry-black.png (content/images/errorpage-larry-black.png)
|
||||
content/images/errorpage-larry-white.png (content/images/errorpage-larry-white.png)
|
||||
|
@ -5,16 +5,30 @@ const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
function debug(msg) {
|
||||
//dump("B2GAboutRedirector: " + msg + "\n");
|
||||
}
|
||||
|
||||
function netErrorURL() {
|
||||
let uri = "app://system.gaiamobile.org/net_error.html";
|
||||
try {
|
||||
uri = Services.prefs.getCharPref("b2g.neterror.url");
|
||||
} catch(e) {}
|
||||
return uri;
|
||||
}
|
||||
|
||||
let modules = {
|
||||
certerror: {
|
||||
uri: "chrome://browser/content/aboutCertError.xhtml",
|
||||
privileged: false,
|
||||
hide: true
|
||||
},
|
||||
neterror: {
|
||||
uri: netErrorURL(),
|
||||
privileged: false,
|
||||
hide: true
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -69,6 +69,7 @@ contract @mozilla.org/recovery-service;1 {b3caca5d-0bb0-48c6-912b-6be6cbf08832}
|
||||
# B2GAboutRedirector
|
||||
component {920400b1-cf8f-4760-a9c4-441417b15134} B2GAboutRedirector.js
|
||||
contract @mozilla.org/network/protocol/about;1?what=certerror {920400b1-cf8f-4760-a9c4-441417b15134}
|
||||
contract @mozilla.org/network/protocol/about;1?what=neterror {920400b1-cf8f-4760-a9c4-441417b15134}
|
||||
|
||||
# FilePicker.js
|
||||
component {436ff8f9-0acc-4b11-8ec7-e293efba3141} FilePicker.js
|
||||
|
@ -1,4 +1,4 @@
|
||||
{
|
||||
"revision": "7c63d2f71b0b68f085e01cb09f355b259ade2dd1",
|
||||
"revision": "44efe8a2b5ce1abc18fb4da92fe774d08290bd31",
|
||||
"repo_path": "/integration/gaia-central"
|
||||
}
|
||||
|
@ -1,176 +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/. -->
|
||||
|
||||
<!ENTITY % brandDTD SYSTEM "chrome://branding/locale/brand.dtd">
|
||||
%brandDTD;
|
||||
|
||||
<!ENTITY loadError.label "Problem loading page">
|
||||
<!ENTITY retry.label "Try Again">
|
||||
|
||||
<!-- Specific error messages -->
|
||||
|
||||
<!ENTITY connectionFailure.title "Unable to connect">
|
||||
<!ENTITY connectionFailure.longDesc "&sharedLongDesc2;">
|
||||
|
||||
<!ENTITY deniedPortAccess.title "This address is restricted">
|
||||
<!ENTITY deniedPortAccess.longDesc "">
|
||||
|
||||
<!ENTITY dnsNotFound.title "Server not found">
|
||||
<!ENTITY dnsNotFound.longDesc2 "
|
||||
<ul>
|
||||
<li>Check the address for typing errors such as
|
||||
<strong>ww</strong>.example.com instead of
|
||||
<strong>www</strong>.example.com</li>
|
||||
<li>If you are unable to load any pages, check your device's data or Wi-Fi connection.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY fileNotFound.title "File not found">
|
||||
<!ENTITY fileNotFound.longDesc "
|
||||
<ul>
|
||||
<li>Check the file name for capitalization or other typing errors.</li>
|
||||
<li>Check to see if the file was moved, renamed or deleted.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
|
||||
<!ENTITY generic.title "Oops.">
|
||||
<!ENTITY generic.longDesc "
|
||||
<p>&brandShortName; can't load this page for some reason.</p>
|
||||
">
|
||||
|
||||
<!ENTITY malformedURI.title "The address isn't valid">
|
||||
<!ENTITY malformedURI.longDesc "
|
||||
<ul>
|
||||
<li>Web addresses are usually written like
|
||||
<strong>http://www.example.com/</strong></li>
|
||||
<li>Make sure that you're using forward slashes (i.e.
|
||||
<strong>/</strong>).</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY netInterrupt.title "The connection was interrupted">
|
||||
<!ENTITY netInterrupt.longDesc "&sharedLongDesc2;">
|
||||
|
||||
<!ENTITY notCached.title "Document Expired">
|
||||
<!ENTITY notCached.longDesc "<p>The requested document is not available in &brandShortName;'s cache.</p><ul><li>As a security precaution, &brandShortName; does not automatically re-request sensitive documents.</li><li>Click Try Again to re-request the document from the website.</li></ul>">
|
||||
|
||||
<!ENTITY netOffline.title "Offline mode">
|
||||
<!ENTITY netOffline.longDesc2 "
|
||||
<ul>
|
||||
<li>Try again. &brandShortName; will attempt to open a connection and reload the page.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY contentEncodingError.title "Content Encoding Error">
|
||||
<!ENTITY contentEncodingError.longDesc "
|
||||
<ul>
|
||||
<li>Please contact the website owners to inform them of this problem.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY unsafeContentType.title "Unsafe File Type">
|
||||
<!ENTITY unsafeContentType.longDesc "
|
||||
<ul>
|
||||
<li>Please contact the website owners to inform them of this problem.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY netReset.title "The connection was reset">
|
||||
<!ENTITY netReset.longDesc "&sharedLongDesc2;">
|
||||
|
||||
<!ENTITY netTimeout.title "The connection has timed out">
|
||||
<!ENTITY netTimeout.longDesc "&sharedLongDesc2;">
|
||||
|
||||
<!ENTITY protocolNotFound.title "The address wasn't understood">
|
||||
<!ENTITY protocolNotFound.longDesc "
|
||||
<ul>
|
||||
<li>You might need to install other software to open this address.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY proxyConnectFailure.title "The proxy server is refusing connections">
|
||||
<!ENTITY proxyConnectFailure.longDesc "
|
||||
<ul>
|
||||
<li>Check the proxy settings to make sure that they are correct.</li>
|
||||
<li>Contact your network administrator to make sure the proxy server is
|
||||
working.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY proxyResolveFailure.title "Unable to find the proxy server">
|
||||
<!ENTITY proxyResolveFailure.longDesc2 "
|
||||
<ul>
|
||||
<li>Check the proxy settings to make sure that they are correct.</li>
|
||||
<li>Check to make sure your device has a working data or Wi-Fi connection.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY redirectLoop.title "The page isn't redirecting properly">
|
||||
<!ENTITY redirectLoop.longDesc "
|
||||
<ul>
|
||||
<li>This problem can sometimes be caused by disabling or refusing to accept
|
||||
cookies.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY unknownSocketType.title "Unexpected response from server">
|
||||
<!ENTITY unknownSocketType.longDesc "
|
||||
<ul>
|
||||
<li>Check to make sure your system has the Personal Security Manager
|
||||
installed.</li>
|
||||
<li>This might be due to a non-standard configuration on the server.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY nssFailure2.title "Secure Connection Failed">
|
||||
<!ENTITY nssFailure2.longDesc "
|
||||
<ul>
|
||||
<li>The page you are trying to view cannot be shown because the authenticity of the received data could not be verified.</li>
|
||||
<li>Please contact the website owners to inform them of this problem. Alternatively, use the command found in the help menu to report this broken site.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY nssBadCert.title "Secure Connection Failed">
|
||||
<!ENTITY nssBadCert.longDesc2 "
|
||||
<ul>
|
||||
<li>This could be a problem with the server's configuration, or it could be
|
||||
someone trying to impersonate the server.</li>
|
||||
<li>If you have connected to this server successfully in the past, the error may
|
||||
be temporary, and you can try again later.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY sharedLongDesc2 "
|
||||
<ul>
|
||||
<li>The site could be temporarily unavailable or too busy. Try again in a few moments.</li>
|
||||
<li>If you are unable to load any pages, check your mobile device's data or Wi-Fi connection.</li>
|
||||
</ul>
|
||||
">
|
||||
|
||||
<!ENTITY cspFrameAncestorBlocked.title "Blocked by Content Security Policy">
|
||||
<!ENTITY cspFrameAncestorBlocked.longDesc "<p>&brandShortName; prevented this page from loading in this way because the page has a content security policy that disallows it.</p>">
|
||||
|
||||
<!ENTITY corruptedContentError.title "Corrupted Content Error">
|
||||
<!ENTITY corruptedContentError.longDesc "<p>The page you are trying to view cannot be shown because an error in the data transmission was detected.</p><ul><li>Please contact the website owners to inform them of this problem.</li></ul>">
|
||||
|
||||
<!ENTITY securityOverride.linkText "Or you can add an exception…">
|
||||
<!ENTITY securityOverride.getMeOutOfHereButton "Get me out of here!">
|
||||
<!ENTITY securityOverride.exceptionButtonLabel "Add Exception…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (securityOverride.warningContent) - Do not translate the
|
||||
contents of the <xul:button> tags. The only language content is the label= field,
|
||||
which uses strings already defined above. The button is included here (instead of
|
||||
netError.xhtml) because it exposes functionality specific to firefox. -->
|
||||
|
||||
<!ENTITY securityOverride.warningContent "
|
||||
<p>You should not add an exception if you are using an internet connection that you do not trust completely or if you are not used to seeing a warning for this server.</p>
|
||||
|
||||
<button id='getMeOutOfHereButton'>&securityOverride.getMeOutOfHereButton;</button>
|
||||
<button id='exceptionDialogButton'>&securityOverride.exceptionButtonLabel;</button>
|
||||
">
|
||||
|
||||
<!ENTITY remoteXUL.title "Remote XUL">
|
||||
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
|
||||
|
@ -7,10 +7,8 @@
|
||||
@AB_CD@.jar:
|
||||
% locale b2g-l10n @AB_CD@ %locale/@AB_CD@/b2g-l10n/
|
||||
|
||||
% override chrome://global/locale/netError.dtd chrome://b2g-l10n/locale/netError.dtd
|
||||
% override chrome://global/locale/aboutCertError.dtd chrome://b2g-l10n/locale/aboutCertError.dtd
|
||||
% override chrome://global/locale/appstrings.properties chrome://b2g-l10n/locale/appstrings.properties
|
||||
* locale/@AB_CD@/b2g-l10n/netError.dtd (%chrome/overrides/netError.dtd)
|
||||
* locale/@AB_CD@/b2g-l10n/aboutCertError.dtd (%chrome/overrides/aboutCertError.dtd)
|
||||
* locale/@AB_CD@/b2g-l10n/appstrings.properties (%chrome/overrides/appstrings.properties)
|
||||
|
||||
|
@ -4904,17 +4904,16 @@
|
||||
|
||||
<method name="_calcMouseTargetRect">
|
||||
<body><![CDATA[
|
||||
let alignRight = false;
|
||||
let container = this.parentNode;
|
||||
let alignRight = (getComputedStyle(container).direction == "rtl");
|
||||
let panelRect = this.getBoundingClientRect();
|
||||
let containerRect = container.getBoundingClientRect();
|
||||
|
||||
if (getComputedStyle(document.documentElement).direction == "rtl")
|
||||
alignRight = !alignRight;
|
||||
|
||||
let rect = this.getBoundingClientRect();
|
||||
this._mouseTargetRect = {
|
||||
top: rect.top,
|
||||
bottom: rect.bottom,
|
||||
left: alignRight ? window.innerWidth - rect.width : 0,
|
||||
right: alignRight ? window.innerWidth : rect.width
|
||||
top: panelRect.top,
|
||||
bottom: panelRect.bottom,
|
||||
left: alignRight ? containerRect.right - panelRect.width : containerRect.left,
|
||||
right: alignRight ? containerRect.right : containerRect.left + panelRect.width
|
||||
};
|
||||
]]></body>
|
||||
</method>
|
||||
|
7
browser/base/content/test/chrome/Makefile.in
Normal file
@ -0,0 +1,7 @@
|
||||
# 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_CHROME_FILES = \
|
||||
test_aboutCrashed.xul \
|
||||
$(NULL)
|
6
browser/base/content/test/chrome/moz.build
Normal file
@ -0,0 +1,6 @@
|
||||
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
86
browser/base/content/test/chrome/test_aboutCrashed.xul
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<iframe type="content" id="frame1"/>
|
||||
<iframe type="content" id="frame2" onload="doTest()"/>
|
||||
<script type="application/javascript"><![CDATA[
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Load error pages do not fire "load" events, so let's use a progressListener.
|
||||
function waitForErrorPage(frame) {
|
||||
let errorPageDeferred = Promise.defer();
|
||||
|
||||
let progressListener = {
|
||||
onLocationChange: function(aWebProgress, aRequest, aLocation, aFlags) {
|
||||
if (aFlags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) {
|
||||
frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress)
|
||||
.removeProgressListener(progressListener,
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION);
|
||||
|
||||
errorPageDeferred.resolve();
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference])
|
||||
};
|
||||
|
||||
frame.docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress)
|
||||
.addProgressListener(progressListener,
|
||||
Ci.nsIWebProgress.NOTIFY_LOCATION);
|
||||
|
||||
return errorPageDeferred.promise;
|
||||
}
|
||||
|
||||
function doTest() {
|
||||
Task.spawn(function test_aboutCrashed() {
|
||||
let frame1 = document.getElementById("frame1");
|
||||
let frame2 = document.getElementById("frame2");
|
||||
let uri1 = Services.io.newURI("http://www.example.com/1", null, null);
|
||||
let uri2 = Services.io.newURI("http://www.example.com/2", null, null);
|
||||
|
||||
let errorPageReady = waitForErrorPage(frame1);
|
||||
frame1.docShell.chromeEventHandler.setAttribute("crashedPageTitle", "pageTitle");
|
||||
frame1.docShell.displayLoadError(Components.results.NS_ERROR_CONTENT_CRASHED, uri1, null);
|
||||
|
||||
yield errorPageReady;
|
||||
frame1.docShell.chromeEventHandler.removeAttribute("crashedPageTitle");
|
||||
|
||||
SimpleTest.is(frame1.contentDocument.documentURI,
|
||||
"about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/1&c=UTF-8&d=pageTitle",
|
||||
"Correct about:tabcrashed displayed for page with title.");
|
||||
|
||||
errorPageReady = waitForErrorPage(frame2);
|
||||
frame2.docShell.displayLoadError(Components.results.NS_ERROR_CONTENT_CRASHED, uri2, null);
|
||||
|
||||
yield errorPageReady;
|
||||
|
||||
SimpleTest.is(frame2.contentDocument.documentURI,
|
||||
"about:tabcrashed?e=tabcrashed&u=http%3A//www.example.com/2&c=UTF-8&d=%20",
|
||||
"Correct about:tabcrashed displayed for page with no title.");
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" style="height: 300px; overflow: auto;" />
|
||||
</window>
|
@ -4,5 +4,5 @@
|
||||
# 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/.
|
||||
|
||||
DIRS += ['general', 'newtab', 'social']
|
||||
DIRS += ['chrome', 'general', 'newtab', 'social']
|
||||
|
||||
|
@ -1127,7 +1127,7 @@ var ViewMenu = {
|
||||
* Set up the content of the view menu.
|
||||
*/
|
||||
populateSortMenu: function VM_populateSortMenu(event) {
|
||||
this.fillWithColumns(event, "viewUnsorted", "directionSeparator", "radio", "view.sortBy.");
|
||||
this.fillWithColumns(event, "viewUnsorted", "directionSeparator", "radio", "view.sortBy.1.");
|
||||
|
||||
var sortColumn = this._getSortColumn();
|
||||
var viewSortAscending = document.getElementById("viewSortAscending");
|
||||
|
@ -384,7 +384,7 @@
|
||||
<treecol label="&col.url.label;" id="placesContentUrl" anonid="url" flex="5"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.lastvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
|
||||
<treecol label="&col.mostrecentvisit.label;" id="placesContentDate" anonid="date" flex="1" hidden="true"
|
||||
persist="width hidden ordinal sortActive sortDirection"/>
|
||||
<splitter class="tree-splitter"/>
|
||||
<treecol label="&col.visitcount.label;" id="placesContentVisitCount" anonid="visitCount" flex="1" hidden="true"
|
||||
|
@ -2585,7 +2585,6 @@ let SessionStoreInternal = {
|
||||
restoreHistory:
|
||||
function ssi_restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
|
||||
aRestoreImmediately) {
|
||||
var _this = this;
|
||||
// if the tab got removed before being completely restored, then skip it
|
||||
while (aTabs.length > 0 && !(this._canRestoreTabHistory(aTabs[0]))) {
|
||||
aTabs.shift();
|
||||
@ -2654,9 +2653,11 @@ let SessionStoreInternal = {
|
||||
tab.dispatchEvent(event);
|
||||
|
||||
// Restore the history in the next tab
|
||||
aWindow.setTimeout(function(){
|
||||
_this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
|
||||
aRestoreImmediately);
|
||||
aWindow.setTimeout(() => {
|
||||
if (!aWindow.closed) {
|
||||
this.restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap,
|
||||
aRestoreImmediately);
|
||||
}
|
||||
}, 0);
|
||||
|
||||
// This could cause us to ignore MAX_CONCURRENT_TAB_RESTORES a bit, but
|
||||
|
@ -61,6 +61,9 @@ let UI = {
|
||||
|
||||
this.template = new Template(document.body, this.store, Utils.l10n);
|
||||
this.template.start();
|
||||
|
||||
this._onSimulatorConnected = this._onSimulatorConnected.bind(this);
|
||||
this._onSimulatorDisconnected = this._onSimulatorDisconnected.bind(this);
|
||||
},
|
||||
|
||||
useFloatingScrollbarsIfNeeded: function() {
|
||||
@ -136,16 +139,25 @@ let UI = {
|
||||
this.connection.log("Simulator ready. Connecting.");
|
||||
this.connection.port = port;
|
||||
this.connection.host = "localhost";
|
||||
this.connection.once("connected", () => {
|
||||
this.connection.log("Connected to simulator.");
|
||||
this.connection.keepConnecting = false;
|
||||
});
|
||||
this.connection.once("connected",
|
||||
this._onSimulatorConnected);
|
||||
this.connection.once("disconnected",
|
||||
this._onSimulatorDisconnected);
|
||||
this.connection.keepConnecting = true;
|
||||
this.connection.connect();
|
||||
});
|
||||
document.body.classList.remove("show-simulators");
|
||||
},
|
||||
|
||||
_onSimulatorConnected: function() {
|
||||
this.connection.log("Connected to simulator.");
|
||||
this.connection.keepConnecting = false;
|
||||
},
|
||||
|
||||
_onSimulatorDisconnected: function() {
|
||||
this.connection.off("connected", this._onSimulatorConnected);
|
||||
},
|
||||
|
||||
connectToAdbDevice: function(name) {
|
||||
let device = Devices.getByName(name);
|
||||
device.connect().then((port) => {
|
||||
|
@ -46,7 +46,7 @@ function testSetBreakpoint() {
|
||||
let deferred = promise.defer();
|
||||
|
||||
gDebugger.gThreadClient.interrupt(aResponse => {
|
||||
gDebugger.gThreadClient.setBreakpoint({ url: JS_URL, line: 30, column: 10 }, aResponse => {
|
||||
gDebugger.gThreadClient.setBreakpoint({ url: JS_URL, line: 30, column: 21 }, aResponse => {
|
||||
ok(!aResponse.error,
|
||||
"Should be able to set a breakpoint in a js file.");
|
||||
ok(!aResponse.actualLocation,
|
||||
|
40
browser/devtools/devtools-clhandler.js
Normal file
@ -0,0 +1,40 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
function devtoolsCommandlineHandler() {
|
||||
}
|
||||
devtoolsCommandlineHandler.prototype = {
|
||||
handle: function(cmdLine) {
|
||||
if (!cmdLine.handleFlag("jsconsole", false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
let window = Services.wm.getMostRecentWindow("devtools:webconsole");
|
||||
if (!window) {
|
||||
let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools;
|
||||
// Load the browser devtools main module as the loader's main module.
|
||||
devtools.main("main");
|
||||
let hudservice = devtools.require("devtools/webconsole/hudservice");
|
||||
let console = Cu.import("resource://gre/modules/devtools/Console.jsm", {}).console;
|
||||
hudservice.toggleBrowserConsole().then(null, console.error);
|
||||
} else {
|
||||
window.focus(); // the Browser Console was already open
|
||||
}
|
||||
|
||||
if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
},
|
||||
|
||||
helpInfo : " -jsconsole Open the Browser Console.\n",
|
||||
|
||||
classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]),
|
||||
};
|
||||
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([devtoolsCommandlineHandler]);
|
2
browser/devtools/devtools-clhandler.manifest
Normal file
@ -0,0 +1,2 @@
|
||||
component {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32} devtools-clhandler.js
|
||||
contract @mozilla.org/toolkit/console-clh;1 {9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}
|
@ -40,9 +40,6 @@ function OptionsPanel(iframeWindow, toolbox) {
|
||||
this.toolbox = toolbox;
|
||||
this.isReady = false;
|
||||
|
||||
// Make restart method available from xul
|
||||
this.panelWin.restart = this.restart;
|
||||
|
||||
EventEmitter.decorate(this);
|
||||
};
|
||||
|
||||
@ -57,7 +54,6 @@ OptionsPanel.prototype = {
|
||||
|
||||
this.setupToolsList();
|
||||
this.populatePreferences();
|
||||
this.prepareRestartPreferences();
|
||||
|
||||
this._disableJSClicked = this._disableJSClicked.bind(this);
|
||||
|
||||
@ -201,34 +197,6 @@ OptionsPanel.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles checkbox click inside hbox with class "hidden-labels-box". The
|
||||
* labels inside the hbox are shown again when the user click on the checkbox
|
||||
* in the box.
|
||||
*/
|
||||
prepareRestartPreferences: function() {
|
||||
let checkboxes = this.panelDoc.querySelectorAll(".hidden-labels-box > checkbox");
|
||||
for (let checkbox of checkboxes) {
|
||||
checkbox.addEventListener("command", function(target) {
|
||||
target.parentNode.classList.toggle("visible");
|
||||
}.bind(null, checkbox));
|
||||
}
|
||||
},
|
||||
|
||||
restart: function() {
|
||||
let canceled = Cc["@mozilla.org/supports-PRBool;1"]
|
||||
.createInstance(Ci.nsISupportsPRBool);
|
||||
Services.obs.notifyObservers(canceled, "quit-application-requested", "restart");
|
||||
if (canceled.data) {
|
||||
return;
|
||||
}
|
||||
|
||||
// restart
|
||||
Cc['@mozilla.org/toolkit/app-startup;1']
|
||||
.getService(Ci.nsIAppStartup)
|
||||
.quit(Ci.nsIAppStartup.eAttemptQuit | Ci.nsIAppStartup.eRestart);
|
||||
},
|
||||
|
||||
/**
|
||||
* Disables JavaScript for the currently loaded tab. We force a page refresh
|
||||
* here because setting docShell.allowJavascript to true fails to block JS
|
||||
|
@ -74,21 +74,11 @@
|
||||
<checkbox label="&options.enableChrome.label3;"
|
||||
tooltiptext="&options.enableChrome.tooltip;"
|
||||
data-pref="devtools.chrome.enabled"/>
|
||||
<label class="options-citation-label"
|
||||
value="&options.context.requiresRestart2;"/>
|
||||
<label class="text-link"
|
||||
onclick="restart()"
|
||||
value="&options.restartButton.label;"/>
|
||||
</hbox>
|
||||
<hbox class="hidden-labels-box">
|
||||
<checkbox label="&options.enableRemote.label3;"
|
||||
tooltiptext="&options.enableRemote.tooltip;"
|
||||
data-pref="devtools.debugger.remote-enabled"/>
|
||||
<label class="options-citation-label"
|
||||
value="&options.context.requiresRestart2;"/>
|
||||
<label class="text-link"
|
||||
onclick="restart()"
|
||||
value="&options.restartButton.label;"/>
|
||||
</hbox>
|
||||
</vbox>
|
||||
</vbox>
|
||||
|
@ -168,7 +168,7 @@ InspectorPanel.prototype = {
|
||||
// as default selected, else set documentElement
|
||||
return walker.getRootNode().then(aRootNode => {
|
||||
rootNode = aRootNode;
|
||||
return walker.querySelector(aRootNode, this.selectionCssSelector);
|
||||
return walker.querySelector(rootNode, this.selectionCssSelector);
|
||||
}).then(front => {
|
||||
if (front) {
|
||||
return front;
|
||||
|
@ -43,5 +43,7 @@ MOCHITEST_BROWSER_FILES := \
|
||||
browser_inspector_select_last_selected.html \
|
||||
browser_inspector_select_last_selected2.html \
|
||||
browser_inspector_basic_highlighter.js \
|
||||
browser_inspector_dead_node_exception.html \
|
||||
browser_inspector_dead_node_exception.js \
|
||||
head.js \
|
||||
$(NULL)
|
||||
|
@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>iframe creation/deletion test</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="yay"></div>
|
||||
<script type="text/javascript">
|
||||
var yay = document.querySelector("#yay");
|
||||
yay.textContent = "nothing";
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
|
||||
yay.textContent = "before events";
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
var iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
|
||||
yay.textContent = "DOMContentLoaded";
|
||||
});
|
||||
window.addEventListener("load", function() {
|
||||
var iframe = document.createElement('iframe');
|
||||
document.body.appendChild(iframe);
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
|
||||
yay.textContent = "load";
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,56 @@
|
||||
/* Any copyright", " is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
let contentTab, contentDoc, inspector;
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
// Create a tab
|
||||
contentTab = gBrowser.selectedTab = gBrowser.addTab();
|
||||
|
||||
// Open the toolbox's inspector first
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, "inspector").then(function(toolbox) {
|
||||
inspector = toolbox.getCurrentPanel();
|
||||
|
||||
inspector.selection.setNode(content.document.querySelector("body"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
is(inspector.selection.node.tagName, "BODY", "Inspector displayed");
|
||||
|
||||
// Then load our test page
|
||||
gBrowser.selectedBrowser.addEventListener("load", function onload() {
|
||||
gBrowser.selectedBrowser.removeEventListener("load", onload, true);
|
||||
contentDoc = content.document;
|
||||
|
||||
// The content doc contains a script that creates an iframe and deletes
|
||||
// it immediately after. This is what used to make the inspector go
|
||||
// blank when navigating to that page.
|
||||
|
||||
var iframe = contentDoc.createElement("iframe");
|
||||
contentDoc.body.appendChild(iframe);
|
||||
iframe.parentNode.removeChild(iframe);
|
||||
|
||||
is(contentDoc.querySelector("iframe"), null, "Iframe has been removed");
|
||||
|
||||
inspector.once("markuploaded", () => {
|
||||
// Assert that the markup-view is displayed and works
|
||||
is(contentDoc.querySelector("iframe"), null, "Iframe has been removed");
|
||||
is(contentDoc.getElementById("yay").textContent, "load", "Load event fired");
|
||||
|
||||
inspector.selection.setNode(contentDoc.getElementById("yay"));
|
||||
inspector.once("inspector-updated", () => {
|
||||
ok(inspector.selection.node, "Inspector still displayed");
|
||||
|
||||
// Clean up and go
|
||||
contentTab, contentDoc, inspector = null;
|
||||
gBrowser.removeTab(contentTab);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
}, true);
|
||||
content.location = "http://mochi.test:8888/browser/browser/devtools/" +
|
||||
"inspector/test/browser_inspector_dead_node_exception.html";
|
||||
});
|
||||
});
|
||||
}
|
@ -24,3 +24,8 @@ DIRS += [
|
||||
'fontinspector',
|
||||
'app-manager',
|
||||
]
|
||||
|
||||
EXTRA_COMPONENTS += [
|
||||
'devtools-clhandler.js',
|
||||
'devtools-clhandler.manifest',
|
||||
]
|
||||
|
@ -254,13 +254,14 @@ HUD_SERVICE.prototype =
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
connect().then(getTarget).then(openWindow).then((aWindow) =>
|
||||
connect().then(getTarget).then(openWindow).then((aWindow) => {
|
||||
this.openBrowserConsole(target, aWindow, aWindow)
|
||||
.then((aBrowserConsole) => {
|
||||
this._browserConsoleID = aBrowserConsole.hudId;
|
||||
this._browserConsoleDefer.resolve(aBrowserConsole);
|
||||
this._browserConsoleDefer = null;
|
||||
}));
|
||||
})
|
||||
}, console.error);
|
||||
|
||||
return this._browserConsoleDefer.promise;
|
||||
},
|
||||
|
@ -62,7 +62,7 @@ function consoleOpened(hud)
|
||||
let text = output.textContent;
|
||||
chromeConsole = text.indexOf("bug587757a");
|
||||
contentConsole = text.indexOf("bug587757b");
|
||||
execValue = text.indexOf("browser.xul");
|
||||
execValue = text.indexOf("webconsole.xul");
|
||||
exception = text.indexOf("foobarExceptionBug587757");
|
||||
xhrRequest = text.indexOf("test-console.html");
|
||||
}
|
||||
|
@ -24,7 +24,10 @@ function test()
|
||||
ok(hud, "browser console opened");
|
||||
|
||||
hud.jsterm.clearOutput();
|
||||
hud.jsterm.execute("foobarzTezt = content.document", onAddVariable);
|
||||
hud.jsterm.execute("Cu = Components.utils;" +
|
||||
"Cu.import('resource://gre/modules/Services.jsm');" +
|
||||
"chromeWindow = Services.wm.getMostRecentWindow('navigator:browser');" +
|
||||
"foobarzTezt = chromeWindow.content.document", onAddVariable);
|
||||
}
|
||||
|
||||
function onAddVariable()
|
||||
|
@ -52,15 +52,6 @@
|
||||
- -->
|
||||
<!ENTITY options.defaultColorUnit.name "Color Names">
|
||||
|
||||
<!-- LOCALIZATION NOTE (options.context.requiresRestart2): This is the requires
|
||||
- restart label at right of settings that require a browser restart to be
|
||||
- effective. -->
|
||||
<!ENTITY options.context.requiresRestart2 "Requires browser restart">
|
||||
|
||||
<!-- LOCALIZATION NOTE (options.restartButton.label): This is the label for the
|
||||
- restart button next to options.context.requiresRestart2 label. -->
|
||||
<!ENTITY options.restartButton.label "Restart now">
|
||||
|
||||
<!-- LOCALIZATION NOTE (options.context.triggersPageRefresh2): This is the
|
||||
- triggers page refresh label next to the settings in the advanced settings
|
||||
- group in the options panel which trigger page reload. -->
|
||||
|
@ -81,7 +81,7 @@
|
||||
<!ENTITY col.name.label "Name">
|
||||
<!ENTITY col.tags.label "Tags">
|
||||
<!ENTITY col.url.label "Location">
|
||||
<!ENTITY col.lastvisit.label "Visit Date">
|
||||
<!ENTITY col.mostrecentvisit.label "Most Recent Visit">
|
||||
<!ENTITY col.visitcount.label "Visit Count">
|
||||
<!ENTITY col.keyword.label "Keyword">
|
||||
<!ENTITY col.description.label "Description">
|
||||
|
@ -25,24 +25,28 @@ menuOpenLivemarkOrigin.label=Open "%S"
|
||||
|
||||
sortByName=Sort '%S' by Name
|
||||
sortByNameGeneric=Sort by Name
|
||||
view.sortBy.name.label=Sort by Name
|
||||
view.sortBy.name.accesskey=N
|
||||
view.sortBy.url.label=Sort by Location
|
||||
view.sortBy.url.accesskey=L
|
||||
view.sortBy.date.label=Sort by Visit Date
|
||||
view.sortBy.date.accesskey=V
|
||||
view.sortBy.visitCount.label=Sort by Visit Count
|
||||
view.sortBy.visitCount.accesskey=C
|
||||
view.sortBy.keyword.label=Sort by Keyword
|
||||
view.sortBy.keyword.accesskey=K
|
||||
view.sortBy.description.label=Sort by Description
|
||||
view.sortBy.description.accesskey=D
|
||||
view.sortBy.dateAdded.label=Sort by Added
|
||||
view.sortBy.dateAdded.accesskey=e
|
||||
view.sortBy.lastModified.label=Sort by Last Modified
|
||||
view.sortBy.lastModified.accesskey=M
|
||||
view.sortBy.tags.label=Sort by Tags
|
||||
view.sortBy.tags.accesskey=T
|
||||
# LOCALIZATION NOTE (view.sortBy.1.name.label): sortBy properties are versioned.
|
||||
# When any of these changes, all of the properties must be bumped, and the
|
||||
# change must be annotated here. Both label and accesskey must be updated.
|
||||
# - version 1: changed view.sortBy.1.date.
|
||||
view.sortBy.1.name.label=Sort by Name
|
||||
view.sortBy.1.name.accesskey=N
|
||||
view.sortBy.1.url.label=Sort by Location
|
||||
view.sortBy.1.url.accesskey=L
|
||||
view.sortBy.1.date.label=Sort by Most Recent Visit
|
||||
view.sortBy.1.date.accesskey=V
|
||||
view.sortBy.1.visitCount.label=Sort by Visit Count
|
||||
view.sortBy.1.visitCount.accesskey=C
|
||||
view.sortBy.1.keyword.label=Sort by Keyword
|
||||
view.sortBy.1.keyword.accesskey=K
|
||||
view.sortBy.1.description.label=Sort by Description
|
||||
view.sortBy.1.description.accesskey=D
|
||||
view.sortBy.1.dateAdded.label=Sort by Added
|
||||
view.sortBy.1.dateAdded.accesskey=e
|
||||
view.sortBy.1.lastModified.label=Sort by Last Modified
|
||||
view.sortBy.1.lastModified.accesskey=M
|
||||
view.sortBy.1.tags.label=Sort by Tags
|
||||
view.sortBy.1.tags.accesskey=T
|
||||
|
||||
searchBookmarks=Search Bookmarks
|
||||
searchHistory=Search History
|
||||
|
@ -77,6 +77,13 @@ var ContentAreaObserver = {
|
||||
return this._deckTransitioning;
|
||||
},
|
||||
|
||||
get viewstate() {
|
||||
if (this.width < Services.prefs.getIntPref("browser.ui.snapped.maxWidth")) {
|
||||
return "snapped";
|
||||
}
|
||||
return (this.height > this.width) ? "portrait" : "landscape";
|
||||
},
|
||||
|
||||
/*
|
||||
* Public apis
|
||||
*/
|
||||
@ -122,6 +129,8 @@ var ContentAreaObserver = {
|
||||
this.styles["window-height"].height = newHeight + "px";
|
||||
this.styles["window-height"].maxHeight = newHeight + "px";
|
||||
|
||||
this._updateViewState();
|
||||
|
||||
this.updateContentArea(newWidth, this._getContentHeightForWindow(newHeight));
|
||||
this._disatchBrowserEvent("SizeChanged");
|
||||
},
|
||||
@ -280,6 +289,15 @@ var ContentAreaObserver = {
|
||||
* Internal helpers
|
||||
*/
|
||||
|
||||
_updateViewState: function (aState) {
|
||||
let oldViewstate = Elements.windowState.getAttribute("viewstate");
|
||||
let viewstate = aState || this.viewstate;
|
||||
if (viewstate != oldViewstate) {
|
||||
Elements.windowState.setAttribute("viewstate", viewstate);
|
||||
Services.obs.notifyObservers(null, "metro_viewstate_changed", viewstate);
|
||||
}
|
||||
},
|
||||
|
||||
_shiftBrowserDeck: function _shiftBrowserDeck(aAmount) {
|
||||
if (aAmount == 0) {
|
||||
this._deckTransitioning = false;
|
||||
|
@ -102,7 +102,6 @@ var BrowserUI = {
|
||||
window.addEventListener("MozImprecisePointer", this, true);
|
||||
|
||||
Services.prefs.addObserver("browser.cache.disk_cache_ssl", this, false);
|
||||
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
||||
|
||||
// Init core UI modules
|
||||
ContextUI.init();
|
||||
@ -112,9 +111,6 @@ var BrowserUI = {
|
||||
SettingsCharm.init();
|
||||
NavButtonSlider.init();
|
||||
|
||||
// show the right toolbars, awesomescreen, etc for the os viewstate
|
||||
BrowserUI._adjustDOMforViewState();
|
||||
|
||||
// We can delay some initialization until after startup. We wait until
|
||||
// the first page is shown, then dispatch a UIReadyDelayed event.
|
||||
messageManager.addMessageListener("pageshow", function onPageShow() {
|
||||
@ -178,6 +174,7 @@ var BrowserUI = {
|
||||
messageManager.removeMessageListener("Browser:MozApplicationManifest", OfflineApps);
|
||||
|
||||
PanelUI.uninit();
|
||||
FlyoutPanelsUI.uninit();
|
||||
Downloads.uninit();
|
||||
SettingsCharm.uninit();
|
||||
messageManager.removeMessageListener("Content:StateChange", this);
|
||||
@ -592,13 +589,6 @@ var BrowserUI = {
|
||||
this.changeDebugPort(Services.prefs.getIntPref(aData));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "metro_viewstate_changed":
|
||||
this._adjustDOMforViewState(aData);
|
||||
if (aData == "snapped") {
|
||||
FlyoutPanelsUI.hide();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
},
|
||||
@ -638,28 +628,6 @@ var BrowserUI = {
|
||||
pullDesktopControlledPrefType(Ci.nsIPrefBranch.PREF_STRING, "setCharPref");
|
||||
},
|
||||
|
||||
_adjustDOMforViewState: function(aState) {
|
||||
let currViewState = aState;
|
||||
if (!currViewState && Services.metro.immersive) {
|
||||
switch (Services.metro.snappedState) {
|
||||
case Ci.nsIWinMetroUtils.fullScreenLandscape:
|
||||
currViewState = "landscape";
|
||||
break;
|
||||
case Ci.nsIWinMetroUtils.fullScreenPortrait:
|
||||
currViewState = "portrait";
|
||||
break;
|
||||
case Ci.nsIWinMetroUtils.filled:
|
||||
currViewState = "filled";
|
||||
break;
|
||||
case Ci.nsIWinMetroUtils.snapped:
|
||||
currViewState = "snapped";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Elements.windowState.setAttribute("viewstate", currViewState);
|
||||
},
|
||||
|
||||
_titleChanged: function(aBrowser) {
|
||||
let url = this.getDisplayURI(aBrowser);
|
||||
|
||||
|
@ -130,14 +130,7 @@ var Browser = {
|
||||
window.controllers.appendController(this);
|
||||
window.controllers.appendController(BrowserUI);
|
||||
|
||||
let os = Services.obs;
|
||||
os.addObserver(SessionHistoryObserver, "browser:purge-session-history", false);
|
||||
os.addObserver(ActivityObserver, "application-background", false);
|
||||
os.addObserver(ActivityObserver, "application-foreground", false);
|
||||
os.addObserver(ActivityObserver, "system-active", false);
|
||||
os.addObserver(ActivityObserver, "system-idle", false);
|
||||
os.addObserver(ActivityObserver, "system-display-on", false);
|
||||
os.addObserver(ActivityObserver, "system-display-off", false);
|
||||
Services.obs.addObserver(SessionHistoryObserver, "browser:purge-session-history", false);
|
||||
|
||||
window.QueryInterface(Ci.nsIDOMChromeWindow).browserDOMWindow = new nsBrowserAccess();
|
||||
|
||||
@ -247,14 +240,7 @@ var Browser = {
|
||||
messageManager.removeMessageListener("Browser:PluginClickToPlayClicked", this);
|
||||
messageManager.removeMessageListener("Browser:TapOnSelection", this);
|
||||
|
||||
var os = Services.obs;
|
||||
os.removeObserver(SessionHistoryObserver, "browser:purge-session-history");
|
||||
os.removeObserver(ActivityObserver, "application-background");
|
||||
os.removeObserver(ActivityObserver, "application-foreground");
|
||||
os.removeObserver(ActivityObserver, "system-active");
|
||||
os.removeObserver(ActivityObserver, "system-idle");
|
||||
os.removeObserver(ActivityObserver, "system-display-on");
|
||||
os.removeObserver(ActivityObserver, "system-display-off");
|
||||
Services.obs.removeObserver(SessionHistoryObserver, "browser:purge-session-history");
|
||||
|
||||
window.controllers.removeController(this);
|
||||
window.controllers.removeController(BrowserUI);
|
||||
@ -1394,37 +1380,6 @@ var SessionHistoryObserver = {
|
||||
}
|
||||
};
|
||||
|
||||
var ActivityObserver = {
|
||||
_inBackground : false,
|
||||
_notActive : false,
|
||||
_isDisplayOff : false,
|
||||
_timeoutID: 0,
|
||||
observe: function ao_observe(aSubject, aTopic, aData) {
|
||||
if (aTopic == "application-background") {
|
||||
this._inBackground = true;
|
||||
} else if (aTopic == "application-foreground") {
|
||||
this._inBackground = false;
|
||||
} else if (aTopic == "system-idle") {
|
||||
this._notActive = true;
|
||||
} else if (aTopic == "system-active") {
|
||||
this._notActive = false;
|
||||
} else if (aTopic == "system-display-on") {
|
||||
this._isDisplayOff = false;
|
||||
} else if (aTopic == "system-display-off") {
|
||||
this._isDisplayOff = true;
|
||||
}
|
||||
let activeTabState = !this._inBackground && !this._notActive && !this._isDisplayOff;
|
||||
if (this._timeoutID)
|
||||
clearTimeout(this._timeoutID);
|
||||
if (Browser.selectedTab.active != activeTabState) {
|
||||
// On Maemo all backgrounded applications getting portrait orientation
|
||||
// so if browser had landscape mode then we need timeout in order
|
||||
// to finish last rotate/paint operation and have nice lookine browser in TS
|
||||
this._timeoutID = setTimeout(function() { Browser.selectedTab.active = activeTabState; }, activeTabState ? 0 : kSetInactiveStateTimeout);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getNotificationBox(aBrowser) {
|
||||
return Browser.getNotificationBox(aBrowser);
|
||||
}
|
||||
|
@ -172,6 +172,7 @@
|
||||
|
||||
<stack id="stack" flex="1">
|
||||
<observes element="bcast_urlbarState" attribute="*"/>
|
||||
<observes element="bcast_windowState" attribute="*"/>
|
||||
<!-- Page Area -->
|
||||
<vbox id="page">
|
||||
<vbox id="tray" class="tray-toolbar" observes="bcast_windowState" >
|
||||
|
@ -36,6 +36,12 @@ let FlyoutPanelsUI = {
|
||||
return sandbox[name];
|
||||
});
|
||||
});
|
||||
|
||||
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
||||
},
|
||||
|
||||
uninit: function () {
|
||||
Services.obs.removeObserver(this, "metro_viewstate_changed");
|
||||
},
|
||||
|
||||
show: function(aToShow) {
|
||||
@ -73,6 +79,16 @@ let FlyoutPanelsUI = {
|
||||
return this._currentFlyout ? true : false;
|
||||
},
|
||||
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "metro_viewstate_changed":
|
||||
if (aData == "snapped") {
|
||||
this.hide();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
dispatchEvent: function(aEvent) {
|
||||
if (this._currentFlyout) {
|
||||
this._currentFlyout._topmostElement.dispatchEvent(aEvent);
|
||||
|
@ -13,8 +13,8 @@
|
||||
* @param aRoot Bookmark root to show in the view.
|
||||
*/
|
||||
function BookmarksView(aSet, aLimit, aRoot, aFilterUnpinned) {
|
||||
this._set = aSet;
|
||||
this._set.controller = this;
|
||||
View.call(this, aSet);
|
||||
|
||||
this._inBatch = false; // batch up grid updates to avoid redundant arrangeItems calls
|
||||
|
||||
this._limit = aLimit;
|
||||
@ -25,12 +25,10 @@ function BookmarksView(aSet, aLimit, aRoot, aFilterUnpinned) {
|
||||
this._changes = new BookmarkChangeListener(this);
|
||||
this._pinHelper = new ItemPinHelper("metro.bookmarks.unpinned");
|
||||
this._bookmarkService.addObserver(this._changes, false);
|
||||
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
||||
StartUI.chromeWin.addEventListener('MozAppbarDismissing', this, false);
|
||||
StartUI.chromeWin.addEventListener('BookmarksNeedsRefresh', this, false);
|
||||
window.addEventListener("TabClose", this, true);
|
||||
|
||||
this._adjustDOMforViewState();
|
||||
this.root = aRoot;
|
||||
}
|
||||
|
||||
@ -62,11 +60,11 @@ BookmarksView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
|
||||
destruct: function bv_destruct() {
|
||||
this._bookmarkService.removeObserver(this._changes);
|
||||
Services.obs.removeObserver(this, "metro_viewstate_changed");
|
||||
if (StartUI.chromeWin) {
|
||||
StartUI.chromeWin.removeEventListener('MozAppbarDismissing', this, false);
|
||||
StartUI.chromeWin.removeEventListener('BookmarksNeedsRefresh', this, false);
|
||||
}
|
||||
View.prototype.destruct.call(this);
|
||||
},
|
||||
|
||||
handleItemClick: function bv_handleItemClick(aItem) {
|
||||
@ -275,15 +273,6 @@ BookmarksView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
this._sendNeedsRefresh();
|
||||
},
|
||||
|
||||
// nsIObservers
|
||||
observe: function (aSubject, aTopic, aState) {
|
||||
switch(aTopic) {
|
||||
case "metro_viewstate_changed":
|
||||
this.onViewStateChange(aState);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
handleEvent: function bv_handleEvent(aEvent) {
|
||||
switch (aEvent.type){
|
||||
case "MozAppbarDismissing":
|
||||
|
@ -5,8 +5,8 @@
|
||||
'use strict';
|
||||
|
||||
function HistoryView(aSet, aLimit, aFilterUnpinned) {
|
||||
this._set = aSet;
|
||||
this._set.controller = this;
|
||||
View.call(this, aSet);
|
||||
|
||||
this._inBatch = 0;
|
||||
|
||||
this._limit = aLimit;
|
||||
@ -16,12 +16,9 @@ function HistoryView(aSet, aLimit, aFilterUnpinned) {
|
||||
|
||||
this._pinHelper = new ItemPinHelper("metro.history.unpinned");
|
||||
this._historyService.addObserver(this, false);
|
||||
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
||||
StartUI.chromeWin.addEventListener('MozAppbarDismissing', this, false);
|
||||
StartUI.chromeWin.addEventListener('HistoryNeedsRefresh', this, false);
|
||||
window.addEventListener("TabClose", this, true);
|
||||
|
||||
this._adjustDOMforViewState();
|
||||
}
|
||||
|
||||
HistoryView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
@ -30,11 +27,11 @@ HistoryView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
|
||||
destruct: function destruct() {
|
||||
this._historyService.removeObserver(this);
|
||||
Services.obs.removeObserver(this, "metro_viewstate_changed");
|
||||
if (StartUI.chromeWin) {
|
||||
StartUI.chromeWin.removeEventListener('MozAppbarDismissing', this, false);
|
||||
StartUI.chromeWin.removeEventListener('HistoryNeedsRefresh', this, false);
|
||||
}
|
||||
View.prototype.destruct.call(this);
|
||||
},
|
||||
|
||||
handleItemClick: function tabview_handleItemClick(aItem) {
|
||||
@ -223,15 +220,6 @@ HistoryView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
}
|
||||
},
|
||||
|
||||
// nsIObservers
|
||||
observe: function (aSubject, aTopic, aState) {
|
||||
switch(aTopic) {
|
||||
case "metro_viewstate_changed":
|
||||
this.onViewStateChange(aState);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// nsINavHistoryObserver & helpers
|
||||
|
||||
onBeginUpdateBatch: function() {
|
||||
|
@ -20,8 +20,8 @@ Components.utils.import("resource://services-sync/main.js");
|
||||
* You may only have one UI access point at this time.
|
||||
*/
|
||||
function RemoteTabsView(aSet, aSetUIAccessList) {
|
||||
this._set = aSet;
|
||||
this._set.controller = this;
|
||||
View.call(this, aSet);
|
||||
|
||||
this._uiAccessElements = aSetUIAccessList;
|
||||
|
||||
// Sync uses special voodoo observers.
|
||||
@ -29,15 +29,12 @@ function RemoteTabsView(aSet, aSetUIAccessList) {
|
||||
Weave.Svc.Obs.add("weave:service:sync:finish", this);
|
||||
Weave.Svc.Obs.add("weave:service:start-over", this);
|
||||
|
||||
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
||||
|
||||
if (this.isSyncEnabled() ) {
|
||||
this.populateGrid();
|
||||
}
|
||||
else {
|
||||
this.setUIAccessVisible(false);
|
||||
}
|
||||
this._adjustDOMforViewState();
|
||||
}
|
||||
|
||||
RemoteTabsView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
@ -51,9 +48,6 @@ RemoteTabsView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "metro_viewstate_changed":
|
||||
this.onViewStateChange(data);
|
||||
break;
|
||||
case "weave:service:sync:finish":
|
||||
this.populateGrid();
|
||||
break;
|
||||
@ -102,9 +96,9 @@ RemoteTabsView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
},
|
||||
|
||||
destruct: function destruct() {
|
||||
Services.obs.removeObserver(this, "metro_viewstate_changed");
|
||||
Weave.Svc.Obs.remove("weave:engine:sync:finish", this);
|
||||
Weave.Svc.Obs.remove("weave:service:logout:start-over", this);
|
||||
View.prototype.destruct.call(this);
|
||||
},
|
||||
|
||||
isSyncEnabled: function isSyncEnabled() {
|
||||
|
@ -26,7 +26,7 @@ var StartUI = {
|
||||
document.getElementById("bcast_preciseInput").setAttribute("input",
|
||||
this.chromeWin.InputSourceHelper.isPrecise ? "precise" : "imprecise");
|
||||
|
||||
this._adjustDOMforViewState();
|
||||
this._adjustDOMforViewState(this.chromeWin.ContentAreaObserver.viewstate);
|
||||
|
||||
TopSitesStartView.init();
|
||||
BookmarksStartView.init();
|
||||
@ -81,6 +81,10 @@ var StartUI = {
|
||||
section.setAttribute("expanded", "true");
|
||||
},
|
||||
|
||||
_adjustDOMforViewState: function(aState) {
|
||||
document.getElementById("bcast_windowState").setAttribute("viewstate", aState);
|
||||
},
|
||||
|
||||
handleEvent: function handleEvent(aEvent) {
|
||||
switch (aEvent.type) {
|
||||
case "MozPrecisePointer":
|
||||
@ -106,33 +110,6 @@ var StartUI = {
|
||||
}
|
||||
},
|
||||
|
||||
_adjustDOMforViewState: function(aState) {
|
||||
let currViewState = aState;
|
||||
if (!currViewState && Services.metro.immersive) {
|
||||
switch (Services.metro.snappedState) {
|
||||
case Ci.nsIWinMetroUtils.fullScreenLandscape:
|
||||
currViewState = "landscape";
|
||||
break;
|
||||
case Ci.nsIWinMetroUtils.fullScreenPortrait:
|
||||
currViewState = "portrait";
|
||||
break;
|
||||
case Ci.nsIWinMetroUtils.filled:
|
||||
currViewState = "filled";
|
||||
break;
|
||||
case Ci.nsIWinMetroUtils.snapped:
|
||||
currViewState = "snapped";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("bcast_windowState").setAttribute("viewstate", currViewState);
|
||||
if (currViewState == "snapped") {
|
||||
document.getElementById("start-topsites-grid").removeAttribute("tiletype");
|
||||
} else {
|
||||
document.getElementById("start-topsites-grid").setAttribute("tiletype", "thumbnail");
|
||||
}
|
||||
},
|
||||
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
switch (aTopic) {
|
||||
case "metro_viewstate_changed":
|
||||
|
@ -11,8 +11,8 @@ Cu.import("resource://gre/modules/PageThumbs.jsm");
|
||||
Cu.import("resource:///modules/colorUtils.jsm");
|
||||
|
||||
function TopSitesView(aGrid, aMaxSites) {
|
||||
this._set = aGrid;
|
||||
this._set.controller = this;
|
||||
View.call(this, aGrid);
|
||||
|
||||
this._topSitesMax = aMaxSites;
|
||||
|
||||
// clean up state when the appbar closes
|
||||
@ -23,9 +23,6 @@ function TopSitesView(aGrid, aMaxSites) {
|
||||
|
||||
PageThumbs.addExpirationFilter(this);
|
||||
Services.obs.addObserver(this, "Metro:RefreshTopsiteThumbnail", false);
|
||||
Services.obs.addObserver(this, "metro_viewstate_changed", false);
|
||||
|
||||
this._adjustDOMforViewState();
|
||||
|
||||
NewTabUtils.allPages.register(this);
|
||||
TopSites.prepareCache().then(function(){
|
||||
@ -43,12 +40,12 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
|
||||
destruct: function destruct() {
|
||||
Services.obs.removeObserver(this, "Metro:RefreshTopsiteThumbnail");
|
||||
Services.obs.removeObserver(this, "metro_viewstate_changed");
|
||||
PageThumbs.removeExpirationFilter(this);
|
||||
NewTabUtils.allPages.unregister(this);
|
||||
if (StartUI.chromeWin) {
|
||||
StartUI.chromeWin.removeEventListener('MozAppbarDismissing', this, false);
|
||||
}
|
||||
View.prototype.destruct.call(this);
|
||||
},
|
||||
|
||||
handleItemClick: function tabview_handleItemClick(aItem) {
|
||||
@ -137,6 +134,7 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
case "MozAppbarDismissing":
|
||||
// clean up when the context appbar is dismissed - we don't remember selections
|
||||
this._lastSelectedSites = null;
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
@ -234,6 +232,13 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
|
||||
View.prototype._adjustDOMforViewState.call(this, aState);
|
||||
|
||||
// Don't show thumbnails in snapped view.
|
||||
if (aState == "snapped") {
|
||||
document.getElementById("start-topsites-grid").removeAttribute("tiletype");
|
||||
} else {
|
||||
document.getElementById("start-topsites-grid").setAttribute("tiletype", "thumbnail");
|
||||
}
|
||||
|
||||
// propogate tiletype changes down to tile children
|
||||
let tileType = this._set.getAttribute("tiletype");
|
||||
for (let item of this._set.children) {
|
||||
@ -251,9 +256,6 @@ TopSitesView.prototype = Util.extend(Object.create(View.prototype), {
|
||||
case "Metro:RefreshTopsiteThumbnail":
|
||||
this.forceReloadOfThumbnail(aState);
|
||||
break;
|
||||
case "metro_viewstate_changed":
|
||||
this.onViewStateChange(aState);
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -111,7 +111,7 @@ gTests.push({
|
||||
},
|
||||
tearDown: function() {
|
||||
BookmarksTestHelper.restore();
|
||||
restoreViewstate();
|
||||
yield restoreViewstate();
|
||||
}
|
||||
});
|
||||
|
||||
@ -160,6 +160,6 @@ gTests.push({
|
||||
tearDown: function() {
|
||||
BookmarksTestHelper.restore();
|
||||
HistoryTestHelper.restore();
|
||||
restoreViewstate();
|
||||
yield restoreViewstate();
|
||||
}
|
||||
});
|
||||
|
@ -47,7 +47,7 @@ const mochitestPath = splitPath.join('/') + '/';
|
||||
|
||||
function isLandscapeMode()
|
||||
{
|
||||
return (Services.metro.snappedState == Ci.nsIWinMetroUtils.fullScreenLandscape);
|
||||
return Elements.windowState.getAttribute("viewstate") == "landscape";
|
||||
}
|
||||
|
||||
function setDevPixelEqualToPx()
|
||||
|
@ -20,7 +20,7 @@ function setSnappedViewstate() {
|
||||
browser.style.borderRight = padding + "px solid gray";
|
||||
|
||||
// Communicate viewstate change
|
||||
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'snapped');
|
||||
ContentAreaObserver._updateViewState("snapped");
|
||||
|
||||
// Make sure it renders the new mode properly
|
||||
yield waitForMs(0);
|
||||
@ -36,16 +36,15 @@ function setPortraitViewstate() {
|
||||
|
||||
browser.style.borderRight = padding + "px solid gray";
|
||||
|
||||
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'portrait');
|
||||
ContentAreaObserver._updateViewState("portrait");
|
||||
|
||||
// Make sure it renders the new mode properly
|
||||
yield waitForMs(0);
|
||||
}
|
||||
|
||||
function restoreViewstate() {
|
||||
ok(isLandscapeMode(), "restoreViewstate expects landscape mode to work.");
|
||||
|
||||
Services.obs.notifyObservers(null, 'metro_viewstate_changed', 'landscape');
|
||||
ContentAreaObserver._updateViewState("landscape");
|
||||
ok(isLandscapeMode(), "restoreViewstate should restore landscape mode.");
|
||||
|
||||
Browser.selectedBrowser.style.removeProperty("border-right");
|
||||
|
||||
|
@ -6,10 +6,7 @@
|
||||
{"index":1,"title":"@firefox_about@", "type":"text/x-moz-place", "uri":"http://www.mozilla.org/@AB_CD@/about/",
|
||||
"iconUri":"chrome://branding/content/favicon32.png"
|
||||
},
|
||||
{"index":2,"title":"@getting_started@", "type":"text/x-moz-place", "uri":"http://www.mozilla.org/@AB_CD@/firefox/central/",
|
||||
"iconUri":"chrome://branding/content/favicon32.png"
|
||||
},
|
||||
{"index":3,"title":"@firefox_community@", "type":"text/x-moz-place", "uri":"http://www.mozilla.org/@AB_CD@/contribute/",
|
||||
{"index":2,"title":"@firefox_community@", "type":"text/x-moz-place", "uri":"http://www.mozilla.org/@AB_CD@/contribute/",
|
||||
"iconUri":"chrome://branding/content/favicon32.png"
|
||||
}
|
||||
]
|
||||
|
@ -23,10 +23,23 @@ function makeURI(aURL, aOriginCharset, aBaseURI) {
|
||||
// --------------------------------
|
||||
// View prototype for shared functionality
|
||||
|
||||
function View() {
|
||||
function View(aSet) {
|
||||
this._set = aSet;
|
||||
this._set.controller = this;
|
||||
|
||||
this.viewStateObserver = {
|
||||
observe: (aSubject, aTopic, aData) => this._adjustDOMforViewState(aData)
|
||||
};
|
||||
Services.obs.addObserver(this.viewStateObserver, "metro_viewstate_changed", false);
|
||||
|
||||
this._adjustDOMforViewState();
|
||||
}
|
||||
|
||||
View.prototype = {
|
||||
destruct: function () {
|
||||
Services.obs.removeObserver(this.viewStateObserver, "metro_viewstate_changed");
|
||||
},
|
||||
|
||||
_adjustDOMforViewState: function _adjustDOMforViewState(aState) {
|
||||
if (this._set) {
|
||||
if (undefined == aState)
|
||||
@ -44,10 +57,6 @@ View.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
onViewStateChange: function (aState) {
|
||||
this._adjustDOMforViewState(aState);
|
||||
},
|
||||
|
||||
_updateFavicon: function pv__updateFavicon(aItem, aUri) {
|
||||
if ("string" == typeof aUri) {
|
||||
aUri = makeURI(aUri);
|
||||
|
@ -377,6 +377,9 @@ pref("geo.wifi.uri", "https://www.googleapis.com/geolocation/v1/geolocate?key=%G
|
||||
// JS error console
|
||||
pref("devtools.errorconsole.enabled", false);
|
||||
|
||||
// snapped view
|
||||
pref("browser.ui.snapped.maxWidth", 600);
|
||||
|
||||
// kinetic tweakables
|
||||
pref("browser.ui.kinetic.updateInterval", 16);
|
||||
pref("browser.ui.kinetic.exponentialC", 1400);
|
||||
|
@ -375,6 +375,7 @@ documenttab[selected] .documenttab-selection {
|
||||
background-position: left 6px center;
|
||||
}
|
||||
|
||||
#stack[viewstate="snapped"] > .overlay-button,
|
||||
#stack[keyboardVisible] > .overlay-button,
|
||||
#stack[autocomplete] > .overlay-button,
|
||||
#stack[fullscreen] > .overlay-button,
|
||||
|
@ -64,6 +64,9 @@ this.TabCrashReporter = {
|
||||
},
|
||||
|
||||
onAboutTabCrashedLoad: function (aBrowser) {
|
||||
if (!this.childMap)
|
||||
return;
|
||||
|
||||
let dumpID = this.childMap.get(this.browserMap.get(aBrowser));
|
||||
if (!dumpID)
|
||||
return;
|
||||
|
@ -294,7 +294,7 @@ case "$target" in
|
||||
# The build tools got moved around to different directories in
|
||||
# SDK Tools r22. Try to locate them.
|
||||
android_build_tools=""
|
||||
for suffix in android-4.3 18.0.1 18.0.0 17.0.0 android-4.2.2; do
|
||||
for suffix in android-4.3 18.1.0 18.0.1 18.0.0 17.0.0 android-4.2.2; do
|
||||
tools_directory="$android_sdk/../../build-tools/$suffix"
|
||||
if test -d "$tools_directory" ; then
|
||||
android_build_tools="$tools_directory"
|
||||
|
@ -4347,6 +4347,13 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI *aURI,
|
||||
nsCOMPtr<Element> element = do_QueryInterface(handler);
|
||||
element->GetAttribute(NS_LITERAL_STRING("crashedPageTitle"), messageStr);
|
||||
}
|
||||
|
||||
// DisplayLoadError requires a non-empty messageStr to proceed and call LoadErrorPage.
|
||||
// If the page doesn't have a title, we will use a blank space which will be trimmed
|
||||
// and thus treated as empty by the front-end.
|
||||
if (messageStr.IsEmpty()) {
|
||||
messageStr.Assign(NS_LITERAL_STRING(" "));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Errors requiring simple formatting
|
||||
@ -4591,8 +4598,26 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
|
||||
errorPageUrl.AppendLiteral("&d=");
|
||||
errorPageUrl.AppendASCII(escapedDescription.get());
|
||||
|
||||
// Append the manifest URL if the error comes from an app.
|
||||
uint32_t appId;
|
||||
nsresult rv = GetAppId(&appId);
|
||||
if (appId != nsIScriptSecurityManager::NO_APP_ID &&
|
||||
appId != nsIScriptSecurityManager::UNKNOWN_APP_ID) {
|
||||
nsCOMPtr<nsIAppsService> appsService =
|
||||
do_GetService(APPS_SERVICE_CONTRACTID);
|
||||
NS_ASSERTION(appsService, "No AppsService available");
|
||||
nsAutoString manifestURL;
|
||||
appsService->GetManifestURLByLocalId(appId, manifestURL);
|
||||
nsCString manifestParam;
|
||||
SAFE_ESCAPE(manifestParam,
|
||||
NS_ConvertUTF16toUTF8(manifestURL).get(),
|
||||
url_Path);
|
||||
errorPageUrl.AppendLiteral("&m=");
|
||||
errorPageUrl.AppendASCII(manifestParam.get());
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIURI> errorPageURI;
|
||||
nsresult rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
|
||||
rv = NS_NewURI(getter_AddRefs(errorPageURI), errorPageUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return InternalLoad(errorPageURI, nullptr, nullptr,
|
||||
|
@ -33,5 +33,3 @@ phishingBlocked=The website at %S has been reported as a web forgery designed to
|
||||
cspFrameAncestorBlocked=This page has a content security policy that prevents it from being embedded in this way.
|
||||
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default.
|
||||
#LOCALIZATION NOTE (tabcrashed): The following string is shown in the tab title if a page with a blank title has crashed. Current UX says that the tab title should remain blank
|
||||
tabcrashed=
|
||||
|
@ -1426,7 +1426,12 @@ gfxFT2FontList::GetDefaultFont(const gfxFontStyle* aStyle)
|
||||
return FindFamily(resolvedName);
|
||||
}
|
||||
}
|
||||
#elif defined(ANDROID)
|
||||
#elif defined(MOZ_WIDGET_GONK)
|
||||
nsAutoString resolvedName;
|
||||
if (ResolveFontName(NS_LITERAL_STRING("Fira Sans OT"), resolvedName)) {
|
||||
return FindFamily(resolvedName);
|
||||
}
|
||||
#elif defined(MOZ_WIDGET_ANDROID)
|
||||
nsAutoString resolvedName;
|
||||
if (ResolveFontName(NS_LITERAL_STRING("Roboto"), resolvedName) ||
|
||||
ResolveFontName(NS_LITERAL_STRING("Droid Sans"), resolvedName)) {
|
||||
|
@ -294,7 +294,7 @@ case "$target" in
|
||||
# The build tools got moved around to different directories in
|
||||
# SDK Tools r22. Try to locate them.
|
||||
android_build_tools=""
|
||||
for suffix in android-4.3 18.0.1 18.0.0 17.0.0 android-4.2.2; do
|
||||
for suffix in android-4.3 18.1.0 18.0.1 18.0.0 17.0.0 android-4.2.2; do
|
||||
tools_directory="$android_sdk/../../build-tools/$suffix"
|
||||
if test -d "$tools_directory" ; then
|
||||
android_build_tools="$tools_directory"
|
||||
|
@ -43,7 +43,7 @@ fuzzy-if(azureSkiaGL,10,400) == text-not-in-doc-test.html text-not-in-doc-ref.ht
|
||||
!= text-bidi-ltr-test.html text-bidi-ltr-notref.html # for bug 698185
|
||||
== text-bidi-rtl-test.html text-bidi-rtl-ref.html
|
||||
|
||||
!= text-font-lang.html text-font-lang-notref.html
|
||||
skip-if(B2G) != text-font-lang.html text-font-lang-notref.html
|
||||
|
||||
== text-measure.html text-measure-ref.html
|
||||
|
||||
|
@ -181,9 +181,6 @@ abstract public class GeckoApp
|
||||
protected TabsPanel mTabsPanel;
|
||||
protected ButtonToast mToast;
|
||||
|
||||
// Handles notification messages from javascript
|
||||
protected NotificationHelper mNotificationHelper;
|
||||
|
||||
protected LayerView mLayerView;
|
||||
private AbsoluteLayout mPluginContainer;
|
||||
|
||||
@ -1235,7 +1232,6 @@ abstract public class GeckoApp
|
||||
|
||||
// Set up tabs panel.
|
||||
mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel);
|
||||
mNotificationHelper = new NotificationHelper(this);
|
||||
mToast = new ButtonToast(findViewById(R.id.toast));
|
||||
|
||||
// Determine whether we should restore tabs.
|
||||
@ -1796,11 +1792,6 @@ abstract public class GeckoApp
|
||||
alertCookie = "";
|
||||
}
|
||||
handleNotification(ACTION_ALERT_CALLBACK, alertName, alertCookie);
|
||||
|
||||
if (intent.hasExtra(NotificationHelper.NOTIFICATION_ID)) {
|
||||
String id = intent.getStringExtra(NotificationHelper.NOTIFICATION_ID);
|
||||
mNotificationHelper.hideNotification(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -2045,8 +2036,6 @@ abstract public class GeckoApp
|
||||
mPromptService.destroy();
|
||||
if (mTextSelection != null)
|
||||
mTextSelection.destroy();
|
||||
if (mNotificationHelper != null)
|
||||
mNotificationHelper.destroy();
|
||||
|
||||
if (SmsManager.getInstance() != null) {
|
||||
SmsManager.getInstance().stop();
|
||||
|
@ -1330,12 +1330,6 @@ public class GeckoAppShell
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Also send a notification to the observer service
|
||||
// New listeners should register for these notifications since they will be called even if
|
||||
// Gecko has been killed and restared between when your notification was shown and when the
|
||||
// user clicked on it.
|
||||
sendEventToGecko(GeckoEvent.createBroadcastEvent("Notification:Clicked", aAlertCookie));
|
||||
closeNotification(aAlertName);
|
||||
}
|
||||
|
||||
|
@ -98,6 +98,7 @@ public class GeckoApplication extends Application {
|
||||
public void onCreate() {
|
||||
HardwareUtils.init(getApplicationContext());
|
||||
Clipboard.init(getApplicationContext());
|
||||
NotificationHelper.init(getApplicationContext());
|
||||
GeckoLoader.loadMozGlue();
|
||||
super.onCreate();
|
||||
}
|
||||
|
@ -649,7 +649,7 @@ RES_DRAWABLE_MDPI = \
|
||||
res/drawable-mdpi/ic_menu_bookmark_add.png \
|
||||
res/drawable-mdpi/ic_menu_bookmark_remove.png \
|
||||
res/drawable-mdpi/ic_menu_character_encoding.png \
|
||||
res/drawable-mdpi/ic_menu_close_all_tabs.png \
|
||||
res/drawable-mdpi/close.png \
|
||||
res/drawable-mdpi/ic_menu_forward.png \
|
||||
res/drawable-mdpi/ic_menu_guest.png \
|
||||
res/drawable-mdpi/ic_menu_new_private_tab.png \
|
||||
@ -671,6 +671,8 @@ RES_DRAWABLE_MDPI = \
|
||||
res/drawable-mdpi/icon_pageaction.png \
|
||||
res/drawable-mdpi/icon_reading_list_empty.png \
|
||||
res/drawable-mdpi/progress_spinner.png \
|
||||
res/drawable-mdpi/play.png \
|
||||
res/drawable-mdpi/pause.png \
|
||||
res/drawable-mdpi/tab_indicator_divider.9.png \
|
||||
res/drawable-mdpi/tab_indicator_selected.9.png \
|
||||
res/drawable-mdpi/tab_indicator_selected_focused.9.png \
|
||||
@ -763,7 +765,7 @@ RES_DRAWABLE_HDPI = \
|
||||
res/drawable-hdpi/ic_menu_bookmark_add.png \
|
||||
res/drawable-hdpi/ic_menu_bookmark_remove.png \
|
||||
res/drawable-hdpi/ic_menu_character_encoding.png \
|
||||
res/drawable-hdpi/ic_menu_close_all_tabs.png \
|
||||
res/drawable-hdpi/close.png \
|
||||
res/drawable-hdpi/ic_menu_forward.png \
|
||||
res/drawable-hdpi/ic_menu_guest.png \
|
||||
res/drawable-hdpi/ic_menu_new_private_tab.png \
|
||||
@ -818,6 +820,8 @@ RES_DRAWABLE_HDPI = \
|
||||
res/drawable-hdpi/menu_item_more.png \
|
||||
res/drawable-hdpi/menu_item_uncheck.png \
|
||||
res/drawable-hdpi/pin.png \
|
||||
res/drawable-hdpi/play.png \
|
||||
res/drawable-hdpi/pause.png \
|
||||
res/drawable-hdpi/shield.png \
|
||||
res/drawable-hdpi/shield_doorhanger.png \
|
||||
res/drawable-hdpi/tabs_normal.png \
|
||||
@ -862,7 +866,7 @@ RES_DRAWABLE_XHDPI = \
|
||||
res/drawable-xhdpi/ic_menu_addons_filler.png \
|
||||
res/drawable-xhdpi/ic_menu_bookmark_add.png \
|
||||
res/drawable-xhdpi/ic_menu_bookmark_remove.png \
|
||||
res/drawable-xhdpi/ic_menu_close_all_tabs.png \
|
||||
res/drawable-xhdpi/close.png \
|
||||
res/drawable-xhdpi/ic_menu_character_encoding.png \
|
||||
res/drawable-xhdpi/ic_menu_forward.png \
|
||||
res/drawable-xhdpi/ic_menu_guest.png \
|
||||
@ -917,6 +921,8 @@ RES_DRAWABLE_XHDPI = \
|
||||
res/drawable-xhdpi/menu_item_more.png \
|
||||
res/drawable-xhdpi/menu_item_uncheck.png \
|
||||
res/drawable-xhdpi/pin.png \
|
||||
res/drawable-xhdpi/play.png \
|
||||
res/drawable-xhdpi/pause.png \
|
||||
res/drawable-xhdpi/shield.png \
|
||||
res/drawable-xhdpi/shield_doorhanger.png \
|
||||
res/drawable-xhdpi/tab_indicator_divider.9.png \
|
||||
|
@ -14,6 +14,8 @@ import org.json.JSONObject;
|
||||
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.Bitmap;
|
||||
@ -24,21 +26,59 @@ import android.util.Log;
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class NotificationHelper implements GeckoEventListener {
|
||||
public final class NotificationHelper implements GeckoEventListener {
|
||||
public static final String NOTIFICATION_ID = "NotificationHelper_ID";
|
||||
private static final String LOGTAG = "GeckoNotificationManager";
|
||||
private Context mContext;
|
||||
private Set<String> mShowing;
|
||||
private static final String HELPER_NOTIFICATION = "helperNotif";
|
||||
private static final String HELPER_BROADCAST_ACTION = "helperBroadcastAction";
|
||||
|
||||
public NotificationHelper(Context context) {
|
||||
// Attributes mandatory to be used while sending a notification from js.
|
||||
private static final String TITLE_ATTR = "title";
|
||||
private static final String TEXT_ATTR = "text";
|
||||
private static final String ID_ATTR = "id";
|
||||
private static final String SMALLICON_ATTR = "smallIcon";
|
||||
|
||||
// Attributes that can be used while sending a notification from js.
|
||||
private static final String PROGRESS_VALUE_ATTR = "progress_value";
|
||||
private static final String PROGRESS_MAX_ATTR = "progress_max";
|
||||
private static final String LIGHT_ATTR = "light";
|
||||
private static final String ONGOING_ATTR = "ongoing";
|
||||
private static final String WHEN_ATTR = "when";
|
||||
private static final String LARGE_ICON_ATTR = "largeIcon";
|
||||
private static final String COOKIE_ATTR = "cookie";
|
||||
private static final String EVENT_TYPE_ATTR = "eventType";
|
||||
private static final String ACTIONS_ATTR = "actions";
|
||||
private static final String ACTION_ATTR = "actionKind";
|
||||
private static final String ACTION_TITLE_ATTR = "title";
|
||||
private static final String ACTION_ICON_ATTR = "icon";
|
||||
|
||||
private static final String NOTIFICATION_SCHEME = "moz-notification";
|
||||
|
||||
private static final String CLICK_EVENT = "notification-clicked";
|
||||
private static final String CLEARED_EVENT = "notification-cleared";
|
||||
|
||||
private static Context mContext;
|
||||
private static Set<String> mShowing;
|
||||
private static BroadcastReceiver mReceiver;
|
||||
private static NotificationHelper mInstance;
|
||||
|
||||
private NotificationHelper() {
|
||||
}
|
||||
|
||||
public static void init(Context context) {
|
||||
if (mInstance != null) {
|
||||
Log.w(LOGTAG, "NotificationHelper.init() called twice!");
|
||||
}
|
||||
mInstance = new NotificationHelper();
|
||||
mContext = context;
|
||||
mShowing = new HashSet<String>();
|
||||
registerEventListener("Notification:Show");
|
||||
registerEventListener("Notification:Hide");
|
||||
registerReceiver(context);
|
||||
}
|
||||
|
||||
private void registerEventListener(String event) {
|
||||
GeckoAppShell.getEventDispatcher().registerEventListener(event, this);
|
||||
private static void registerEventListener(String event) {
|
||||
GeckoAppShell.getEventDispatcher().registerEventListener(event, mInstance);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -50,24 +90,107 @@ public class NotificationHelper implements GeckoEventListener {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isHelperIntent(Intent i) {
|
||||
return i.getBooleanExtra(HELPER_NOTIFICATION, false);
|
||||
}
|
||||
|
||||
private static void registerReceiver(Context context) {
|
||||
IntentFilter filter = new IntentFilter(HELPER_BROADCAST_ACTION);
|
||||
// Scheme is needed, otherwise only broadcast with no data will be catched.
|
||||
filter.addDataScheme(NOTIFICATION_SCHEME);
|
||||
mReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mInstance.handleNotificationIntent(intent);
|
||||
}
|
||||
};
|
||||
context.registerReceiver(mReceiver, filter);
|
||||
}
|
||||
|
||||
|
||||
private void handleNotificationIntent(Intent i) {
|
||||
final Uri data = i.getData();
|
||||
if (data == null) {
|
||||
Log.w(LOGTAG, "handleNotificationEvent: empty data");
|
||||
return;
|
||||
}
|
||||
final String id = data.getQueryParameter(ID_ATTR);
|
||||
final String notificationType = data.getQueryParameter(EVENT_TYPE_ATTR);
|
||||
if (id == null || notificationType == null) {
|
||||
Log.w(LOGTAG, "handleNotificationEvent: invalid intent parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
// In case the user swiped out the notification, we empty the id
|
||||
// set.
|
||||
if (CLEARED_EVENT.equals(notificationType)) {
|
||||
mShowing.remove(id);
|
||||
}
|
||||
|
||||
// If the notification was clicked, we are closing it.
|
||||
if (CLICK_EVENT.equals(notificationType) && !i.getBooleanExtra(ONGOING_ATTR, false)) {
|
||||
hideNotification(id);
|
||||
}
|
||||
String cookie = data.getQueryParameter(COOKIE_ATTR);
|
||||
|
||||
if (GeckoThread.checkLaunchState(GeckoThread.LaunchState.GeckoRunning)) {
|
||||
JSONObject args = new JSONObject();
|
||||
try {
|
||||
args.put(NOTIFICATION_ID, id);
|
||||
if (cookie != null) {
|
||||
args.put(COOKIE_ATTR, cookie);
|
||||
}
|
||||
args.put(EVENT_TYPE_ATTR, notificationType);
|
||||
GeckoAppShell.sendEventToGecko(GeckoEvent.createBroadcastEvent("Notification:Event", args.toString()));
|
||||
} catch (JSONException e) {
|
||||
Log.w(LOGTAG, "Error building JSON notification arguments.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PendingIntent buildNotificationPendingIntent(JSONObject message, String type) {
|
||||
Intent notificationIntent = new Intent(HELPER_BROADCAST_ACTION);
|
||||
final boolean ongoing = message.optBoolean(ONGOING_ATTR);
|
||||
notificationIntent.putExtra(ONGOING_ATTR, ongoing);
|
||||
|
||||
Uri.Builder b = new Uri.Builder();
|
||||
b.scheme(NOTIFICATION_SCHEME).appendQueryParameter(EVENT_TYPE_ATTR, type);
|
||||
|
||||
try {
|
||||
final String id = message.getString(ID_ATTR);
|
||||
b.appendQueryParameter(ID_ATTR, id);
|
||||
if (message.has(COOKIE_ATTR)) {
|
||||
b.appendQueryParameter(COOKIE_ATTR,
|
||||
message.getString(COOKIE_ATTR));
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
Log.i(LOGTAG, "buildNotificationPendingIntent, error parsing", ex);
|
||||
}
|
||||
final Uri dataUri = b.build();
|
||||
notificationIntent.setData(dataUri);
|
||||
notificationIntent.putExtra(HELPER_NOTIFICATION, true);
|
||||
PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
return pi;
|
||||
}
|
||||
|
||||
private void showNotification(JSONObject message) {
|
||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext);
|
||||
|
||||
// These attributes are required
|
||||
final String id;
|
||||
try {
|
||||
builder.setContentTitle(message.getString("title"));
|
||||
builder.setContentText(message.getString("text"));
|
||||
id = message.getString("id");
|
||||
builder.setContentTitle(message.getString(TITLE_ATTR));
|
||||
builder.setContentText(message.getString(TEXT_ATTR));
|
||||
id = message.getString(ID_ATTR);
|
||||
} catch (JSONException ex) {
|
||||
Log.i(LOGTAG, "Error parsing", ex);
|
||||
return;
|
||||
}
|
||||
|
||||
Uri imageUri = Uri.parse(message.optString("smallicon"));
|
||||
Uri imageUri = Uri.parse(message.optString(SMALLICON_ATTR));
|
||||
builder.setSmallIcon(BitmapUtils.getResource(imageUri, R.drawable.ic_status_logo));
|
||||
|
||||
JSONArray light = message.optJSONArray("light");
|
||||
JSONArray light = message.optJSONArray(LIGHT_ATTR);
|
||||
if (light != null && light.length() == 3) {
|
||||
try {
|
||||
builder.setLights(light.getInt(0),
|
||||
@ -78,33 +201,51 @@ public class NotificationHelper implements GeckoEventListener {
|
||||
}
|
||||
}
|
||||
|
||||
boolean ongoing = message.optBoolean("ongoing");
|
||||
boolean ongoing = message.optBoolean(ONGOING_ATTR);
|
||||
builder.setOngoing(ongoing);
|
||||
|
||||
if (message.has("when")) {
|
||||
int when = message.optInt("when");
|
||||
if (message.has(WHEN_ATTR)) {
|
||||
int when = message.optInt(WHEN_ATTR);
|
||||
builder.setWhen(when);
|
||||
}
|
||||
|
||||
if (message.has("largeicon")) {
|
||||
Bitmap b = BitmapUtils.getBitmapFromDataURI(message.optString("largeicon"));
|
||||
if (message.has(LARGE_ICON_ATTR)) {
|
||||
Bitmap b = BitmapUtils.getBitmapFromDataURI(message.optString(LARGE_ICON_ATTR));
|
||||
builder.setLargeIcon(b);
|
||||
}
|
||||
|
||||
// We currently don't support a callback when these are clicked.
|
||||
// Instead we just open fennec.
|
||||
Intent notificationIntent = new Intent(GeckoApp.ACTION_ALERT_CALLBACK);
|
||||
String app = mContext.getClass().getName();
|
||||
notificationIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, app);
|
||||
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
// if this isn't an ongoing notification, add the id to the intent so that we
|
||||
// can remove the notification from our list of active notifications if its clicked
|
||||
if (!ongoing) {
|
||||
notificationIntent.putExtra(NOTIFICATION_ID, id);
|
||||
if (message.has(PROGRESS_VALUE_ATTR) &&
|
||||
message.has(PROGRESS_MAX_ATTR)) {
|
||||
try {
|
||||
final int progress = message.getInt(PROGRESS_VALUE_ATTR);
|
||||
final int progressMax = message.getInt(PROGRESS_MAX_ATTR);
|
||||
builder.setProgress(progressMax, progress, false);
|
||||
} catch (JSONException ex) {
|
||||
Log.i(LOGTAG, "Error parsing", ex);
|
||||
}
|
||||
}
|
||||
|
||||
PendingIntent pi = PendingIntent.getActivity(mContext, 0, notificationIntent, 0);
|
||||
JSONArray actions = message.optJSONArray(ACTIONS_ATTR);
|
||||
if (actions != null) {
|
||||
try {
|
||||
for (int i = 0; i < actions.length(); i++) {
|
||||
JSONObject action = actions.getJSONObject(i);
|
||||
final PendingIntent pending = buildNotificationPendingIntent(message, action.getString(ACTION_ATTR));
|
||||
final String actionTitle = action.getString(ACTION_TITLE_ATTR);
|
||||
final Uri actionImage = Uri.parse(action.optString(ACTION_ICON_ATTR));
|
||||
builder.addAction(BitmapUtils.getResource(actionImage, R.drawable.ic_status_logo),
|
||||
actionTitle,
|
||||
pending);
|
||||
}
|
||||
} catch (JSONException ex) {
|
||||
Log.i(LOGTAG, "Error parsing", ex);
|
||||
}
|
||||
}
|
||||
|
||||
PendingIntent pi = buildNotificationPendingIntent(message, CLICK_EVENT);
|
||||
builder.setContentIntent(pi);
|
||||
PendingIntent deletePendingIntent = buildNotificationPendingIntent(message, CLEARED_EVENT);
|
||||
builder.setDeleteIntent(deletePendingIntent);
|
||||
|
||||
GeckoAppShell.sNotificationClient.add(id.hashCode(), builder.build());
|
||||
if (!mShowing.contains(id)) {
|
||||
@ -134,8 +275,4 @@ public class NotificationHelper implements GeckoEventListener {
|
||||
hideNotification(id);
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
clearAll();
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 377 B After Width: | Height: | Size: 377 B |
After Width: | Height: | Size: 763 B |
After Width: | Height: | Size: 362 B |
After Width: | Height: | Size: 670 B |
BIN
mobile/android/base/resources/drawable-hdpi/pause.png
Normal file
After Width: | Height: | Size: 450 B |
BIN
mobile/android/base/resources/drawable-hdpi/play.png
Normal file
After Width: | Height: | Size: 611 B |
Before Width: | Height: | Size: 277 B After Width: | Height: | Size: 277 B |
After Width: | Height: | Size: 497 B |
After Width: | Height: | Size: 252 B |
After Width: | Height: | Size: 463 B |
BIN
mobile/android/base/resources/drawable-mdpi/pause.png
Normal file
After Width: | Height: | Size: 380 B |
BIN
mobile/android/base/resources/drawable-mdpi/play.png
Normal file
After Width: | Height: | Size: 479 B |
Before Width: | Height: | Size: 594 B After Width: | Height: | Size: 594 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 389 B |
After Width: | Height: | Size: 853 B |
BIN
mobile/android/base/resources/drawable-xhdpi/pause.png
Normal file
After Width: | Height: | Size: 467 B |
BIN
mobile/android/base/resources/drawable-xhdpi/play.png
Normal file
After Width: | Height: | Size: 550 B |
@ -62,6 +62,11 @@
|
||||
android:icon="@drawable/ic_menu_apps"
|
||||
android:title="@string/apps"/>
|
||||
|
||||
<item android:id="@+id/new_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
android:title="@string/new_guest_session"/>
|
||||
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
@ -75,11 +80,6 @@
|
||||
android:icon="@drawable/ic_menu_settings"
|
||||
android:title="@string/settings" />
|
||||
|
||||
<item android:id="@+id/new_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
android:title="@string/new_guest_session"/>
|
||||
|
||||
<item android:id="@+id/exit_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
|
@ -63,6 +63,11 @@
|
||||
android:icon="@drawable/ic_menu_apps"
|
||||
android:title="@string/apps"/>
|
||||
|
||||
<item android:id="@+id/new_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
android:title="@string/new_guest_session"/>
|
||||
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
@ -76,11 +81,6 @@
|
||||
android:icon="@drawable/ic_menu_settings"
|
||||
android:title="@string/settings" />
|
||||
|
||||
<item android:id="@+id/new_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
android:title="@string/new_guest_session"/>
|
||||
|
||||
<item android:id="@+id/exit_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
|
@ -63,6 +63,11 @@
|
||||
android:icon="@drawable/ic_menu_apps"
|
||||
android:title="@string/apps"/>
|
||||
|
||||
<item android:id="@+id/new_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
android:title="@string/new_guest_session"/>
|
||||
|
||||
</menu>
|
||||
|
||||
</item>
|
||||
@ -76,11 +81,6 @@
|
||||
android:icon="@drawable/ic_menu_settings"
|
||||
android:title="@string/settings" />
|
||||
|
||||
<item android:id="@+id/new_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
android:title="@string/new_guest_session"/>
|
||||
|
||||
<item android:id="@+id/exit_guest_session"
|
||||
android:icon="@drawable/ic_menu_guest"
|
||||
android:visible="false"
|
||||
|
@ -2,6 +2,7 @@
|
||||
package @ANDROID_PACKAGE_NAME@.tests;
|
||||
|
||||
import @ANDROID_PACKAGE_NAME@.*;
|
||||
import android.os.Build;
|
||||
|
||||
abstract class PixelTest extends BaseTest {
|
||||
private static final long PAINT_CLEAR_DELAY = 10000; // milliseconds
|
||||
@ -9,7 +10,11 @@ abstract class PixelTest extends BaseTest {
|
||||
protected final PaintedSurface loadAndGetPainted(String url) {
|
||||
Actions.RepeatedEventExpecter paintExpecter = mActions.expectPaint();
|
||||
loadUrl(url);
|
||||
verifyHomePagerHidden();
|
||||
// Skip this on the Tegras (Android 2.2) since they are too slow,
|
||||
// which results in too many intermittent failures.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {
|
||||
verifyHomePagerHidden();
|
||||
}
|
||||
paintExpecter.blockUntilClear(PAINT_CLEAR_DELAY);
|
||||
paintExpecter.unregisterListener();
|
||||
PaintedSurface p = mDriver.getPaintedSurface();
|
||||
|
@ -143,12 +143,18 @@ public class testSettingsMenuItems extends PixelTest {
|
||||
ClassLoader classLoader = getActivity().getClassLoader();
|
||||
Class appConstants = classLoader.loadClass("org.mozilla.gecko.AppConstants");
|
||||
|
||||
// Text reflow
|
||||
Field textReflowField = appConstants.getField("RELEASE_BUILD");
|
||||
boolean textReflow = textReflowField.getBoolean(appConstants);
|
||||
if (textReflow) {
|
||||
// Preferences dependent on RELEASE_BUILD
|
||||
Field releaseBuildField = appConstants.getField("RELEASE_BUILD");
|
||||
boolean releaseBuild = releaseBuildField.getBoolean(appConstants);
|
||||
if (!releaseBuild) {
|
||||
// Text reflow - only built if *not* release build
|
||||
String[] textReflowUi = { "Text reflow" };
|
||||
settingsMap.get("Display").add(textReflowUi);
|
||||
|
||||
// Anonymous cell tower/wifi collection - only built if *not* release build
|
||||
String[] networkReportingUi = { "Mozilla location services", "Help improve geolocation services for the Open Web by letting " + BRAND_NAME + " collect and send anonymous cellular tower data" };
|
||||
settingsMap.get("Mozilla").add(networkReportingUi);
|
||||
|
||||
}
|
||||
|
||||
// Automatic updates
|
||||
@ -167,14 +173,6 @@ public class testSettingsMenuItems extends PixelTest {
|
||||
settingsMap.get("Mozilla").add(crashReporterUi);
|
||||
}
|
||||
|
||||
// Anonymous cell tower/wifi collection; built if *not* a RELEASE_BUILD
|
||||
Field releaseBuildField = appConstants.getField("RELEASE_BUILD");
|
||||
boolean releaseBuild = releaseBuildField.getBoolean(appConstants);
|
||||
if (!releaseBuild) {
|
||||
String[] networkReportingUi = { "Mozilla location services", "Help improve geolocation services for the Open Web by letting " + BRAND_NAME + " collect and send anonymous cellular tower data" };
|
||||
settingsMap.get("Mozilla").add(networkReportingUi);
|
||||
}
|
||||
|
||||
// Telemetry
|
||||
Field telemetryField = appConstants.getField("MOZ_TELEMETRY_REPORTING");
|
||||
boolean telemetry = telemetryField.getBoolean(appConstants);
|
||||
|
@ -5136,10 +5136,16 @@ var FormAssistant = {
|
||||
|
||||
// Reset invalid submit state on each pageshow
|
||||
case "pageshow":
|
||||
let target = aEvent.originalTarget;
|
||||
let selectedDocument = BrowserApp.selectedBrowser.contentDocument;
|
||||
if (target == selectedDocument || target.ownerDocument == selectedDocument)
|
||||
this._invalidSubmit = false;
|
||||
if (!this._invalidSubmit)
|
||||
return;
|
||||
|
||||
let selectedBrowser = BrowserApp.selectedBrowser;
|
||||
if (selectedBrowser) {
|
||||
let selectedDocument = selectedBrowser.contentDocument;
|
||||
let target = aEvent.originalTarget;
|
||||
if (target == selectedDocument || target.ownerDocument == selectedDocument)
|
||||
this._invalidSubmit = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -10,6 +10,27 @@ function dump(a) {
|
||||
}
|
||||
|
||||
const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download";
|
||||
const URI_PAUSE_ICON = "drawable://pause";
|
||||
const URI_CANCEL_ICON = "drawable://close";
|
||||
const URI_RESUME_ICON = "drawable://play";
|
||||
|
||||
const PAUSE_ACTION = {
|
||||
actionKind : "pause",
|
||||
title : Strings.browser.GetStringFromName("alertDownloadsPause"),
|
||||
icon : URI_PAUSE_ICON
|
||||
};
|
||||
|
||||
const CANCEL_ACTION = {
|
||||
actionKind : "cancel",
|
||||
title : Strings.browser.GetStringFromName("alertDownloadsCancel"),
|
||||
icon : URI_CANCEL_ICON
|
||||
};
|
||||
|
||||
const RESUME_ACTION = {
|
||||
actionKind : "resume",
|
||||
title : Strings.browser.GetStringFromName("alertDownloadsResume"),
|
||||
icon : URI_RESUME_ICON
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
|
||||
|
||||
@ -18,6 +39,7 @@ var Downloads = {
|
||||
_dlmgr: null,
|
||||
_progressAlert: null,
|
||||
_privateDownloads: [],
|
||||
_showingPrompt: false,
|
||||
|
||||
_getLocalFile: function dl__getLocalFile(aFileURI) {
|
||||
// if this is a URL, get the file from that
|
||||
@ -36,6 +58,7 @@ var Downloads = {
|
||||
this._progressAlert = new AlertDownloadProgressListener();
|
||||
this._dlmgr.addPrivacyAwareListener(this._progressAlert);
|
||||
Services.obs.addObserver(this, "last-pb-context-exited", true);
|
||||
Services.obs.addObserver(this, "Notification:Event", true);
|
||||
},
|
||||
|
||||
openDownload: function dl_openDownload(aDownload) {
|
||||
@ -60,61 +83,113 @@ var Downloads = {
|
||||
OS.File.remove(f.path);
|
||||
},
|
||||
|
||||
showAlert: function dl_showAlert(aDownload, aMessage, aTitle, aIcon) {
|
||||
let self = this;
|
||||
getNotificationIdFromDownload: function dl_getNotificationIdFromDownload(aDownload) {
|
||||
return aDownload.target.spec.replace("file:", "download:");
|
||||
},
|
||||
|
||||
// Use this flag to make sure we only show one prompt at a time
|
||||
let cancelPrompt = false;
|
||||
|
||||
// Callback for tapping on the alert popup
|
||||
let observer = {
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
if (aTopic == "alertclickcallback") {
|
||||
if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED) {
|
||||
// Only open the downloaded file if the download is complete
|
||||
self.openDownload(aDownload);
|
||||
} else if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING &&
|
||||
!cancelPrompt) {
|
||||
cancelPrompt = true;
|
||||
// Open a prompt that offers a choice to cancel the download
|
||||
let title = Strings.browser.GetStringFromName("downloadCancelPromptTitle");
|
||||
let message = Strings.browser.GetStringFromName("downloadCancelPromptMessage");
|
||||
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_YES +
|
||||
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_NO;
|
||||
|
||||
let choice = Services.prompt.confirmEx(null, title, message, flags,
|
||||
null, null, null, null, {});
|
||||
if (choice == 0)
|
||||
self.cancelDownload(aDownload);
|
||||
cancelPrompt = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
showNotification: function dl_showNotification(aDownload, aMessage, aTitle, aOptions) {
|
||||
let msg = {
|
||||
type: "Notification:Show",
|
||||
id: this.getNotificationIdFromDownload(aDownload),
|
||||
title: aTitle,
|
||||
smallIcon: URI_GENERIC_ICON_DOWNLOAD,
|
||||
text: aMessage,
|
||||
ongoing: false,
|
||||
cookie: aDownload.guid
|
||||
};
|
||||
|
||||
if (!aIcon)
|
||||
aIcon = URI_GENERIC_ICON_DOWNLOAD;
|
||||
|
||||
if (aDownload.isPrivate) {
|
||||
this._privateDownloads.push(aDownload);
|
||||
if (aOptions && aOptions.icon) {
|
||||
msg.smallIcon = aOptions.icon;
|
||||
}
|
||||
|
||||
var notifier = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
notifier.showAlertNotification(aIcon, aTitle, aMessage, true, "", observer,
|
||||
aDownload.target.spec.replace("file:", "download:"));
|
||||
if (aOptions && aOptions.percentComplete) {
|
||||
msg.progress_value = aOptions.percentComplete;
|
||||
msg.progress_max = 100;
|
||||
}
|
||||
if (aOptions && aOptions.actions) {
|
||||
msg.actions = aOptions.actions;
|
||||
}
|
||||
if (aOptions && aOptions.ongoing) {
|
||||
msg.ongoing = aOptions.ongoing;
|
||||
}
|
||||
this._bridge.handleGeckoMessage(JSON.stringify(msg));
|
||||
},
|
||||
|
||||
removeNotification: function dl_removeNotification(aDownload) {
|
||||
let msg = {
|
||||
type: "Notification:Hide",
|
||||
id: this.getNotificationIdFromDownload(aDownload)
|
||||
};
|
||||
this._bridge.handleGeckoMessage(JSON.stringify(msg));
|
||||
},
|
||||
|
||||
showCancelConfirmPrompt: function dl_showCancelConfirmPrompt(aDownload) {
|
||||
if (this._showingPrompt)
|
||||
return;
|
||||
this._showingPrompt = true;
|
||||
// Open a prompt that offers a choice to cancel the download
|
||||
let title = Strings.browser.GetStringFromName("downloadCancelPromptTitle");
|
||||
let message = Strings.browser.GetStringFromName("downloadCancelPromptMessage");
|
||||
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_YES +
|
||||
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_NO;
|
||||
let choice = Services.prompt.confirmEx(null, title, message, flags,
|
||||
null, null, null, null, {});
|
||||
if (choice == 0)
|
||||
this.cancelDownload(aDownload);
|
||||
this._showingPrompt = false;
|
||||
},
|
||||
|
||||
handleClickEvent: function dl_handleClickEvent(aDownload) {
|
||||
// Only open the downloaded file if the download is complete
|
||||
if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED)
|
||||
this.openDownload(aDownload);
|
||||
else if (aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_DOWNLOADING ||
|
||||
aDownload.state == Ci.nsIDownloadManager.DOWNLOAD_PAUSED)
|
||||
this.showCancelConfirmPrompt(aDownload);
|
||||
},
|
||||
|
||||
handleNotificationEvent: function dl_handleNotificationEvent(aNotifData, aDownload) {
|
||||
switch (aNotifData.eventType) {
|
||||
case "notification-clicked":
|
||||
this.handleClickEvent(aDownload);
|
||||
break;
|
||||
case "cancel":
|
||||
this.cancelDownload(aDownload);
|
||||
break;
|
||||
case "pause":
|
||||
aDownload.pause();
|
||||
break;
|
||||
case "resume":
|
||||
aDownload.resume();
|
||||
break;
|
||||
case "notification-cleared":
|
||||
// notification cleared by the user
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
// observer for last-pb-context-exited
|
||||
observe: function dl_observe(aSubject, aTopic, aData) {
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener);
|
||||
let download;
|
||||
while ((download = this._privateDownloads.pop())) {
|
||||
try {
|
||||
let notificationName = download.target.spec.replace("file:", "download:");
|
||||
progressListener.onCancel(notificationName);
|
||||
} catch (e) {
|
||||
dump("Error removing private download: " + e);
|
||||
switch (aTopic) {
|
||||
case "Notification:Event": {
|
||||
let data = JSON.parse(aData);
|
||||
let guid = data.cookie;
|
||||
this._dlmgr.getDownloadByGUID(guid, (function(status, download) {
|
||||
if (Components.isSuccessCode(status))
|
||||
this.handleNotificationEvent(data, download);
|
||||
}).bind(this));
|
||||
break;
|
||||
}
|
||||
case "last-pb-context-exited": {
|
||||
let download;
|
||||
while ((download = this._privateDownloads.pop())) {
|
||||
try {
|
||||
Downloads.removeNotification(download);
|
||||
} catch (e) {
|
||||
dump("Error removing private download: " + e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -125,6 +200,12 @@ var Downloads = {
|
||||
!aIID.equals(Ci.nsISupportsWeakReference))
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
return this;
|
||||
},
|
||||
|
||||
get _bridge() {
|
||||
delete this._bridge;
|
||||
return this._bridge = Cc["@mozilla.org/android/bridge;1"].getService(Ci.nsIAndroidBridge);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@ -143,9 +224,8 @@ AlertDownloadProgressListener.prototype = {
|
||||
} catch(ex) { }
|
||||
let contentLength = aDownload.size;
|
||||
if (availableSpace > 0 && contentLength > 0 && contentLength > availableSpace) {
|
||||
Downloads.showAlert(aDownload, strings.GetStringFromName("alertDownloadsNoSpace"),
|
||||
Downloads.showNotification(aDownload, strings.GetStringFromName("alertDownloadsNoSpace"),
|
||||
strings.GetStringFromName("alertDownloadsSize"));
|
||||
|
||||
aDownload.cancel();
|
||||
}
|
||||
|
||||
@ -153,10 +233,11 @@ AlertDownloadProgressListener.prototype = {
|
||||
// Undetermined progress is not supported yet
|
||||
return;
|
||||
}
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener);
|
||||
let notificationName = aDownload.target.spec.replace("file:", "download:");
|
||||
progressListener.onProgress(notificationName, aDownload.percentComplete, 100);
|
||||
Downloads.showNotification(aDownload, aDownload.percentComplete + "%",
|
||||
aDownload.displayName, { percentComplete: aDownload.percentComplete,
|
||||
ongoing: true,
|
||||
actions: [PAUSE_ACTION, CANCEL_ACTION] });
|
||||
|
||||
},
|
||||
|
||||
onDownloadStateChange: function(aState, aDownload) {
|
||||
@ -164,19 +245,21 @@ AlertDownloadProgressListener.prototype = {
|
||||
switch (state) {
|
||||
case Ci.nsIDownloadManager.DOWNLOAD_QUEUED:
|
||||
NativeWindow.toast.show(Strings.browser.GetStringFromName("alertDownloadsToast"), "long");
|
||||
Downloads.showAlert(aDownload, Strings.browser.GetStringFromName("alertDownloadsStart2"),
|
||||
Downloads.showNotification(aDownload, Strings.browser.GetStringFromName("alertDownloadsStart2"),
|
||||
aDownload.displayName);
|
||||
break;
|
||||
case Ci.nsIDownloadManager.DOWNLOAD_PAUSED:
|
||||
Downloads.showNotification(aDownload, aDownload.percentComplete + "%",
|
||||
aDownload.displayName, { percentComplete: aDownload.percentComplete,
|
||||
ongoing: true,
|
||||
actions: [RESUME_ACTION, CANCEL_ACTION] });
|
||||
break;
|
||||
case Ci.nsIDownloadManager.DOWNLOAD_FAILED:
|
||||
case Ci.nsIDownloadManager.DOWNLOAD_CANCELED:
|
||||
case Ci.nsIDownloadManager.DOWNLOAD_BLOCKED_PARENTAL:
|
||||
case Ci.nsIDownloadManager.DOWNLOAD_DIRTY:
|
||||
case Ci.nsIDownloadManager.DOWNLOAD_FINISHED: {
|
||||
let alertsService = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
let progressListener = alertsService.QueryInterface(Ci.nsIAlertsProgressListener);
|
||||
let notificationName = aDownload.target.spec.replace("file:", "download:");
|
||||
progressListener.onCancel(notificationName);
|
||||
|
||||
Downloads.removeNotification(aDownload);
|
||||
if (aDownload.isPrivate) {
|
||||
let index = this._privateDownloads.indexOf(aDownload);
|
||||
if (index != -1) {
|
||||
@ -185,7 +268,7 @@ AlertDownloadProgressListener.prototype = {
|
||||
}
|
||||
|
||||
if (state == Ci.nsIDownloadManager.DOWNLOAD_FINISHED) {
|
||||
Downloads.showAlert(aDownload, Strings.browser.GetStringFromName("alertDownloadsDone2"),
|
||||
Downloads.showNotification(aDownload, Strings.browser.GetStringFromName("alertDownloadsDone2"),
|
||||
aDownload.displayName);
|
||||
}
|
||||
break;
|
||||
|
@ -16,6 +16,9 @@ alertCantOpenDownload=Can't open file. Tap to save it.
|
||||
alertDownloadsSize=Download too big
|
||||
alertDownloadsNoSpace=Not enough storage space
|
||||
alertDownloadsToast=Download started…
|
||||
alertDownloadsPause=Pause
|
||||
alertDownloadsResume=Resume
|
||||
alertDownloadsCancel=Cancel
|
||||
|
||||
alertFullScreenToast=Press BACK to leave full-screen mode
|
||||
|
||||
|
@ -9,9 +9,8 @@ let Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
|
||||
"resource://gre/modules/FormHistory.jsm");
|
||||
Cu.import("resource://gre/modules/LoadContextInfo.jsm");
|
||||
Cu.import("resource://gre/modules/FormHistory.jsm");
|
||||
|
||||
function dump(a) {
|
||||
Services.console.logStringMessage(a);
|
||||
|
@ -349,7 +349,7 @@ nsJARChannel::LookupFile()
|
||||
rv = mJarBaseURI->GetScheme(scheme);
|
||||
if (NS_SUCCEEDED(rv) && scheme.EqualsLiteral("remoteopenfile")) {
|
||||
nsRefPtr<RemoteOpenFileChild> remoteFile = new RemoteOpenFileChild();
|
||||
rv = remoteFile->Init(mJarBaseURI);
|
||||
rv = remoteFile->Init(mJarBaseURI, mAppURI);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
mJarFile = remoteFile;
|
||||
|
||||
|
@ -189,7 +189,7 @@ NeckoChild::DeallocPTCPServerSocketChild(PTCPServerSocketChild* child)
|
||||
}
|
||||
|
||||
PRemoteOpenFileChild*
|
||||
NeckoChild::AllocPRemoteOpenFileChild(const URIParams&)
|
||||
NeckoChild::AllocPRemoteOpenFileChild(const URIParams&, const OptionalURIParams&)
|
||||
{
|
||||
// We don't allocate here: instead we always use IPDL constructor that takes
|
||||
// an existing RemoteOpenFileChild
|
||||
|
@ -47,7 +47,8 @@ protected:
|
||||
const uint16_t& aBacklog,
|
||||
const nsString& aBinaryType);
|
||||
virtual bool DeallocPTCPServerSocketChild(PTCPServerSocketChild*);
|
||||
virtual PRemoteOpenFileChild* AllocPRemoteOpenFileChild(const URIParams&);
|
||||
virtual PRemoteOpenFileChild* AllocPRemoteOpenFileChild(const URIParams&,
|
||||
const OptionalURIParams&);
|
||||
virtual bool DeallocPRemoteOpenFileChild(PRemoteOpenFileChild*);
|
||||
};
|
||||
|
||||
|
@ -348,7 +348,8 @@ NeckoParent::DeallocPTCPServerSocketParent(PTCPServerSocketParent* actor)
|
||||
}
|
||||
|
||||
PRemoteOpenFileParent*
|
||||
NeckoParent::AllocPRemoteOpenFileParent(const URIParams& aURI)
|
||||
NeckoParent::AllocPRemoteOpenFileParent(const URIParams& aURI,
|
||||
const OptionalURIParams& aAppURI)
|
||||
{
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
|
||||
nsCOMPtr<nsIFileURL> fileURL = do_QueryInterface(uri);
|
||||
@ -396,7 +397,21 @@ NeckoParent::AllocPRemoteOpenFileParent(const URIParams& aURI)
|
||||
fileURL->GetPath(requestedPath);
|
||||
NS_UnescapeURL(requestedPath);
|
||||
|
||||
if (hasManage) {
|
||||
// Check if we load the whitelisted app uri for the neterror page.
|
||||
bool netErrorWhiteList = false;
|
||||
|
||||
nsCOMPtr<nsIURI> appUri = DeserializeURI(aAppURI);
|
||||
if (appUri) {
|
||||
nsAdoptingString netErrorURI;
|
||||
netErrorURI = Preferences::GetString("b2g.neterror.url");
|
||||
if (netErrorURI) {
|
||||
nsAutoCString spec;
|
||||
appUri->GetSpec(spec);
|
||||
netErrorWhiteList = spec.Equals(NS_ConvertUTF16toUTF8(netErrorURI).get());
|
||||
}
|
||||
}
|
||||
|
||||
if (hasManage || netErrorWhiteList) {
|
||||
// webapps-manage permission means allow reading any application.zip file
|
||||
// in either the regular webapps directory, or the core apps directory (if
|
||||
// we're using one).
|
||||
@ -447,8 +462,8 @@ NeckoParent::AllocPRemoteOpenFileParent(const URIParams& aURI)
|
||||
printf_stderr("NeckoParent::AllocPRemoteOpenFile: "
|
||||
"FATAL error: app without webapps-manage permission is "
|
||||
"requesting file '%s' but is only allowed to open its "
|
||||
"own application.zip: KILLING CHILD PROCESS\n",
|
||||
requestedPath.get());
|
||||
"own application.zip at %s: KILLING CHILD PROCESS\n",
|
||||
requestedPath.get(), mustMatch.get());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -460,7 +475,8 @@ NeckoParent::AllocPRemoteOpenFileParent(const URIParams& aURI)
|
||||
|
||||
bool
|
||||
NeckoParent::RecvPRemoteOpenFileConstructor(PRemoteOpenFileParent* aActor,
|
||||
const URIParams& aFileURI)
|
||||
const URIParams& aFileURI,
|
||||
const OptionalURIParams& aAppURI)
|
||||
{
|
||||
return static_cast<RemoteOpenFileParent*>(aActor)->OpenSendCloseDelete();
|
||||
}
|
||||
|
@ -88,10 +88,12 @@ protected:
|
||||
virtual bool DeallocPWebSocketParent(PWebSocketParent*);
|
||||
virtual PTCPSocketParent* AllocPTCPSocketParent();
|
||||
|
||||
virtual PRemoteOpenFileParent* AllocPRemoteOpenFileParent(const URIParams& aFileURI)
|
||||
virtual PRemoteOpenFileParent* AllocPRemoteOpenFileParent(const URIParams& aFileURI,
|
||||
const OptionalURIParams& aAppURI)
|
||||
MOZ_OVERRIDE;
|
||||
virtual bool RecvPRemoteOpenFileConstructor(PRemoteOpenFileParent* aActor,
|
||||
const URIParams& aFileURI)
|
||||
const URIParams& aFileURI,
|
||||
const OptionalURIParams& aAppURI)
|
||||
MOZ_OVERRIDE;
|
||||
virtual bool DeallocPRemoteOpenFileParent(PRemoteOpenFileParent* aActor)
|
||||
MOZ_OVERRIDE;
|
||||
|
@ -54,7 +54,7 @@ parent:
|
||||
|
||||
PWebSocket(PBrowser browser, SerializedLoadContext loadContext);
|
||||
PTCPServerSocket(uint16_t localPort, uint16_t backlog, nsString binaryType);
|
||||
PRemoteOpenFile(URIParams fileuri);
|
||||
PRemoteOpenFile(URIParams fileuri, OptionalURIParams appuri);
|
||||
|
||||
HTMLDNSPrefetch(nsString hostname, uint16_t flags);
|
||||
CancelHTMLDNSPrefetch(nsString hostname, uint16_t flags, nsresult reason);
|
||||
|
@ -75,6 +75,9 @@ RemoteOpenFileChild::RemoteOpenFileChild(const RemoteOpenFileChild& other)
|
||||
{
|
||||
// Note: don't clone mListener or we'll have a refcount leak.
|
||||
other.mURI->Clone(getter_AddRefs(mURI));
|
||||
if (other.mAppURI) {
|
||||
other.mAppURI->Clone(getter_AddRefs(mAppURI));
|
||||
}
|
||||
other.mFile->Clone(getter_AddRefs(mFile));
|
||||
}
|
||||
|
||||
@ -93,12 +96,16 @@ RemoteOpenFileChild::~RemoteOpenFileChild()
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemoteOpenFileChild::Init(nsIURI* aRemoteOpenUri)
|
||||
RemoteOpenFileChild::Init(nsIURI* aRemoteOpenUri, nsIURI* aAppUri)
|
||||
{
|
||||
if (!aRemoteOpenUri) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (aAppUri) {
|
||||
aAppUri->Clone(getter_AddRefs(mAppURI));
|
||||
}
|
||||
|
||||
nsAutoCString scheme;
|
||||
nsresult rv = aRemoteOpenUri->GetScheme(scheme);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
@ -183,8 +190,10 @@ RemoteOpenFileChild::AsyncRemoteFileOpen(int32_t aFlags,
|
||||
|
||||
URIParams uri;
|
||||
SerializeURI(mURI, uri);
|
||||
OptionalURIParams appUri;
|
||||
SerializeURI(mAppURI, appUri);
|
||||
|
||||
gNeckoChild->SendPRemoteOpenFileConstructor(this, uri);
|
||||
gNeckoChild->SendPRemoteOpenFileConstructor(this, uri, appUri);
|
||||
|
||||
// The chrome process now has a logical ref to us until it calls Send__delete.
|
||||
AddIPDLReference();
|
||||
|
@ -63,8 +63,9 @@ public:
|
||||
NS_DECL_NSIFILE
|
||||
NS_DECL_NSIHASHABLE
|
||||
|
||||
// URI must be scheme 'remoteopenfile://': otherwise looks like a file:// uri.
|
||||
nsresult Init(nsIURI* aRemoteOpenUri);
|
||||
// aRemoteOpenUri must be scheme 'remoteopenfile://': otherwise looks like
|
||||
// a file:// uri.
|
||||
nsresult Init(nsIURI* aRemoteOpenUri, nsIURI* aAppUri);
|
||||
|
||||
// Send message to parent to tell it to open file handle for file.
|
||||
// TabChild is required, for IPC security.
|
||||
@ -100,6 +101,7 @@ protected:
|
||||
// regular nsIFile object, that we forward most calls to.
|
||||
nsCOMPtr<nsIFile> mFile;
|
||||
nsCOMPtr<nsIURI> mURI;
|
||||
nsCOMPtr<nsIURI> mAppURI;
|
||||
nsCOMPtr<nsIRemoteOpenFileListener> mListener;
|
||||
nsRefPtr<TabChild> mTabChild;
|
||||
PRFileDesc* mNSPRFileDesc;
|
||||
|
@ -313,7 +313,7 @@ this.DownloadIntegration = {
|
||||
* @return {Promise}
|
||||
* @resolves The nsIFile of downloads directory.
|
||||
*/
|
||||
getUserDownloadsDirectory: function DI_getUserDownloadsDirectory() {
|
||||
getPreferredDownloadsDirectory: function DI_getPreferredDownloadsDirectory() {
|
||||
return Task.spawn(function() {
|
||||
let directory = null;
|
||||
let prefValue = 1;
|
||||
@ -356,7 +356,7 @@ this.DownloadIntegration = {
|
||||
return Task.spawn(function() {
|
||||
let directory = null;
|
||||
#ifdef XP_MACOSX
|
||||
directory = yield this.getUserDownloadsDirectory();
|
||||
directory = yield this.getPreferredDownloadsDirectory();
|
||||
#elifdef ANDROID
|
||||
directory = yield this.getSystemDownloadsDirectory();
|
||||
#else
|
||||
|
@ -273,8 +273,8 @@ this.Downloads = {
|
||||
* @return {Promise}
|
||||
* @resolves The nsIFile of downloads directory.
|
||||
*/
|
||||
getUserDownloadsDirectory: function D_getUserDownloadsDirectory() {
|
||||
return DownloadIntegration.getUserDownloadsDirectory();
|
||||
getPreferredDownloadsDirectory: function D_getPreferredDownloadsDirectory() {
|
||||
return DownloadIntegration.getPreferredDownloadsDirectory();
|
||||
},
|
||||
|
||||
/**
|
||||
|