Merge mozilla-central to mozilla-inbound

This commit is contained in:
Carsten "Tomcat" Book 2015-07-01 14:40:04 +02:00
commit 3fa23d15ff
51 changed files with 677 additions and 329 deletions

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -19,7 +19,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -1,9 +1,9 @@
{
"git": {
"git_revision": "90ed5ebde89b6fc095524e47c59d5b8d192d3ff2",
"git_revision": "5a39ff43424e92e73c468b8f00a6c62476f30177",
"remote": "https://git.mozilla.org/releases/gaia.git",
"branch": ""
},
"revision": "a49e3b3bbdc87f84039093f17441a59d1cbb2960",
"revision": "0469dbd8dbeb9fc7a3e90e9e2471976d637f4f33",
"repo_path": "integration/gaia-central"
}

View File

@ -17,7 +17,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>

View File

@ -15,7 +15,7 @@
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="gaia" path="gaia" remote="mozillaorg" revision="90ed5ebde89b6fc095524e47c59d5b8d192d3ff2"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="5a39ff43424e92e73c468b8f00a6c62476f30177"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>

View File

@ -0,0 +1,96 @@
# 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/.
let TrackingProtection = {
PREF_ENABLED: "privacy.trackingprotection.enabled",
init() {
let $ = selector => document.querySelector(selector);
this.container = $("#tracking-protection-container");
this.content = $("#tracking-protection-content");
this.updateEnabled();
Services.prefs.addObserver(this.PREF_ENABLED, this, false);
this.enabledHistogram.add(this.enabled);
},
uninit() {
Services.prefs.removeObserver(this.PREF_ENABLED, this);
},
observe() {
this.updateEnabled();
},
updateEnabled() {
this.enabled = Services.prefs.getBoolPref(this.PREF_ENABLED);
this.container.hidden = !this.enabled;
},
get enabledHistogram() {
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED");
},
get eventsHistogram() {
return Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS");
},
onSecurityChange(state) {
if (!this.enabled) {
return;
}
let {
STATE_BLOCKED_TRACKING_CONTENT, STATE_LOADED_TRACKING_CONTENT
} = Ci.nsIWebProgressListener;
if (state & STATE_BLOCKED_TRACKING_CONTENT) {
this.content.setAttribute("block-active", true);
this.content.removeAttribute("block-disabled");
} else if (state & STATE_LOADED_TRACKING_CONTENT) {
this.content.setAttribute("block-disabled", true);
this.content.removeAttribute("block-active");
} else {
this.content.removeAttribute("block-disabled");
this.content.removeAttribute("block-active");
}
// Telemetry for state change.
this.eventsHistogram.add(0);
},
disableForCurrentPage() {
// Convert document URI into the format used by
// nsChannelClassifier::ShouldEnableTrackingProtection.
// Any scheme turned into https is correct.
let normalizedUrl = Services.io.newURI(
"https://" + gBrowser.selectedBrowser.currentURI.hostPort,
null, null);
// Add the current host in the 'trackingprotection' consumer of
// the permission manager using a normalized URI. This effectively
// places this host on the tracking protection allowlist.
Services.perms.add(normalizedUrl,
"trackingprotection", Services.perms.ALLOW_ACTION);
// Telemetry for disable protection.
this.eventsHistogram.add(1);
BrowserReload();
},
enableForCurrentPage() {
// Remove the current host from the 'trackingprotection' consumer
// of the permission manager. This effectively removes this host
// from the tracking protection allowlist.
Services.perms.remove(gBrowser.selectedBrowser.currentURI.host,
"trackingprotection");
// Telemetry for enable protection.
this.eventsHistogram.add(2);
BrowserReload();
},
};

View File

@ -280,6 +280,7 @@ let gInitialPages = [
#include browser-social.js
#include browser-tabview.js
#include browser-thumbnails.js
#include browser-trackingprotection.js
#ifdef MOZ_DATA_REPORTING
#include browser-data-submission-info-bar.js
@ -964,6 +965,7 @@ var gBrowserInit = {
BrowserOnClick.init();
DevEdition.init();
AboutPrivateBrowsingListener.init();
TrackingProtection.init();
let mm = window.getGroupMessageManager("browsers");
mm.loadFrameScript("chrome://browser/content/tab-content.js", true);
@ -1446,12 +1448,6 @@ var gBrowserInit = {
}
}, 5000);
// Telemetry for tracking protection.
let tpEnabled = gPrefService
.getBoolPref("privacy.trackingprotection.enabled");
Services.telemetry.getHistogramById("TRACKING_PROTECTION_ENABLED")
.add(tpEnabled);
PanicButtonNotifier.init();
});
this.delayedStartupFinished = true;
@ -1534,6 +1530,8 @@ var gBrowserInit = {
DevEdition.uninit();
TrackingProtection.uninit();
gMenuButtonUpdateBadge.uninit();
ReadingListUI.uninit();
@ -4383,6 +4381,7 @@ var XULBrowserWindow = {
uri = Services.uriFixup.createExposableURI(uri);
} catch (e) {}
gIdentityHandler.checkIdentity(this._state, uri);
TrackingProtection.onSecurityChange(this._state);
},
// simulate all change notifications after switching tabs
@ -6781,7 +6780,7 @@ var gIdentityHandler = {
nsIWebProgressListener.STATE_BLOCKED_TRACKING_CONTENT |
nsIWebProgressListener.STATE_LOADED_TRACKING_CONTENT)) {
this.showBadContentDoorhanger(state);
} else if (gPrefService.getBoolPref("privacy.trackingprotection.enabled")) {
} else if (TrackingProtection.enabled) {
// We didn't show the shield
Services.telemetry.getHistogramById("TRACKING_PROTECTION_SHIELD")
.add(0);

View File

@ -2,118 +2,100 @@
* 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/. */
// Test that the Tracking Protection Doorhanger appears
// and has the correct state when tracking content is blocked (Bug 1043801)
// Test that the Tracking Protection section is visible in the Control Center
// and has the correct state for the cases when:
// * A page with no tracking elements is loaded.
// * A page with tracking elements is loaded and they are blocked.
// * A page with tracking elements is loaded and they are not blocked.
// See also Bugs 1175327 and 1043801.
var PREF = "privacy.trackingprotection.enabled";
var BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
var TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
let PREF = "privacy.trackingprotection.enabled";
let BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
let TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
let TrackingProtection = null;
function testBenignPage(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was ON and tracking was NOT present");
registerCleanupFunction(function() {
TrackingProtection = null;
Services.prefs.clearUserPref(PREF);
gBrowser.removeCurrentTab();
});
function hidden(sel) {
let win = gBrowser.ownerGlobal;
let el = win.document.querySelector(sel);
let display = win.getComputedStyle(el).getPropertyValue("display", null);
return display === "none";
}
function* testTrackingPage(gTestBrowser)
{
// Make sure the doorhanger appears
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
isnot(notification, null, "Tracking Content Doorhanger did appear when protection was ON and tracking was present");
notification.reshow();
var notificationElement = PopupNotifications.panel.firstChild;
function testBenignPage() {
ok (!TrackingProtection.content.hasAttribute("block-disabled"), "blocking not disabled");
ok (!TrackingProtection.content.hasAttribute("block-active"), "blocking is not active");
// Wait for the method to be attached after showing the popup
yield promiseWaitForCondition(() => {
return notificationElement.disableTrackingContentProtection;
});
// Make sure the state of the doorhanger includes blocking tracking elements
ok(notificationElement.isTrackingContentBlocked,
"Tracking Content is being blocked");
// Make sure the notification has no trackingblockdisabled attribute
ok(!notificationElement.hasAttribute("trackingblockdisabled"),
"Doorhanger must have no trackingblockdisabled attribute");
// Make sure that the no tracking elements message appears
ok (!hidden("#tracking-not-detected"), "labelNoTracking is visible");
ok (hidden("#tracking-loaded"), "labelTrackingLoaded is hidden");
ok (hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
}
function* testTrackingPageWhitelisted(gTestBrowser)
{
// Make sure the doorhanger appears
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
isnot(notification, null, "Tracking Content Doorhanger did appear when protection was ON and tracking was present but white-listed");
notification.reshow();
var notificationElement = PopupNotifications.panel.firstChild;
function testTrackingPage() {
ok (!TrackingProtection.content.hasAttribute("block-disabled"), "blocking not disabled");
ok (TrackingProtection.content.hasAttribute("block-active"), "blocking is active");
// Wait for the method to be attached after showing the popup
yield promiseWaitForCondition(() => {
return notificationElement.disableTrackingContentProtection;
});
var notificationElement = PopupNotifications.panel.firstChild;
// Make sure the state of the doorhanger does NOT include blocking tracking elements
ok(!notificationElement.isTrackingContentBlocked,
"Tracking Content is NOT being blocked");
// Make sure the notification has the trackingblockdisabled attribute set to true
is(notificationElement.getAttribute("trackingblockdisabled"), "true",
"Doorhanger must have [trackingblockdisabled='true'] attribute");
// Make sure that the blocked tracking elements message appears
ok (hidden("#tracking-not-detected"), "labelNoTracking is hidden");
ok (hidden("#tracking-loaded"), "labelTrackingLoaded is hidden");
ok (!hidden("#tracking-blocked"), "labelTrackingBlocked is visible");
}
function testTrackingPageOFF(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was OFF and tracking was present");
}
function testTrackingPageWhitelisted() {
ok (TrackingProtection.content.hasAttribute("block-disabled"), "blocking is disabled");
ok (!TrackingProtection.content.hasAttribute("block-active"), "blocking is not active");
function testBenignPageOFF(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was OFF and tracking was NOT present");
// Make sure that the blocked tracking elements message appears
ok (hidden("#tracking-not-detected"), "labelNoTracking is hidden");
ok (!hidden("#tracking-loaded"), "labelTrackingLoaded is visible");
ok (hidden("#tracking-blocked"), "labelTrackingBlocked is hidden");
}
add_task(function* () {
registerCleanupFunction(function() {
Services.prefs.clearUserPref(PREF);
gBrowser.removeCurrentTab();
});
yield updateTrackingProtectionDatabase();
let tab = gBrowser.selectedTab = gBrowser.addTab();
// Enable Tracking Protection
TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
ok (TrackingProtection, "Functionality is attached to the browser window");
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
"The initial enabled value is based on the default pref value");
info("Enable Tracking Protection");
Services.prefs.setBoolPref(PREF, true);
ok (TrackingProtection.enabled, "Functionality is enabled after setting the pref");
// Point tab to a test page NOT containing tracking elements
info("Point tab to a test page NOT containing tracking elements");
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
testBenignPage(gBrowser.getBrowserForTab(tab));
testBenignPage();
// Point tab to a test page containing tracking elements
info("Point tab to a test page containing tracking elements");
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
// Tracking content must be blocked
yield testTrackingPage(gBrowser.getBrowserForTab(tab));
info("Tracking content must be blocked");
testTrackingPage();
// Disable Tracking Content Protection for the page (which reloads the page)
PopupNotifications.panel.firstChild.disableTrackingContentProtection();
info("Disable Tracking Content Protection for the page (which reloads the page)");
TrackingProtection.disableForCurrentPage();
// Wait for tab to reload following tracking-protection page white-listing
info("Wait for tab to reload following tracking-protection page white-listing");
yield promiseTabLoadEvent(tab);
// Tracking content must be white-listed (NOT blocked)
yield testTrackingPageWhitelisted(gBrowser.getBrowserForTab(tab));
info("Tracking content must be white-listed (NOT blocked)");
testTrackingPageWhitelisted();
// Re-enable Tracking Content Protection for the page (which reloads the page)
PopupNotifications.panel.firstChild.enableTrackingContentProtection();
info("Re-enable Tracking Content Protection for the page (which reloads the page)");
TrackingProtection.enableForCurrentPage();
// Wait for tab to reload following tracking-protection page white-listing
info("Wait for tab to reload following tracking-protection page white-listing");
yield promiseTabLoadEvent(tab);
// Tracking content must be blocked
yield testTrackingPage(gBrowser.getBrowserForTab(tab));
info("Tracking content must be blocked");
testTrackingPage();
});

View File

@ -2,45 +2,48 @@
* 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/. */
// Test that the Tracking Protection Doorhanger does not ever appear
// when the feature is off (Bug 1043801)
// Test that the Tracking Protection section is never visible in the
// Control Center when the feature is off.
// See also Bugs 1175327 and 1043801.
var PREF = "privacy.trackingprotection.enabled";
var BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
var TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
let PREF = "privacy.trackingprotection.enabled";
let BENIGN_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/benignPage.html";
let TRACKING_PAGE = "http://tracking.example.org/browser/browser/base/content/test/general/trackingPage.html";
let TrackingProtection = null;
function testTrackingPageOFF(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was OFF and tracking was present");
registerCleanupFunction(function() {
TrackingProtection = null;
Services.prefs.clearUserPref(PREF);
gBrowser.removeCurrentTab();
});
function testTrackingPageOFF() {
ok (TrackingProtection.container.hidden, "The container is hidden");
}
function testBenignPageOFF(gTestBrowser)
{
// Make sure the doorhanger does NOT appear
var notification = PopupNotifications.getNotification("bad-content", gTestBrowser);
is(notification, null, "Tracking Content Doorhanger did NOT appear when protection was OFF and tracking was NOT present");
function testBenignPageOFF() {
ok (TrackingProtection.container.hidden, "The container is hidden");
}
add_task(function* () {
registerCleanupFunction(function() {
Services.prefs.clearUserPref(PREF);
gBrowser.removeCurrentTab();
});
yield updateTrackingProtectionDatabase();
let tab = gBrowser.selectedTab = gBrowser.addTab();
// Disable Tracking Protection
TrackingProtection = gBrowser.ownerGlobal.TrackingProtection;
ok (TrackingProtection, "Functionality is attached to the browser window");
is (TrackingProtection.enabled, Services.prefs.getBoolPref(PREF),
"The initial enabled value is based on the default pref value");
info ("Disable Tracking Protection");
Services.prefs.setBoolPref(PREF, false);
ok (!TrackingProtection.enabled, "Functionality is disabled after setting the pref");
// Point tab to a test page containing tracking elements
info ("Point tab to a test page containing tracking elements");
yield promiseTabLoadEvent(tab, TRACKING_PAGE);
testTrackingPageOFF(gBrowser.getBrowserForTab(tab));
testTrackingPageOFF();
// Point tab to a test page NOT containing tracking elements
info ("Point tab to a test page NOT containing tracking elements");
yield promiseTabLoadEvent(tab, BENIGN_PAGE);
testBenignPageOFF(gBrowser.getBrowserForTab(tab));
testBenignPageOFF();
});

View File

@ -2377,10 +2377,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
Services.urlFormatter.formatURLPref("app.support.baseURL")
+ "tracking-protection";
}
if (Services.prefs.getBoolPref("privacy.trackingprotection.enabled")) {
let histogram = Services.telemetry.getHistogramById("TRACKING_PROTECTION_EVENTS");
histogram.add(0);
}
]]></constructor>
<method name="disableMixedContentProtection">
<body><![CDATA[
@ -2415,10 +2411,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
// places this host on the tracking protection allowlist.
Services.perms.add(normalizedUrl,
"trackingprotection", Services.perms.ALLOW_ACTION);
// Telemetry for disable protection
let histogram = Services.telemetry.getHistogramById(
"TRACKING_PROTECTION_EVENTS");
histogram.add(1);
BrowserReload();
]]></body>
</method>
@ -2429,10 +2421,6 @@ file, You can obtain one at http://mozilla.org/MPL/2.0/.
// from the tracking protection allowlist.
Services.perms.remove(gBrowser.selectedBrowser.currentURI.host,
"trackingprotection");
// Telemetry for enable protection
let histogram = Services.telemetry.getHistogramById(
"TRACKING_PROTECTION_EVENTS");
histogram.add(2);
BrowserReload();
]]></body>
</method>

View File

@ -36,6 +36,42 @@
oncommand="gIdentityHandler.showSubView('security', this)"/>
</hbox>
<!-- Tracking Protection Section -->
<hbox id="tracking-protection-container" class="identity-popup-section">
<vbox id="tracking-protection-content" flex="1">
<description class="identity-popup-text identity-popup-headline"
crop="end"
value="&trackingProtection.title;" />
<label id="tracking-blocked"
class="identity-popup-text"
crop="end">&trackingProtection.detectedBlocked;</label>
<label id="tracking-loaded"
class="identity-popup-text"
crop="end">&trackingProtection.detectedNotBlocked;</label>
<label id="tracking-not-detected"
class="identity-popup-text"
crop="end">&trackingProtection.notDetected;</label>
<button id="tracking-actions"
type="menu" label="&trackingContentBlocked.options;"
sizetopopup="none">
<menupopup>
<menuitem
id="tracking-action-unblock"
label="&trackingProtection.unblock.label;"
accesskey="&trackingProtection.unblock.accesskey;"
oncommand="TrackingProtection.disableForCurrentPage();"/>
<menuitem
id="tracking-action-block"
label="&trackingProtection.block.label;"
accesskey="&trackingProtection.block.accesskey;"
oncommand="TrackingProtection.enableForCurrentPage();"/>
</menupopup>
</button>
</vbox>
</hbox>
<!-- Permissions Section -->
<hbox id="identity-popup-permissions" class="identity-popup-section">
<vbox id="identity-popup-permissions-content" flex="1">

View File

@ -21,7 +21,7 @@ function test() {
];
if (AppConstants.NIGHTLY_BUILD)
tests.push(test_locbar_suggestion_retention("searches", true)),
tests.push(test_locbar_suggestion_retention("searches", true));
run_test_subset(tests);
}

View File

@ -21,7 +21,7 @@ function test() {
];
if (AppConstants.NIGHTLY_BUILD)
tests.push(test_locbar_suggestion_retention("searches", true)),
tests.push(test_locbar_suggestion_retention("searches", true));
run_test_subset(tests);
}

View File

@ -455,6 +455,7 @@ function Workers() {
this._onWorkerListChanged = this._onWorkerListChanged.bind(this);
this._onWorkerFreeze = this._onWorkerFreeze.bind(this);
this._onWorkerThaw = this._onWorkerThaw.bind(this);
this._onWorkerSelect = this._onWorkerSelect.bind(this);
}
Workers.prototype = {
@ -476,6 +477,10 @@ Workers.prototype = {
},
_updateWorkerList: function () {
if (!this._tabClient.listWorkers) {
return;
}
this._tabClient.listWorkers((response) => {
let workerActors = new Set();
for (let worker of response.workers) {
@ -516,6 +521,13 @@ Workers.prototype = {
_onWorkerThaw: function (type, packet) {
let workerClient = this._workerClients.get(packet.from);
DebuggerView.Workers.addWorker(packet.from, workerClient.url);
},
_onWorkerSelect: function (workerActor) {
let workerClient = this._workerClients.get(workerActor);
gDevTools.showToolbox(devtools.TargetFactory.forWorker(workerClient),
"jsdebugger",
devtools.Toolbox.HostType.WINDOW);
}
};

View File

@ -3,7 +3,9 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
function WorkersView() {}
function WorkersView() {
this._onWorkerSelect = this._onWorkerSelect.bind(this);
}
WorkersView.prototype = Heritage.extend(WidgetMethods, {
initialize: function () {
@ -17,6 +19,7 @@ WorkersView.prototype = Heritage.extend(WidgetMethods, {
showArrows: true,
});
this.emptyText = L10N.getStr("noWorkersText");
this.widget.addEventListener("select", this._onWorkerSelect, false);
},
addWorker: function (actor, name) {
@ -30,6 +33,13 @@ WorkersView.prototype = Heritage.extend(WidgetMethods, {
removeWorker: function (actor) {
this.remove(this.getItemByValue(actor));
},
_onWorkerSelect: function () {
if (this.selectedItem !== null) {
DebuggerController.Workers._onWorkerSelect(this.selectedItem.value);
this.selectedItem = null;
}
}
});

View File

@ -60,6 +60,15 @@ exports.TargetFactory = {
return targetPromise;
},
forWorker: function TF_forWorker(workerClient) {
let target = targets.get(workerClient);
if (target == null) {
target = new WorkerTarget(workerClient);
targets.set(workerClient, target);
}
return target;
},
/**
* Creating a target for a tab that is being closed is a problem because it
* allows a leak as a result of coming after the close event which normally
@ -799,3 +808,64 @@ WindowTarget.prototype = {
return 'WindowTarget:' + this.window;
},
};
function WorkerTarget(workerClient) {
EventEmitter.decorate(this);
this._workerClient = workerClient;
}
/**
* A WorkerTarget represents a worker. Unlike TabTarget, which can represent
* either a local or remote tab, WorkerTarget always represents a remote worker.
* Moreover, unlike TabTarget, which is constructed with a placeholder object
* for remote tabs (from which a TabClient can then be lazily obtained),
* WorkerTarget is constructed with a WorkerClient directly.
*
* The reason for this is that in order to get notifications when a worker
* closes/freezes/thaws, the UI needs to attach to each worker anyway, so by
* the time a WorkerTarget for a given worker is created, a WorkerClient for
* that worker will already be available. Consequently, there is no need to
* obtain a WorkerClient lazily.
*
* WorkerClient is designed to mimic the interface of TabClient as closely as
* possible. This allows us to debug workers as if they were ordinary tabs,
* requiring only minimal changes to the rest of the frontend.
*/
WorkerTarget.prototype = {
get isRemote() {
return true;
},
get isTabActor() {
return true;
},
get form() {
return {
from: this._workerClient.actor,
type: "attached",
isFrozen: this._workerClient.isFrozen,
url: this._workerClient.url
};
},
get activeTab() {
return this._workerClient;
},
get client() {
return this._workerClient.client;
},
destroy: function () {},
hasActor: function (name) {
return false;
},
getTrait: function (name) {
return undefined;
},
makeRemote: function () {}
};

View File

@ -768,6 +768,15 @@ you can use these alternative items. Otherwise, their values should be empty. -
<!ENTITY mixedContentBlocked2.block.accesskey "E">
<!ENTITY mixedContentBlocked2.disabled.message "Protection is disabled">
<!ENTITY trackingProtection.title "Tracking Protection">
<!ENTITY trackingProtection.detectedBlocked "Attempts to track your online behavior have been blocked.">
<!ENTITY trackingProtection.detectedNotBlocked "Tracking elements detected. You have disabled protection on this site.">
<!ENTITY trackingProtection.notDetected "No tracking elements detected on this website.">
<!ENTITY trackingProtection.unblock.label "Disable protection for this site">
<!ENTITY trackingProtection.unblock.accesskey "D">
<!ENTITY trackingProtection.block.label "Enable protection for this site">
<!ENTITY trackingProtection.block.accesskey "E">
<!ENTITY trackingContentBlocked.message "Tracking">
<!ENTITY trackingContentBlocked.moreinfo "Parts of the page that track your online activity have been blocked.">
<!ENTITY trackingContentBlocked.learnMore "Learn More">

View File

@ -10,6 +10,8 @@ let Cu = Components.utils;
this.EXPORTED_SYMBOLS = [ "NewTabURL" ];
Components.utils.import("resource://gre/modules/Services.jsm");
this.NewTabURL = {
_url: "about:newtab",
_overridden: false,
@ -25,10 +27,12 @@ this.NewTabURL = {
override: function(newURL) {
this._url = newURL;
this._overridden = true;
Services.obs.notifyObservers(null, "newtab-url-changed", this._url);
},
reset: function() {
this._url = "about:newtab";
this._overridden = false;
Services.obs.notifyObservers(null, "newtab-url-changed", this._url);
}
};

View File

@ -4,14 +4,30 @@
"use strict";
Components.utils.import("resource:///modules/NewTabURL.jsm");
Components.utils.import("resource://gre/modules/Services.jsm");
function run_test() {
add_task(function* () {
Assert.equal(NewTabURL.get(), "about:newtab", "Default newtab URL should be about:newtab");
let url = "http://example.com/";
let notificationPromise = promiseNewtabURLNotification(url);
NewTabURL.override(url);
yield notificationPromise;
Assert.ok(NewTabURL.overridden, "Newtab URL should be overridden");
Assert.equal(NewTabURL.get(), url, "Newtab URL should be the custom URL");
notificationPromise = promiseNewtabURLNotification("about:newtab");
NewTabURL.reset();
yield notificationPromise;
Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
Assert.equal(NewTabURL.get(), "about:newtab", "Newtab URL should be the about:newtab");
});
function promiseNewtabURLNotification(aNewURL) {
return new Promise(resolve => {
Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
Services.obs.removeObserver(observer, aTopic);
Assert.equal(aData, aNewURL, "Data for newtab-url-changed notification should be new URL.");
resolve();
}, "newtab-url-changed", false);
});
}

View File

@ -150,6 +150,8 @@ browser.jar:
skin/classic/browser/controlcenter/conn-secure-dv.svg (../shared/controlcenter/conn-secure-dv.svg)
skin/classic/browser/controlcenter/conn-secure-ev.svg (../shared/controlcenter/conn-secure-ev.svg)
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
skin/classic/browser/controlcenter/tracking-protection-disabled.svg (../shared/controlcenter/tracking-protection-disabled.svg)
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customize-illustration.png (../shared/customizableui/customize-illustration.png)
skin/classic/browser/customizableui/customize-illustration-rtl.png (../shared/customizableui/customize-illustration-rtl.png)

View File

@ -194,6 +194,8 @@ browser.jar:
skin/classic/browser/controlcenter/conn-secure-dv.svg (../shared/controlcenter/conn-secure-dv.svg)
skin/classic/browser/controlcenter/conn-secure-ev.svg (../shared/controlcenter/conn-secure-ev.svg)
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
skin/classic/browser/controlcenter/tracking-protection-disabled.svg (../shared/controlcenter/tracking-protection-disabled.svg)
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/browser/customizableui/customize-titleBar-toggle@2x.png (customizableui/customize-titleBar-toggle@2x.png)

View File

@ -55,7 +55,8 @@
#identity-popup-securityView,
#identity-popup-security-content,
#identity-popup-permissions-content {
#identity-popup-permissions-content,
#tracking-protection-content {
padding: 0.75em 0 1em;
-moz-padding-start: calc(2em + 24px);
-moz-padding-end: 1em;
@ -66,7 +67,8 @@
#identity-popup-securityView:-moz-locale-dir(rtl),
#identity-popup-security-content:-moz-locale-dir(rtl),
#identity-popup-permissions-content:-moz-locale-dir(rtl) {
#identity-popup-permissions-content:-moz-locale-dir(rtl),
#tracking-protection-content:-moz-locale-dir(rtl) {
background-position: calc(100% - 1em) 1em;
}
@ -199,6 +201,30 @@
margin-top: 1em;
}
/* TRACKING PROTECTION */
#tracking-protection-content {
background-image: url("chrome://browser/skin/controlcenter/tracking-protection.svg");
}
#tracking-protection-content[block-disabled] {
background-image: url("chrome://browser/skin/controlcenter/tracking-protection-disabled.svg");
}
#tracking-actions {
margin: 1em 0 0;
}
#tracking-protection-content[block-active] > #tracking-not-detected,
#tracking-protection-content[block-disabled] > #tracking-not-detected,
#tracking-protection-content:not([block-active]) > #tracking-blocked,
#tracking-protection-content:not([block-active]) #tracking-action-unblock,
#tracking-protection-content:not([block-disabled]) > #tracking-loaded,
#tracking-protection-content:not([block-disabled]) #tracking-action-block,
#tracking-protection-content:not([block-active]):not([block-disabled]) > #tracking-actions {
display: none;
}
/* PERMISSIONS */
#identity-popup-permissions-content {

View File

@ -0,0 +1,24 @@
<?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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="16"
height="16"
viewBox="0 0 16 16">
<defs>
<path id="shape-shield-outer" d="M8,1L2.8,1.9C2.4,1.9,2,2.4,2,2.8C2,4,2,6.1,2.1,7.1c0.3,2.7,0.8,4,1.9,5.6C5.6,14.7,8,15,8,15s2.4-0.3,4-2.4 c1.2-1.5,1.7-2.9,1.9-5.6C14,6.1,14,4,14,2.8c0-0.5-0.4-0.9-0.8-1L8,1L8,1z"/>
<path id="shape-shield-inner" d="M8,2l5,0.8c0,2,0,3.5-0.1,4.1c-0.3,2.7-0.8,3.8-1.7,5.1c-1.1,1.5-2.7,1.9-3.2,2c-0.4-0.1-2.1-0.5-3.2-2 c-1-1.3-1.5-2.4-1.7-5.1C3,6.3,3,4.8,3,2.8L8,2"/>
<path id="shape-shield-detail" d="M8,13c-0.5-0.1-1.6-0.5-2.4-1.5c-0.9-1.2-1.3-2.1-1.5-4.6C4,6.3,4,5.2,4,3.7L8,3 V13z"/>
<mask id="mask-shield-cutout">
<rect width="16" height="16" fill="#000" />
<use xlink:href="#shape-shield-outer" fill="#fff" />
<use xlink:href="#shape-shield-inner" fill="#000" />
<use xlink:href="#shape-shield-detail" fill="#fff" />
<line x1="3" y1="15" x2="15" y2="3" stroke="#000" stroke-width="2" />
</mask>
</defs>
<use xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)" fill="#808080" />
<line x1="3" y1="14" x2="15" y2="2" stroke="#d92d21" stroke-width="2" />
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,22 @@
<?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/. -->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
width="16"
height="16"
viewBox="0 0 16 16">
<defs>
<path id="shape-shield-outer" d="M8,1L2.8,1.9C2.4,1.9,2,2.4,2,2.8C2,4,2,6.1,2.1,7.1c0.3,2.7,0.8,4,1.9,5.6C5.6,14.7,8,15,8,15s2.4-0.3,4-2.4 c1.2-1.5,1.7-2.9,1.9-5.6C14,6.1,14,4,14,2.8c0-0.5-0.4-0.9-0.8-1L8,1L8,1z"/>
<path id="shape-shield-inner" d="M8,2l5,0.8c0,2,0,3.5-0.1,4.1c-0.3,2.7-0.8,3.8-1.7,5.1c-1.1,1.5-2.7,1.9-3.2,2c-0.4-0.1-2.1-0.5-3.2-2 c-1-1.3-1.5-2.4-1.7-5.1C3,6.3,3,4.8,3,2.8L8,2"/>
<path id="shape-shield-detail" d="M8,13c-0.5-0.1-1.6-0.5-2.4-1.5c-0.9-1.2-1.3-2.1-1.5-4.6C4,6.3,4,5.2,4,3.7L8,3 V13z"/>
<mask id="mask-shield-cutout">
<rect width="16" height="16" fill="#000" />
<use xlink:href="#shape-shield-outer" fill="#fff" />
<use xlink:href="#shape-shield-inner" fill="#000" />
<use xlink:href="#shape-shield-detail" fill="#fff" />
</mask>
</defs>
<use xlink:href="#shape-shield-outer" mask="url(#mask-shield-cutout)" fill="#808080" />
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -197,6 +197,8 @@ browser.jar:
skin/classic/browser/controlcenter/conn-secure-dv.svg (../shared/controlcenter/conn-secure-dv.svg)
skin/classic/browser/controlcenter/conn-secure-ev.svg (../shared/controlcenter/conn-secure-ev.svg)
skin/classic/browser/controlcenter/permissions.svg (../shared/controlcenter/permissions.svg)
skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
skin/classic/browser/controlcenter/tracking-protection-disabled.svg (../shared/controlcenter/tracking-protection-disabled.svg)
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
skin/classic/browser/customizableui/customize-illustration.png (../shared/customizableui/customize-illustration.png)

View File

@ -863,6 +863,7 @@ sync_java_files = [
'fxa/activities/FxAccountStatusFragment.java',
'fxa/activities/FxAccountUpdateCredentialsActivity.java',
'fxa/activities/FxAccountVerifiedAccountActivity.java',
'fxa/activities/PicassoPreferenceIconTarget.java',
'fxa/authenticator/AccountPickler.java',
'fxa/authenticator/AndroidFxAccount.java',
'fxa/authenticator/FxAccountAuthenticator.java',

View File

@ -24,7 +24,7 @@ public class FxAccountConstants {
public static final String STAGE_PROFILE_SERVER_ENDPOINT = "https://latest.dev.lcip.org/profile/v1";
// Action to update on cached profile information.
public static final String ACCOUNT_PROFILE_AVATAR_UPDATED_ACTION = "org.mozilla.gecko.fxa.profile.cached";
public static final String ACCOUNT_PROFILE_JSON_UPDATED_ACTION = "org.mozilla.gecko.fxa.profile.JSON.updated";
// You must be at least 13 years old, on the day of creation, to create a Firefox Account.
public static final int MINIMUM_AGE_TO_CREATE_AN_ACCOUNT = 13;

View File

@ -50,6 +50,8 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.widget.Toast;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
/**
* A fragment that displays the status of an AndroidFxAccount.
@ -140,13 +142,11 @@ public class FxAccountStatusFragment
// Runnable to update last synced time.
protected Runnable lastSyncedTimeUpdateRunnable;
// Runnable to retry fetching profile information.
protected Runnable profileFetchRunnable;
// Broadcast Receiver to update profile Information.
protected FxAccountProfileInformationReceiver accountProfileInformationReceiver;
protected final InnerSyncStatusDelegate syncStatusDelegate = new InnerSyncStatusDelegate();
private Target profileAvatarTarget;
protected Preference ensureFindPreference(String key) {
Preference preference = findPreference(key);
@ -485,6 +485,18 @@ public class FxAccountStatusFragment
// register/unregister calls.
FxAccountSyncStatusHelper.getInstance().startObserving(syncStatusDelegate);
if (AppConstants.MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES) {
// Register a local broadcast receiver to get profile cached notification.
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(FxAccountConstants.ACCOUNT_PROFILE_JSON_UPDATED_ACTION);
accountProfileInformationReceiver = new FxAccountProfileInformationReceiver();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(accountProfileInformationReceiver, intentFilter);
// profilePreference is set during onCreate, so it's definitely not null here.
final float cornerRadius = getResources().getDimension(R.dimen.fxaccount_profile_image_width) / 2;
profileAvatarTarget = new PicassoPreferenceIconTarget(getResources(), profilePreference, cornerRadius);
}
refresh();
}
@ -498,14 +510,15 @@ public class FxAccountStatusFragment
handler.removeCallbacks(lastSyncedTimeUpdateRunnable);
}
if (profileFetchRunnable != null) {
handler.removeCallbacks(profileFetchRunnable);
}
// Focus lost, unregister broadcast receiver.
if (accountProfileInformationReceiver != null) {
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(accountProfileInformationReceiver);
}
if (profileAvatarTarget != null) {
Picasso.with(getActivity()).cancelRequest(profileAvatarTarget);
profileAvatarTarget = null;
}
}
protected void hardRefresh() {
@ -606,53 +619,60 @@ public class FxAccountStatusFragment
return;
}
final ExtendedJSONObject cachedProfileJSON = fxAccount.getCachedProfileJSON();
if (cachedProfileJSON != null) {
// Update profile information from the cached Json.
updateProfileInformation(cachedProfileJSON);
final ExtendedJSONObject profileJSON = fxAccount.getProfileJSON();
if (profileJSON == null) {
// Update the profile title with email as the fallback.
// Profile icon by default use the default avatar as the fallback.
profilePreference.setTitle(fxAccount.getEmail());
return;
}
// Update the profile title with email as the fallback.
// Profile icon by default use the default avatar as the fallback.
profilePreference.setTitle(fxAccount.getEmail());
// Register a local broadcast receiver to get profile cached notification.
final IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(FxAccountConstants.ACCOUNT_PROFILE_AVATAR_UPDATED_ACTION);
accountProfileInformationReceiver = new FxAccountProfileInformationReceiver();
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(accountProfileInformationReceiver, intentFilter);
// Fetch the profile from the server.
fxAccount.maybeUpdateProfileJSON(false);
// Schedule an runnable to retry fetching profile.
profileFetchRunnable = new ProfileFetchUpdateRunnable();
handler.postDelayed(profileFetchRunnable, PROFILE_FETCH_RETRY_INTERVAL_IN_MILLISECONDS);
updateProfileInformation(profileJSON);
}
/**
* Update profile information from json on UI thread.
*
* @param profileJson json fetched from server.
* @param profileJSON json fetched from server.
*/
protected void updateProfileInformation(final ExtendedJSONObject profileJson) {
// Remove the scheduled runnable for fetching the profile information.
if (profileFetchRunnable != null) {
handler.removeCallbacks(profileFetchRunnable);
protected void updateProfileInformation(final ExtendedJSONObject profileJSON) {
// View changes must always be done on UI thread.
ThreadUtils.assertOnUiThread();
FxAccountUtils.pii(LOG_TAG, "Profile JSON is: " + profileJSON.toJSONString());
final String userName = profileJSON.getString(FxAccountConstants.KEY_PROFILE_JSON_USERNAME);
// Update the profile username and email if available.
if (!TextUtils.isEmpty(userName)) {
profilePreference.setTitle(userName);
profilePreference.setSummary(fxAccount.getEmail());
} else {
profilePreference.setTitle(fxAccount.getEmail());
}
// Read the profile information from json and Update the UI elements.
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
// Icon update from java is not supported prior to API 11, skip the avatar update for older device.
if (AppConstants.Versions.feature11Plus) {
profilePreference.setIcon(getResources().getDrawable(R.drawable.sync_avatar_default));
}
profilePreference.setTitle(fxAccount.getAndroidAccount().name);
}
});
// Icon update from java is not supported prior to API 11, skip the avatar image fetch and update for older device.
if (!AppConstants.Versions.feature11Plus) {
Logger.info(LOG_TAG, "Skipping profile image fetch for older pre-API 11 devices.");
return;
}
// Avatar URI empty, skip profile image fetch.
final String avatarURI = profileJSON.getString(FxAccountConstants.KEY_PROFILE_JSON_AVATAR);
if (TextUtils.isEmpty(avatarURI)) {
Logger.info(LOG_TAG, "AvatarURI is empty, skipping profile image fetch.");
return;
}
// Using noPlaceholder would avoid a pop of the default image, but it's not available in the version of Picasso
// we ship in the tree.
Picasso
.with(getActivity())
.load(avatarURI)
.centerInside()
.resizeDimen(R.dimen.fxaccount_profile_image_width, R.dimen.fxaccount_profile_image_height)
.placeholder(R.drawable.sync_avatar_default)
.error(R.drawable.sync_avatar_default)
.into(profileAvatarTarget);
}
private void scheduleAndUpdateLastSyncedTime() {
@ -830,26 +850,24 @@ public class FxAccountStatusFragment
}
}
/**
* The Runnable that schedules a future to fetch profile information.
*/
protected class ProfileFetchUpdateRunnable implements Runnable {
@Override
public void run() {
updateProfileInformation();
}
}
/**
* Broadcast receiver to receive updates for the cached profile action.
*/
public class FxAccountProfileInformationReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(FxAccountConstants.ACCOUNT_PROFILE_AVATAR_UPDATED_ACTION)) {
// We should have a cached profile json here.
updateProfileInformation(fxAccount.getCachedProfileJSON());
if (!intent.getAction().equals(FxAccountConstants.ACCOUNT_PROFILE_JSON_UPDATED_ACTION)) {
return;
}
Logger.info(LOG_TAG, "Profile avatar cache update action broadcast received.");
// Update the UI from cached profile json on the main thread.
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
updateProfileInformation();
}
});
}
}

View File

@ -0,0 +1,76 @@
/* 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/. */
package org.mozilla.gecko.fxa.activities;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.preference.Preference;
import android.support.v4.graphics.drawable.RoundedBitmapDrawable;
import android.support.v4.graphics.drawable.RoundedBitmapDrawableFactory;
import com.squareup.picasso.Picasso;
import com.squareup.picasso.Target;
import org.mozilla.gecko.AppConstants;
/**
* A Picasso Target that updates a preference icon.
*
* Nota bene: Android grew support for updating preference icons programatically
* only in API 11. This class silently ignores requests before API 11.
*/
public class PicassoPreferenceIconTarget implements Target {
private final Preference preference;
private final Resources resources;
private final float cornerRadius;
public PicassoPreferenceIconTarget(Resources resources, Preference preference) {
this(resources, preference, 0);
}
public PicassoPreferenceIconTarget(Resources resources, Preference preference, float cornerRadius) {
this.resources = resources;
this.preference = preference;
this.cornerRadius = cornerRadius;
}
@Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) {
// Updating icons from Java is not supported prior to API 11.
if (!AppConstants.Versions.feature11Plus) {
return;
}
final Drawable drawable;
if (cornerRadius > 0) {
final RoundedBitmapDrawable roundedBitmapDrawable;
roundedBitmapDrawable = RoundedBitmapDrawableFactory.create(resources, bitmap);
roundedBitmapDrawable.setCornerRadius(cornerRadius);
roundedBitmapDrawable.setAntiAlias(true);
drawable = roundedBitmapDrawable;
} else {
drawable = new BitmapDrawable(resources, bitmap);
}
preference.setIcon(drawable);
}
@Override
public void onBitmapFailed(Drawable errorDrawable) {
// Updating icons from Java is not supported prior to API 11.
if (!AppConstants.Versions.feature11Plus) {
return;
}
preference.setIcon(errorDrawable);
}
@Override
public void onPrepareLoad(Drawable placeHolderDrawable) {
// Updating icons from Java is not supported prior to API 11.
if (!AppConstants.Versions.feature11Plus) {
return;
}
preference.setIcon(placeHolderDrawable);
}
}

View File

@ -69,12 +69,12 @@ public class AndroidFxAccount {
public static final String ACCOUNT_KEY_TOKEN_SERVER = "tokenServerURI"; // Sync-specific.
public static final String ACCOUNT_KEY_DESCRIPTOR = "descriptor";
public static final String ACCOUNT_KEY_PROFILE_AVATAR = "avatar";
public static final int CURRENT_BUNDLE_VERSION = 2;
public static final String BUNDLE_KEY_BUNDLE_VERSION = "version";
public static final String BUNDLE_KEY_STATE_LABEL = "stateLabel";
public static final String BUNDLE_KEY_STATE = "state";
public static final String BUNDLE_KEY_PROFILE_JSON = "profile";
// Account authentication token type for fetching account profile.
public static final String PROFILE_OAUTH_TOKEN_TYPE = "oauth::profile";
@ -105,13 +105,6 @@ public class AndroidFxAccount {
}
private static final String PREF_KEY_LAST_SYNCED_TIMESTAMP = "lastSyncedTimestamp";
public static final String PREF_KEY_LAST_PROFILE_FETCH_TIME = "lastProfilefetchTime";
public static final String PREF_KEY_NUMBER_OF_PROFILE_FETCH = "numProfileFetch";
// Max wait time between successful profile avatar network fetch.
public static final long PROFILE_FETCH_RETRY_BACKOFF_DELTA_IN_MILLISECONDS = 24 * 60 * 60 * 1000;
// Max attempts allowed for retrying profile avatar network fetch.
public static final int MAX_PROFILE_FETCH_RETRIES = 5;
protected final Context context;
protected final AccountManager accountManager;
@ -127,7 +120,6 @@ public class AndroidFxAccount {
*/
protected static final ConcurrentHashMap<String, ExtendedJSONObject> perAccountBundleCache =
new ConcurrentHashMap<>();
private ExtendedJSONObject profileJson;
public static void invalidateCaches() {
perAccountBundleCache.clear();
@ -667,39 +659,17 @@ public class AndroidFxAccount {
return intent;
}
private void setLastProfileFetchTimestampAndAttempts(long now, int attempts) {
try {
getSyncPrefs().edit().putLong(PREF_KEY_LAST_PROFILE_FETCH_TIME, now).commit();
getSyncPrefs().edit().putInt(PREF_KEY_NUMBER_OF_PROFILE_FETCH, attempts);
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception setting last profile fetch time & attempts; ignoring.", e);
}
}
private long getLastProfileFetchTimestamp() {
final long neverFetched = -1L;
try {
return getSyncPrefs().getLong(PREF_KEY_LAST_PROFILE_FETCH_TIME, neverFetched);
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception getting last profile fetch time; ignoring.", e);
return neverFetched;
}
}
private int getNumberOfProfileFetch() {
final int neverFetched = 0;
try {
return getSyncPrefs().getInt(PREF_KEY_NUMBER_OF_PROFILE_FETCH, neverFetched);
} catch (Exception e) {
Logger.warn(LOG_TAG, "Got exception getting number of profile fetch; ignoring.", e);
return neverFetched;
}
}
private boolean canScheduleProfileFetch() {
final int attempts = getNumberOfProfileFetch();
final long delta = System.currentTimeMillis() - getLastProfileFetchTimestamp();
return delta > PROFILE_FETCH_RETRY_BACKOFF_DELTA_IN_MILLISECONDS || attempts < MAX_PROFILE_FETCH_RETRIES;
/**
* Create an intent announcing that the profile JSON attached to this Firefox Account has been updated.
* <p>
* It is not guaranteed that the profile JSON has changed.
*
* @return <code>Intent</code> to broadcast.
*/
private Intent makeProfileJSONUpdatedIntent() {
final Intent intent = new Intent();
intent.setAction(FxAccountConstants.ACCOUNT_PROFILE_JSON_UPDATED_ACTION);
return intent;
}
public void setLastSyncedTimestamp(long now) {
@ -755,60 +725,31 @@ public class AndroidFxAccount {
ContentResolver.setIsSyncable(account, BrowserContract.READING_LIST_AUTHORITY, 1);
}
// Helper function to create intent for profile avatar updated event.
private Intent getProfileAvatarUpdatedIntent() {
final Intent profileCachedIntent = new Intent();
profileCachedIntent.setAction(FxAccountConstants.ACCOUNT_PROFILE_AVATAR_UPDATED_ACTION);
return profileCachedIntent;
}
/**
* Returns the cached profile JSON object if available or null.
* Returns the current profile JSON if available, or null.
*
* @return profile JSON Object.
* @return profile JSON object.
*/
public ExtendedJSONObject getCachedProfileJSON() {
if (profileJson == null) {
// Try to retrieve and parse the json string from account manager.
final String profileJsonString = accountManager.getUserData(account, ACCOUNT_KEY_PROFILE_AVATAR);
if (profileJsonString != null) {
Logger.info(LOG_TAG, "Cached Profile information retrieved from AccountManager.");
try {
profileJson = ExtendedJSONObject.parseJSONObject(profileJsonString);
} catch (Exception e) {
Logger.error(LOG_TAG, "Failed to parse profile json; ignoring.", e);
}
}
public ExtendedJSONObject getProfileJSON() {
final String profileString = getBundleData(BUNDLE_KEY_PROFILE_JSON);
if (profileString == null) {
return null;
}
return profileJson;
try {
return new ExtendedJSONObject(profileString);
} catch (Exception e) {
Logger.error(LOG_TAG, "Failed to parse profile JSON; ignoring and returning null.", e);
}
return null;
}
/**
* Fetches the profile json from the server and updates the local cache.
*
* Fetch the profile JSON associated to the underlying Firefox Account from the server and update the local store.
* <p>
* On successful fetch and cache, LocalBroadcastManager is used to notify the receivers asynchronously.
* </p>
*
* @param isForceFetch boolean to isForceFetch fetch from the server.
* The LocalBroadcastManager is used to notify the receivers asynchronously after a successful fetch.
*/
public void maybeUpdateProfileJSON(final boolean isForceFetch) {
final ExtendedJSONObject profileJson = getCachedProfileJSON();
final Intent profileAvatarUpdatedIntent = getProfileAvatarUpdatedIntent();
if (!isForceFetch && profileJson != null && !profileJson.keySet().isEmpty()) {
// Second line of defense, cache may have been updated in between.
Logger.info(LOG_TAG, "Profile already cached.");
LocalBroadcastManager.getInstance(context).sendBroadcast(profileAvatarUpdatedIntent);
return;
}
if (!isForceFetch && !canScheduleProfileFetch()) {
// Rate limiting repeated attempts to fetch the profile information.
Logger.info(LOG_TAG, "Too many attempts to fetch the profile information.");
return;
}
public void fetchProfileJSON() {
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
@ -828,24 +769,15 @@ public class AndroidFxAccount {
final Intent intent = new Intent(context, FxAccountProfileService.class);
intent.putExtra(FxAccountProfileService.KEY_AUTH_TOKEN, authToken);
intent.putExtra(FxAccountProfileService.KEY_PROFILE_SERVER_URI, getProfileServerURI());
intent.putExtra(FxAccountProfileService.KEY_RESULT_RECEIVER, new ProfileResultReceiver(profileAvatarUpdatedIntent));
intent.putExtra(FxAccountProfileService.KEY_RESULT_RECEIVER, new ProfileResultReceiver(new Handler()));
context.startService(intent);
// Update the profile fetch time and attempts, resetting the attempts if last fetch was over a day old.
final int attempts = getNumberOfProfileFetch();
final long now = System.currentTimeMillis();
final long delta = now - getLastProfileFetchTimestamp();
setLastProfileFetchTimestampAndAttempts(now, delta < PROFILE_FETCH_RETRY_BACKOFF_DELTA_IN_MILLISECONDS ? attempts + 1 : 1);
}
});
}
private class ProfileResultReceiver extends ResultReceiver {
private final Intent profileAvatarUpdatedIntent;
public ProfileResultReceiver(Intent broadcastIntent) {
super(new Handler());
this.profileAvatarUpdatedIntent = broadcastIntent;
public ProfileResultReceiver(Handler handler) {
super(handler);
}
@Override
@ -853,21 +785,17 @@ public class AndroidFxAccount {
super.onReceiveResult(resultCode, bundle);
switch (resultCode) {
case Activity.RESULT_OK:
try {
final String resultData = bundle.getString(FxAccountProfileService.KEY_RESULT_STRING);
profileJson = ExtendedJSONObject.parseJSONObject(resultData);
accountManager.setUserData(account, ACCOUNT_KEY_PROFILE_AVATAR, resultData);
Logger.pii(LOG_TAG, "Profile fetch successful." + resultData);
LocalBroadcastManager.getInstance(context).sendBroadcast(profileAvatarUpdatedIntent);
} catch (Exception e) {
Logger.error(LOG_TAG, "Failed to parse profile json; ignoring.", e);
}
final String resultData = bundle.getString(FxAccountProfileService.KEY_RESULT_STRING);
updateBundleValues(BUNDLE_KEY_PROFILE_JSON, resultData);
Logger.info(LOG_TAG, "Profile JSON fetch succeeeded!");
FxAccountUtils.pii(LOG_TAG, "Profile JSON fetch returned: " + resultData);
LocalBroadcastManager.getInstance(context).sendBroadcast(makeDeletedAccountIntent());
break;
case Activity.RESULT_CANCELED:
Logger.warn(LOG_TAG, "Failed to fetch profile; ignoring.");
Logger.warn(LOG_TAG, "Failed to fetch profile JSON; ignoring.");
break;
default:
Logger.warn(LOG_TAG, "Invalid Result code received; ignoring.");
Logger.warn(LOG_TAG, "Invalid result code received; ignoring.");
break;
}
}

View File

@ -11,6 +11,7 @@ import android.os.Bundle;
import android.os.ResultReceiver;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountUtils;
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClient;
import org.mozilla.gecko.background.fxa.oauth.FxAccountAbstractClientException;
import org.mozilla.gecko.background.fxa.profile.FxAccountProfileClient10;
@ -37,6 +38,11 @@ public class FxAccountProfileService extends IntentService {
final String profileServerURI = intent.getStringExtra(KEY_PROFILE_SERVER_URI);
final ResultReceiver resultReceiver = intent.getParcelableExtra(KEY_RESULT_RECEIVER);
if (resultReceiver == null) {
Logger.warn(LOG_TAG, "Result receiver must not be null; ignoring intent.");
return;
}
if (authToken == null || authToken.length() == 0) {
Logger.warn(LOG_TAG, "Invalid Auth Token");
sendResult("Invalid Auth Token", resultReceiver, Activity.RESULT_CANCELED);
@ -66,7 +72,7 @@ public class FxAccountProfileService extends IntentService {
@Override
public void handleSuccess(ExtendedJSONObject result) {
if (result != null){
Logger.pii(LOG_TAG, "Profile Server response : " + result.toJSONString());
FxAccountUtils.pii(LOG_TAG, "Profile server return profile: " + result.toJSONString());
sendResult(result.toJSONString(), resultReceiver, Activity.RESULT_OK);
}
}

View File

@ -14,6 +14,7 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import org.mozilla.gecko.AppConstants;
import org.mozilla.gecko.background.common.log.Logger;
import org.mozilla.gecko.background.fxa.FxAccountUtils;
import org.mozilla.gecko.background.fxa.SkewHandler;
@ -532,6 +533,12 @@ public class FxAccountSyncAdapter extends AbstractThreadedSyncAdapter {
final KeyBundle syncKeyBundle = married.getSyncKeyBundle();
final String clientState = married.getClientState();
syncWithAssertion(audience, assertion, tokenServerEndpointURI, tokenBackoffHandler, sharedPrefs, syncKeyBundle, clientState, sessionCallback, extras, fxAccount);
if (AppConstants.MOZ_ANDROID_FIREFOX_ACCOUNT_PROFILES) {
// Force fetch the profile avatar information.
Logger.info(LOG_TAG, "Fetching profile avatar information.");
fxAccount.fetchProfileJSON();
}
} catch (Exception e) {
syncDelegate.handleError(e);
return;

View File

@ -426,9 +426,9 @@ size. -->
<!ENTITY site_settings_clear "Clear">
<!ENTITY site_settings_no_settings "There are no settings to clear.">
<!-- Localization note (reading_list_added2) : Used in a toast, please keep as short
<!-- Localization note (reading_list_added3) : Used in a toast, please keep as short
as possible. -->
<!ENTITY reading_list_added2 "Added to list">
<!ENTITY reading_list_added3 "Added to Reading List">
<!ENTITY reading_list_removed "Page removed from your Reading List">
<!-- Localization note (reading_list_remove) : Used to remove the currently open page from
the user's reading list. The opposite of overlay_share_reading_list_btn_label. -->

View File

@ -25,4 +25,9 @@
<dimen name="preference_fragment_padding_side">16dp</dimen>
<integer name="preference_fragment_scrollbarStyle">0x02000000</integer> <!-- outsideOverlay -->
<!-- Profile avatar image height. -->
<dimen name="fxaccount_profile_image_height">48dp</dimen>
<!-- Profile avatar image width. -->
<dimen name="fxaccount_profile_image_width">48dp</dimen>
</resources>

View File

@ -326,7 +326,7 @@
<string name="site_settings_clear">&site_settings_clear;</string>
<string name="site_settings_no_settings">&site_settings_no_settings;</string>
<string name="reading_list_added">&reading_list_added2;</string>
<string name="reading_list_added">&reading_list_added3;</string>
<string name="reading_list_removed">&reading_list_removed;</string>
<string name="reading_list_remove">&reading_list_remove;</string>
<string name="reading_list_duplicate">&reading_list_duplicate;</string>

View File

@ -5,8 +5,6 @@
"use strict";
/*globals gSyncCheckIntervalSecs, gUpdateTimerManager, Sqlite, DB_PATH */
this.EXPORTED_SYMBOLS = [ "HomeProvider" ];
const { utils: Cu, classes: Cc, interfaces: Ci } = Components;
@ -127,18 +125,18 @@ function syncTimerCallback(timer) {
}
}
let HomeStorage = function(datasetId) {
this.HomeStorage = function(datasetId) {
this.datasetId = datasetId;
};
let ValidationError = function(message) {
this.ValidationError = function(message) {
this.name = "ValidationError";
this.message = message;
};
ValidationError.prototype = new Error();
ValidationError.prototype.constructor = ValidationError;
let HomeProvider = Object.freeze({
this.HomeProvider = Object.freeze({
ValidationError: ValidationError,
/**

View File

@ -5,7 +5,7 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Amazon.com</ShortName>
<InputEncoding>ISO-8859-1</InputEncoding>
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZJREFUeNrEV01IFGEYfndXNzq0QdalJOoUbQiBUuopD2k/GFSG/Vxyq0OHbCUjwn7AEooUzUNRkdkhS1o9JBVaUDctKqhoRQi0WjtlxG6XVtfpfb6Z2caZ2ZnZXZdeeJxvx+973+f9+775XJIkkUaWMcoYG5TxfMpvxlvGMGM8+RYEFOxn/JJyLzOMiwwv7LqUCNQwHjpxIxKJ0Gg4LABZUVhIfr+f1jLSlNuMwyCwEHoZS6xmvxoZoc6Oq+JpJoVMpOncWdpcWZkOiRIQ2MKDp1az+kIhOtV40pHG6zdvpEOixc1/VtqFvKX5gmOX0pkL2yDgsZpxt+sORaPROe8Q6ncf3tPAk8eG3Ks14lA8brsZYZ2yukBAwOfzCeMHA3WGNXrCVpLnJKeqRyhAfX5RfNmILQF4urG0VIzxBBkU5aQI9agIeU4JqNLZ0UH9ob6sDWZE4MDefSn7P1txO/FcbxypQG18nhinew/u5zYC3dyG+qLL1qjjCKDg9C21q2a3oe9zRsCsn2PR2JzfKEy9PB96Nj8E0IJm54IaGZwPZsWJOU4jY1kD2OlAQhsJjKu3bSe7yPUzifpgMPsuOBY8brtR1evmyFt0IL0IzH4fJtcCH7kK1hn2/hh71G1yKKEdz/DBBIOTkUkRemzVl1uvCGKzE4OMIaFbiv1LSX51L7mXl4kxvgeO8vMaJk0PHiHvjl4DCTWs2lMOX0L6cwD/Bxlp6hNNv2gUT9MjsLiB8koaMOxJRgCMgPijWsqvaCP3qqqUZ4JVzUASYyFyL/WTqyggPxWH4qGtBlJzagCGIYjEzJv2zHe38vOUt6mNPGv20OyPMMV7yuVwL5IjBlLmRej1UX7VLdmLt+2CMVKTiSDn0wO1NPPyBOtdLL+MyzWkTbGhC5AGsBdKkEtWAjglgjUwCq/FGjhV0ZosdOhXI5FyH0DoIIK9slB0CS8UCgr8AlpvpamwqHpttcO4WtSqA57ioKENE05IqIYSY46uD4Is0qmGG2s9RYeS7adI3Paz3K6lTMmzIdFmXp/d1Gb1YvLF7i4IzxMfu1ITYWOe1VWix7U5tlKpXkzwYycONqfVLcW+cU7lQ0jePf360DqRS4zT/+Ny+ofRxPBoL6fa6zmu5uvtbkwZyE/lev6a8VV9+VeAAQADg36zc4GRNAAAAABJRU5ErkJggg==</Image>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Url type="text/html" method="GET" template="http://www.amazon.com/gp/aw/s">
<Param name="k" value="{searchTerms}"/>
<Param name="sourceid" value="Mozilla-search"/>

View File

@ -4,7 +4,7 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Bing</ShortName>
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDE0IDc5LjE1MTQ4MSwgMjAxMy8wMy8xMy0xMjowOToxNSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjMzMkQxN0Y5NkYxMDExRTNCRERGREFGNkIwOTFENDc1IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjMzMkQxN0ZBNkYxMDExRTNCRERGREFGNkIwOTFENDc1Ij4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6MzMyRDE3Rjc2RjEwMTFFM0JEREZEQUY2QjA5MUQ0NzUiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6MzMyRDE3Rjg2RjEwMTFFM0JEREZEQUY2QjA5MUQ0NzUiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4iSWmdAAACDElEQVR42mIMCAhgoCVgYqAxGPoWMGtoaGCKzo7ZKcH37c9fpjdfOf//Z6TEAhasoiI837107gHR15+sZx9JzDum8/E7O02CiJv9t53qYyHuH6OpiCBgZPxPWwv4OX71BB+INL2uJPKBCqkIE3z4zv7gLV+Y8U0gev2F8+R9qRP3Ja8/F/5HKBGzEO+WTZdUnDUeARmiPN99dO8C0acfbKcfSJ68L3nhiejvv8yUWvDoHd+Fx2IGsq/gInwcv5w1HgLRjz/M5x6Jd+8yozQVbbioglWcg+WvldIzKiTTS0/EmrdZXn4qQv1IhgBgUgUGBRDpSr+u9DjJyfqHyhaASkemf25aD8KNbxJjOlEW/PnH9O0nKyivMTBYKj+NMbsmyf+VakH07RdLx07zl5+5dKTexFtcVRF7j8sRGy6okGwBMJk3b7X6/Zepxuu4sdxLXMouPhGdfUT/6Qce0ix4+5Vzwl5jYJXgoP4IV2Z9/40DWFUcuSNDchA9/8hz6alInfdxVua/WBUAS4itl5VWnNEEhiE5cfDoHa+71gNcem6+FJpxSP/BW37y6+Sjd2V+/GbRkX7DhFpKf/7BNveo3uzD+h++c1CUiv6DS4VLT0WLXE5LC3yBiOy5Lr/4pDbQDiq0KuBxuO+GPD/nL6A/Onea77iq9OsPM3VaFXAALCanHTQYbToObQsAAgwAOOjO/za44IcAAAAASUVORK5CYII=</Image>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Url type="application/x-suggestions+json" template="https://www.bing.com/osjson.aspx">
<Param name="query" value="{searchTerms}"/>
<Param name="language" value="{moz:locale}"/>

File diff suppressed because one or more lines are too long

View File

@ -5,7 +5,7 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Google</ShortName>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAACv0lEQVR42sWX208TURDG958x8M+It5CoDxojGn0wPvCg8UljYhRjBCpqJBQbL6lgI5JyERpFRLAiF7GiqI0QbUCIlm1pQ6XM556z7dQNbTl1l/olkzTd0zO/THe+OUfbXk8ithnhM0I3Alscusxl5tRE8gojokagzBEVubUMDUqJ4x6CNwhMfQOiCSCVRl6tpYFHY8DeGwX38mkllF1u9OwDkEwB90cIZx4SrvQSpiNgEYC218DFLsKR1k33jGuqyfcZyWeXgPQ6UOu1PtvZSBj6BJaeBI7eVttXGWDkC4REorzPq5sIS3GwQt/hHMDpdkJWd4YLr3MPEv7WibsOAfgnwbo1UHjdwWYrwLWAQwDjc2D53hQv7fwyWC2DDgGMzYI1HSkKIFqTVdftEED7KFhEwGH35gCpNWD/TfsAbDxEYAXe56/CLheJFpTyDDnchg+CsKixf+Mab2ZN11ugqt5ZALGhdL+1dM7xhj+bIK4AYWIOUq0v+DeOAnDUuEmWd3AGCIaBnytgie/kOvsA6rEYA8vzksoPoCfBWtCBQy1lBuiZgkW/EsCptq0D4Ol3zEM495ik263TxnNAXbdzANzj9X3SlqXJrBoxM29Ox9538rNFAup8p0MAtV7p8Txmz3YIIOuaHQ3SByyGlViFOEfYApBl/m32vvy/qxqKr7/UxV6R8QUbANVN/JbLft/tUvu7rj4hZW/QVDd6/hEoxTUX9OwJygZA5wRYA6oAPBXZnP4ZQHp/VstJYI9LvQI/YuYBtsZtA+DkPQIhp76Q2pS73EOAeTy334Yd47BITD0BVsigrj8lpNLSG0RrKgHoxcspp58wH4siUfMN90+a8SoM2TFLcXEpUX5X4spXswPNJHt69CvkBEymcpeQ8CLQHwIu+NmgVIKvZpX/8XJamb2eV2QqEStD4pjMZebU/gD3oidE+JhxZwAAAABJRU5ErkJggg==</Image>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Url type="application/x-suggestions+json" method="GET" template="https://www.google.com/complete/search?client=firefox&amp;q={searchTerms}"/>
<Url type="text/html" method="GET" template="https://www.google.com/search">
<Param name="q" value="{searchTerms}"/>

View File

@ -4,7 +4,7 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Twitter</ShortName>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Url type="text/html" method="GET" template="https://mobile.twitter.com/search/">
<Param name="q" value="{searchTerms}"/>
</Url>

View File

@ -5,7 +5,7 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Wikipedia</ShortName>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAQAAADZc7J/AAAACXBIWXMAAAsTAAALEwEAmpwYAAADGGlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjaY2BgnuDo4uTKJMDAUFBUUuQe5BgZERmlwH6egY2BmYGBgYGBITG5uMAxIMCHgYGBIS8/L5UBFTAyMHy7xsDIwMDAcFnX0cXJlYE0wJpcUFTCwMBwgIGBwSgltTiZgYHhCwMDQ3p5SUEJAwNjDAMDg0hSdkEJAwNjAQMDg0h2SJAzAwNjCwMDE09JakUJAwMDg3N+QWVRZnpGiYKhpaWlgmNKflKqQnBlcUlqbrGCZ15yflFBflFiSWoKAwMD1A4GBgYGXpf8EgX3xMw8BSMDVQYqg4jIKAUICxE+CDEESC4tKoMHJQODAIMCgwGDA0MAQyJDPcMChqMMbxjFGV0YSxlXMN5jEmMKYprAdIFZmDmSeSHzGxZLlg6WW6x6rK2s99gs2aaxfWMPZ9/NocTRxfGFM5HzApcj1xZuTe4FPFI8U3mFeCfxCfNN45fhXyygI7BD0FXwilCq0A/hXhEVkb2i4aJfxCaJG4lfkaiQlJM8JpUvLS19QqZMVl32llyfvIv8H4WtioVKekpvldeqFKiaqP5UO6jepRGqqaT5QeuA9iSdVF0rPUG9V/pHDBYY1hrFGNuayJsym740u2C+02KJ5QSrOutcmzjbQDtXe2sHY0cdJzVnJRcFV3k3BXdlD3VPXS8Tbxsfd99gvwT//ID6wIlBS4N3hVwMfRnOFCEXaRUVEV0RMzN2T9yDBLZE3aSw5IaUNak30zkyLDIzs+ZmX8xlz7PPryjYVPiuWLskq3RV2ZsK/cqSql01jLVedVPrHzbqNdU0n22VaytsP9op3VXUfbpXta+x/+5Em0mzJ/+dGj/t8AyNmf2zvs9JmHt6vvmCpYtEFrcu+bYsc/m9lSGrTq9xWbtvveWGbZtMNm/ZarJt+w6rnft3u+45uy9s/4ODOYd+Hmk/Jn58xUnrU+fOJJ/9dX7SRe1LR68kXv13fc5Nm1t379TfU75/4mHeY7En+59lvhB5efB1/lv5dxc+NH0y/fzq64Lv4T8Ffp360/rP8f9/AA0ADzT6lvFdAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAAHqSURBVHjapJUxb9NQFIW/JAip2xNS1/J+goeqUqeajdGVmFgwI1OcmYEgITFG7EgJQ+b2HzgbElJF+QU2iBl7YAFRnQ5+fnFcB0J8Jp/r53vPu+f6vYEA4JBTTjhkN/zkio9kAAihpyr1v/ijN7ovEHqiffFeDHTAdx6wL46HnPX4HM6HHNEHR0NGvRKMhvRE7wT3ACYssBggpyThIRMCAFaEzHhOiQWumfGFBQGQY0kB9EKSCsVCyKpQxUMhdOEMj4Vi91wIGX2uyNJtwTDHAgbjOUBJ/T50ETDAzCn0CiRpLkSd2VW1rqZR6uOpzHoWl40EkmkIlTIhNJc0bUSlSNNtCaZCKGtpyDZimXB92uhBhTEAHzx/BuQ8Isb62Dti16c7PahrNnbovFhXLGQaau4oqDSULDx/BcCl55cEDTUdCqqagWcXbjpqWD8ZWxRUGq5ZOTYhAXLHV0DU/qCtQLJCkZuM0PHQGThvL152JJh5M61SP2CpMpmmgdsTFDJCiaaubq0haQ7Q3xLUZq4NqzS0DNzWxNq8ksgbFmGgwf95oFgijJuB6v9L3Fx2HSg3XeExZxv1xuSEXQt/o8fqg9cDHfB15zuxjRuOETrfu/5b9bhcf+mlRmLgr/cTgp1vqR9c8YlvALcDAPr5jIx+4LKcAAAAAElFTkSuQmCC</Image>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Url type="application/x-suggestions+json" method="GET" template="https://en.wikipedia.org/w/api.php">
<Param name="action" value="opensearch"/>
<Param name="search" value="{searchTerms}"/>

View File

@ -5,7 +5,7 @@
<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
<ShortName>Yahoo</ShortName>
<InputEncoding>UTF-8</InputEncoding>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Image width="16" height="16">data:image/png;base64,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</Image>
<Url type="application/x-suggestions+json" method="GET"
template="https://search.yahoo.com/sugg/ff">
<Param name="output" value="fxjson" />

View File

@ -325,7 +325,6 @@ class Artifacts(object):
n = os.path.join(distdir, 'bin', os.path.basename(info.filename))
fh = FileAvoidWrite(n, mode='r')
shutil.copyfileobj(zf.open(info), fh)
fh.write(zf.open(info).read())
file_existed, file_updated = fh.close()
self.log(logging.INFO, 'artifact',
{'updating': 'Updating' if file_updated else 'Not updating', 'filename': n},

View File

@ -511,7 +511,8 @@ DebuggerClient.prototype = {
executeSoon(() => aOnResponse({
from: workerClient.actor,
type: "attached",
isFrozen: workerClient.isFrozen
isFrozen: workerClient.isFrozen,
url: workerClient.url
}, workerClient));
return;
}
@ -1379,6 +1380,8 @@ function WorkerClient(aClient, aForm) {
this.addListener("close", this._onClose);
this.addListener("freeze", this._onFreeze);
this.addListener("thaw", this._onThaw);
this.traits = {};
}
WorkerClient.prototype = {
@ -1454,6 +1457,10 @@ WorkerClient.prototype = {
this._isFrozen = false;
},
reconfigure: function () {
return Promise.resolve();
},
events: ["close", "freeze", "thaw"]
};