зеркало из https://github.com/mozilla/gecko-dev.git
Bug 630614 - Show an indicator when geolocation is in use. r=johannh
Differential Revision: https://phabricator.services.mozilla.com/D35428 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
741e60d13d
Коммит
15afab0390
|
@ -256,6 +256,18 @@ var gIdentityHandler = {
|
||||||
));
|
));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
get _geoSharingIcon() {
|
||||||
|
delete this._geoSharingIcon;
|
||||||
|
return (this._geoSharingIcon = document.getElementById("geo-sharing-icon"));
|
||||||
|
},
|
||||||
|
|
||||||
|
get _webRTCSharingIcon() {
|
||||||
|
delete this._webRTCSharingIcon;
|
||||||
|
return (this._webRTCSharingIcon = document.getElementById(
|
||||||
|
"webrtc-sharing-icon"
|
||||||
|
));
|
||||||
|
},
|
||||||
|
|
||||||
get _insecureConnectionIconEnabled() {
|
get _insecureConnectionIconEnabled() {
|
||||||
delete this._insecureConnectionIconEnabled;
|
delete this._insecureConnectionIconEnabled;
|
||||||
XPCOMUtils.defineLazyPreferenceGetter(
|
XPCOMUtils.defineLazyPreferenceGetter(
|
||||||
|
@ -513,12 +525,27 @@ var gIdentityHandler = {
|
||||||
let tab = gBrowser.selectedTab;
|
let tab = gBrowser.selectedTab;
|
||||||
this._sharingState = tab._sharingState;
|
this._sharingState = tab._sharingState;
|
||||||
|
|
||||||
this._identityBox.removeAttribute("paused");
|
this._webRTCSharingIcon.removeAttribute("paused");
|
||||||
this._identityBox.removeAttribute("sharing");
|
this._webRTCSharingIcon.removeAttribute("sharing");
|
||||||
if (this._sharingState && this._sharingState.sharing) {
|
this._geoSharingIcon.removeAttribute("sharing");
|
||||||
this._identityBox.setAttribute("sharing", this._sharingState.sharing);
|
|
||||||
if (this._sharingState.paused) {
|
if (this._sharingState) {
|
||||||
this._identityBox.setAttribute("paused", "true");
|
if (
|
||||||
|
this._sharingState &&
|
||||||
|
this._sharingState.webRTC &&
|
||||||
|
this._sharingState.webRTC.sharing
|
||||||
|
) {
|
||||||
|
this._webRTCSharingIcon.setAttribute(
|
||||||
|
"sharing",
|
||||||
|
this._sharingState.webRTC.sharing
|
||||||
|
);
|
||||||
|
|
||||||
|
if (this._sharingState.webRTC.paused) {
|
||||||
|
this._webRTCSharingIcon.setAttribute("paused", "true");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this._sharingState.geo) {
|
||||||
|
this._geoSharingIcon.setAttribute("sharing", this._sharingState.geo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1183,18 +1210,33 @@ var gIdentityHandler = {
|
||||||
gBrowser.selectedBrowser
|
gBrowser.selectedBrowser
|
||||||
);
|
);
|
||||||
|
|
||||||
if (this._sharingState) {
|
if (this._sharingState && this._sharingState.geo) {
|
||||||
|
let geoPermission = permissions.find(perm => perm.id === "geo");
|
||||||
|
if (geoPermission) {
|
||||||
|
geoPermission.sharingState = true;
|
||||||
|
} else {
|
||||||
|
permissions.push({
|
||||||
|
id: "geo",
|
||||||
|
state: SitePermissions.ALLOW,
|
||||||
|
scope: SitePermissions.SCOPE_REQUEST,
|
||||||
|
sharingState: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this._sharingState && this._sharingState.webRTC) {
|
||||||
|
let webrtcState = this._sharingState.webRTC;
|
||||||
// If WebRTC device or screen permissions are in use, we need to find
|
// If WebRTC device or screen permissions are in use, we need to find
|
||||||
// the associated permission item to set the sharingState field.
|
// the associated permission item to set the sharingState field.
|
||||||
for (let id of ["camera", "microphone", "screen"]) {
|
for (let id of ["camera", "microphone", "screen"]) {
|
||||||
if (this._sharingState[id]) {
|
if (webrtcState[id]) {
|
||||||
let found = false;
|
let found = false;
|
||||||
for (let permission of permissions) {
|
for (let permission of permissions) {
|
||||||
if (permission.id != id) {
|
if (permission.id != id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
found = true;
|
found = true;
|
||||||
permission.sharingState = this._sharingState[id];
|
permission.sharingState = webrtcState[id];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!found) {
|
if (!found) {
|
||||||
|
@ -1205,7 +1247,7 @@ var gIdentityHandler = {
|
||||||
id,
|
id,
|
||||||
state: SitePermissions.ALLOW,
|
state: SitePermissions.ALLOW,
|
||||||
scope: SitePermissions.SCOPE_REQUEST,
|
scope: SitePermissions.SCOPE_REQUEST,
|
||||||
sharingState: this._sharingState[id],
|
sharingState: webrtcState[id],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1232,6 +1274,11 @@ var gIdentityHandler = {
|
||||||
) {
|
) {
|
||||||
this._createBlockedPopupIndicator();
|
this._createBlockedPopupIndicator();
|
||||||
hasBlockedPopupIndicator = true;
|
hasBlockedPopupIndicator = true;
|
||||||
|
} else if (
|
||||||
|
permission.id == "geo" &&
|
||||||
|
permission.state === SitePermissions.ALLOW
|
||||||
|
) {
|
||||||
|
this._createGeoLocationLastAccessIndicator();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1288,9 +1335,7 @@ var gIdentityHandler = {
|
||||||
// Synchronize control center and identity block blinking animations.
|
// Synchronize control center and identity block blinking animations.
|
||||||
window
|
window
|
||||||
.promiseDocumentFlushed(() => {
|
.promiseDocumentFlushed(() => {
|
||||||
let sharingIconBlink = document
|
let sharingIconBlink = this._webRTCSharingIcon.getAnimations()[0];
|
||||||
.getElementById("sharing-icon")
|
|
||||||
.getAnimations()[0];
|
|
||||||
let imgBlink = img.getAnimations()[0];
|
let imgBlink = img.getAnimations()[0];
|
||||||
return [sharingIconBlink, imgBlink];
|
return [sharingIconBlink, imgBlink];
|
||||||
})
|
})
|
||||||
|
@ -1403,6 +1448,24 @@ var gIdentityHandler = {
|
||||||
return container;
|
return container;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (aPermission.id == "geo") {
|
||||||
|
let block = document.createXULElement("vbox");
|
||||||
|
block.setAttribute("id", "identity-popup-geo-container");
|
||||||
|
|
||||||
|
let button = this._createPermissionClearButton(aPermission, block);
|
||||||
|
container.appendChild(button);
|
||||||
|
|
||||||
|
block.appendChild(container);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
let button = this._createPermissionClearButton(aPermission, container);
|
||||||
|
container.appendChild(button);
|
||||||
|
|
||||||
|
return container;
|
||||||
|
},
|
||||||
|
|
||||||
|
_createPermissionClearButton(aPermission, container) {
|
||||||
let button = document.createXULElement("button");
|
let button = document.createXULElement("button");
|
||||||
button.setAttribute("class", "identity-popup-permission-remove-button");
|
button.setAttribute("class", "identity-popup-permission-remove-button");
|
||||||
let tooltiptext = gNavigatorBundle.getString("permissions.remove.tooltip");
|
let tooltiptext = gNavigatorBundle.getString("permissions.remove.tooltip");
|
||||||
|
@ -1414,7 +1477,7 @@ var gIdentityHandler = {
|
||||||
aPermission.sharingState &&
|
aPermission.sharingState &&
|
||||||
["camera", "microphone", "screen"].includes(aPermission.id)
|
["camera", "microphone", "screen"].includes(aPermission.id)
|
||||||
) {
|
) {
|
||||||
let windowId = this._sharingState.windowId;
|
let windowId = this._sharingState.webRTC.windowId;
|
||||||
if (aPermission.id == "screen") {
|
if (aPermission.id == "screen") {
|
||||||
windowId = "screen:" + windowId;
|
windowId = "screen:" + windowId;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1426,7 +1489,7 @@ var gIdentityHandler = {
|
||||||
// It's not possible to stop sharing one of camera/microphone
|
// It's not possible to stop sharing one of camera/microphone
|
||||||
// without the other.
|
// without the other.
|
||||||
for (let id of ["camera", "microphone"]) {
|
for (let id of ["camera", "microphone"]) {
|
||||||
if (this._sharingState[id]) {
|
if (this._sharingState.webRTC[id]) {
|
||||||
let perm = SitePermissions.getForPrincipal(principal, id);
|
let perm = SitePermissions.getForPrincipal(principal, id);
|
||||||
if (
|
if (
|
||||||
perm.state == SitePermissions.ALLOW &&
|
perm.state == SitePermissions.ALLOW &&
|
||||||
|
@ -1451,11 +1514,71 @@ var gIdentityHandler = {
|
||||||
PanelView.forNode(
|
PanelView.forNode(
|
||||||
this._identityPopupMainView
|
this._identityPopupMainView
|
||||||
).descriptionHeightWorkaround();
|
).descriptionHeightWorkaround();
|
||||||
|
|
||||||
|
if (aPermission.id === "geo") {
|
||||||
|
gBrowser.updateBrowserSharing(browser, { geo: false });
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
container.appendChild(button);
|
return button;
|
||||||
|
},
|
||||||
|
|
||||||
return container;
|
_getGeoLocationLastAccess() {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let lastAccess = null;
|
||||||
|
ContentPrefService2.getByDomainAndName(
|
||||||
|
gBrowser.currentURI.spec,
|
||||||
|
"permissions.geoLocation.lastAccess",
|
||||||
|
gBrowser.selectedBrowser.loadContext,
|
||||||
|
{
|
||||||
|
handleResult(pref) {
|
||||||
|
lastAccess = pref.value;
|
||||||
|
},
|
||||||
|
handleCompletion() {
|
||||||
|
resolve(lastAccess);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async _createGeoLocationLastAccessIndicator() {
|
||||||
|
let lastAccessStr = await this._getGeoLocationLastAccess();
|
||||||
|
|
||||||
|
if (lastAccessStr == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let lastAccess = new Date(lastAccessStr);
|
||||||
|
if (isNaN(lastAccess)) {
|
||||||
|
Cu.reportError("Invalid timestamp for last geolocation access");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let icon = document.createXULElement("image");
|
||||||
|
icon.setAttribute("class", "popup-subitem");
|
||||||
|
|
||||||
|
let indicator = document.createXULElement("hbox");
|
||||||
|
indicator.setAttribute("class", "identity-popup-permission-item");
|
||||||
|
indicator.setAttribute("align", "center");
|
||||||
|
indicator.setAttribute("id", "geo-access-indicator-item");
|
||||||
|
|
||||||
|
let timeFormat = new Services.intl.RelativeTimeFormat(undefined, {});
|
||||||
|
|
||||||
|
let text = document.createXULElement("label");
|
||||||
|
text.setAttribute("flex", "1");
|
||||||
|
text.setAttribute("class", "identity-popup-permission-label");
|
||||||
|
|
||||||
|
text.textContent = gNavigatorBundle.getFormattedString(
|
||||||
|
"geolocationLastAccessIndicatorText",
|
||||||
|
[timeFormat.formatBestUnit(lastAccess)]
|
||||||
|
);
|
||||||
|
|
||||||
|
indicator.appendChild(icon);
|
||||||
|
indicator.appendChild(text);
|
||||||
|
|
||||||
|
document
|
||||||
|
.getElementById("identity-popup-geo-container")
|
||||||
|
.appendChild(indicator);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createBlockedPopupIndicator() {
|
_createBlockedPopupIndicator() {
|
||||||
|
|
|
@ -242,6 +242,10 @@ XPCOMUtils.defineLazyScriptGetter(
|
||||||
// lazy service getters
|
// lazy service getters
|
||||||
|
|
||||||
XPCOMUtils.defineLazyServiceGetters(this, {
|
XPCOMUtils.defineLazyServiceGetters(this, {
|
||||||
|
ContentPrefService2: [
|
||||||
|
"@mozilla.org/content-pref/service;1",
|
||||||
|
"nsIContentPrefService2",
|
||||||
|
],
|
||||||
classifierService: [
|
classifierService: [
|
||||||
"@mozilla.org/url-classifier/dbservice;1",
|
"@mozilla.org/url-classifier/dbservice;1",
|
||||||
"nsIURIClassifier",
|
"nsIURIClassifier",
|
||||||
|
@ -6300,7 +6304,7 @@ var TabsProgressListener = {
|
||||||
|
|
||||||
let tab = gBrowser.getTabForBrowser(aBrowser);
|
let tab = gBrowser.getTabForBrowser(aBrowser);
|
||||||
if (tab && tab._sharingState) {
|
if (tab && tab._sharingState) {
|
||||||
gBrowser.setBrowserSharing(aBrowser, {});
|
gBrowser.resetBrowserSharing(aBrowser);
|
||||||
}
|
}
|
||||||
webrtcUI.forgetStreamsFromBrowser(aBrowser);
|
webrtcUI.forgetStreamsFromBrowser(aBrowser);
|
||||||
|
|
||||||
|
|
|
@ -865,7 +865,10 @@
|
||||||
<image id="identity-icon"
|
<image id="identity-icon"
|
||||||
consumeanchor="identity-box"
|
consumeanchor="identity-box"
|
||||||
onclick="PageProxyClickHandler(event);"/>
|
onclick="PageProxyClickHandler(event);"/>
|
||||||
<image id="sharing-icon" mousethrough="always"/>
|
<box mousethrough="always">
|
||||||
|
<image class="sharing-icon" id="webrtc-sharing-icon"/>
|
||||||
|
<image class="sharing-icon geo-icon" id="geo-sharing-icon"/>
|
||||||
|
</box>
|
||||||
<box id="blocked-permissions-container" align="center">
|
<box id="blocked-permissions-container" align="center">
|
||||||
<image data-permission-id="geo" class="blocked-permission-icon geo-icon" role="button"
|
<image data-permission-id="geo" class="blocked-permission-icon geo-icon" role="button"
|
||||||
tooltiptext="&urlbar.geolocationBlocked.tooltip;"/>
|
tooltiptext="&urlbar.geolocationBlocked.tooltip;"/>
|
||||||
|
|
|
@ -1403,21 +1403,35 @@
|
||||||
aTab.dispatchEvent(event);
|
aTab.dispatchEvent(event);
|
||||||
},
|
},
|
||||||
|
|
||||||
setBrowserSharing(aBrowser, aState) {
|
resetBrowserSharing(aBrowser) {
|
||||||
let tab = this.getTabForBrowser(aBrowser);
|
let tab = this.getTabForBrowser(aBrowser);
|
||||||
if (!tab) {
|
if (!tab) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
tab._sharingState = {};
|
||||||
|
tab.removeAttribute("sharing");
|
||||||
|
this._tabAttrModified(tab, ["sharing"]);
|
||||||
|
if (aBrowser == this.selectedBrowser) {
|
||||||
|
gIdentityHandler.updateSharingIndicator();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
if (aState.sharing) {
|
updateBrowserSharing(aBrowser, aState) {
|
||||||
tab._sharingState = aState;
|
let tab = this.getTabForBrowser(aBrowser);
|
||||||
if (aState.paused) {
|
if (!tab) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tab._sharingState == null) {
|
||||||
|
tab._sharingState = {};
|
||||||
|
}
|
||||||
|
tab._sharingState = Object.assign(tab._sharingState, aState);
|
||||||
|
if (aState.webRTC && aState.webRTC.sharing) {
|
||||||
|
if (aState.webRTC.paused) {
|
||||||
tab.removeAttribute("sharing");
|
tab.removeAttribute("sharing");
|
||||||
} else {
|
} else {
|
||||||
tab.setAttribute("sharing", aState.sharing);
|
tab.setAttribute("sharing", aState.webRTC.sharing);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tab._sharingState = null;
|
|
||||||
tab.removeAttribute("sharing");
|
tab.removeAttribute("sharing");
|
||||||
}
|
}
|
||||||
this._tabAttrModified(tab, ["sharing"]);
|
this._tabAttrModified(tab, ["sharing"]);
|
||||||
|
@ -1429,7 +1443,10 @@
|
||||||
|
|
||||||
getTabSharingState(aTab) {
|
getTabSharingState(aTab) {
|
||||||
// Normalize the state object for consumers (ie.extensions).
|
// Normalize the state object for consumers (ie.extensions).
|
||||||
let state = Object.assign({}, aTab._sharingState);
|
let state = Object.assign(
|
||||||
|
{},
|
||||||
|
aTab._sharingState && aTab._sharingState.webRTC
|
||||||
|
);
|
||||||
return {
|
return {
|
||||||
camera: !!state.camera,
|
camera: !!state.camera,
|
||||||
microphone: !!state.microphone,
|
microphone: !!state.microphone,
|
||||||
|
@ -2445,9 +2462,9 @@
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset webrtc sharing state.
|
// Reset sharing state.
|
||||||
if (aTab._sharingState) {
|
if (aTab._sharingState) {
|
||||||
this.setBrowserSharing(browser, {});
|
this.resetBrowserSharing(browser);
|
||||||
}
|
}
|
||||||
webrtcUI.forgetStreamsFromBrowser(browser);
|
webrtcUI.forgetStreamsFromBrowser(browser);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@ support-files =
|
||||||
!/image/test/mochitest/blue.png
|
!/image/test/mochitest/blue.png
|
||||||
skip-if = fission && debug # Causes shutdown leaks on automation under Fission.
|
skip-if = fission && debug # Causes shutdown leaks on automation under Fission.
|
||||||
|
|
||||||
|
[browser_geolocation_indicator.js]
|
||||||
[browser_bug822367.js]
|
[browser_bug822367.js]
|
||||||
tags = mcb
|
tags = mcb
|
||||||
support-files =
|
support-files =
|
||||||
|
|
|
@ -0,0 +1,329 @@
|
||||||
|
/* Any copyright is dedicated to the Public Domain.
|
||||||
|
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||||
|
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
ChromeUtils.import("resource:///modules/PermissionUI.jsm", this);
|
||||||
|
ChromeUtils.import("resource:///modules/SitePermissions.jsm", this);
|
||||||
|
|
||||||
|
const CP = Cc["@mozilla.org/content-pref/service;1"].getService(
|
||||||
|
Ci.nsIContentPrefService2
|
||||||
|
);
|
||||||
|
|
||||||
|
const EXAMPLE_PAGE_URL = "https://example.com";
|
||||||
|
const EXAMPLE_PAGE_URI = Services.io.newURI(EXAMPLE_PAGE_URL);
|
||||||
|
const GEO_CONTENT_PREF_KEY = "permissions.geoLocation.lastAccess";
|
||||||
|
const POLL_INTERVAL_FALSE_STATE = 50;
|
||||||
|
|
||||||
|
async function testGeoSharingIconVisible(state = true) {
|
||||||
|
let sharingIcon = document.getElementById("geo-sharing-icon");
|
||||||
|
ok(sharingIcon, "Geo sharing icon exists");
|
||||||
|
|
||||||
|
try {
|
||||||
|
await BrowserTestUtils.waitForCondition(
|
||||||
|
() => sharingIcon.hasAttribute("sharing") === true,
|
||||||
|
"Waiting for geo sharing icon visibility state",
|
||||||
|
// If we wait for sharing icon to *not* show, waitForCondition will always timeout on correct state.
|
||||||
|
// In these cases we want to reduce the wait time from 5 seconds to 2.5 seconds to prevent test duration timeouts
|
||||||
|
!state ? POLL_INTERVAL_FALSE_STATE : undefined
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
ok(!state, "Geo sharing icon not showing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ok(state, "Geo sharing icon showing");
|
||||||
|
}
|
||||||
|
|
||||||
|
async function checkForDOMElement(state, id) {
|
||||||
|
info(`Testing state ${state} of element ${id}`);
|
||||||
|
try {
|
||||||
|
await BrowserTestUtils.waitForCondition(
|
||||||
|
() => {
|
||||||
|
let el = document.getElementById(id);
|
||||||
|
return el != null;
|
||||||
|
},
|
||||||
|
`Waiting for ${id}`,
|
||||||
|
!state ? POLL_INTERVAL_FALSE_STATE : undefined
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
ok(!state, `${id} has correct state`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ok(state, `${id} has correct state`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testIdentityPopupGeoContainer(
|
||||||
|
containerVisible,
|
||||||
|
timestampVisible
|
||||||
|
) {
|
||||||
|
// Only call openIdentityPopup if popup is closed, otherwise it does not resolve
|
||||||
|
if (!gIdentityHandler._identityBox.hasAttribute("open")) {
|
||||||
|
await openIdentityPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
let checkContainer = checkForDOMElement(
|
||||||
|
containerVisible,
|
||||||
|
"identity-popup-geo-container"
|
||||||
|
);
|
||||||
|
let checkAccessIndicator = checkForDOMElement(
|
||||||
|
timestampVisible,
|
||||||
|
"geo-access-indicator-item"
|
||||||
|
);
|
||||||
|
|
||||||
|
return Promise.all([checkContainer, checkAccessIndicator]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function openExamplePage(tabbrowser = gBrowser) {
|
||||||
|
return BrowserTestUtils.openNewForegroundTab(tabbrowser, EXAMPLE_PAGE_URL);
|
||||||
|
}
|
||||||
|
|
||||||
|
function requestGeoLocation(browser) {
|
||||||
|
return ContentTask.spawn(browser, null, () => {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
content.navigator.geolocation.getCurrentPosition(
|
||||||
|
() => resolve(true),
|
||||||
|
error => resolve(error.code !== 1) // PERMISSION_DENIED = 1
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function answerGeoLocationPopup(allow, remember = false) {
|
||||||
|
let notification = PopupNotifications.getNotification("geolocation");
|
||||||
|
ok(
|
||||||
|
PopupNotifications.isPanelOpen && notification,
|
||||||
|
"Geolocation notification is open"
|
||||||
|
);
|
||||||
|
|
||||||
|
let rememberCheck = PopupNotifications.panel.querySelector(
|
||||||
|
".popup-notification-checkbox"
|
||||||
|
);
|
||||||
|
rememberCheck.checked = remember;
|
||||||
|
|
||||||
|
let popupHidden = BrowserTestUtils.waitForEvent(
|
||||||
|
PopupNotifications.panel,
|
||||||
|
"popuphidden"
|
||||||
|
);
|
||||||
|
if (allow) {
|
||||||
|
let allowBtn = PopupNotifications.panel.querySelector(
|
||||||
|
".popup-notification-primary-button"
|
||||||
|
);
|
||||||
|
allowBtn.click();
|
||||||
|
} else {
|
||||||
|
let denyBtn = PopupNotifications.panel.querySelector(
|
||||||
|
".popup-notification-secondary-button"
|
||||||
|
);
|
||||||
|
denyBtn.click();
|
||||||
|
}
|
||||||
|
return popupHidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setGeoLastAccess(browser, state) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
let host = browser.currentURI.host;
|
||||||
|
let handler = {
|
||||||
|
handleCompletion: () => resolve(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!state) {
|
||||||
|
CP.removeByDomainAndName(
|
||||||
|
host,
|
||||||
|
GEO_CONTENT_PREF_KEY,
|
||||||
|
browser.loadContext,
|
||||||
|
handler
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
CP.set(
|
||||||
|
host,
|
||||||
|
GEO_CONTENT_PREF_KEY,
|
||||||
|
new Date().toString(),
|
||||||
|
browser.loadContext,
|
||||||
|
handler
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testGeoLocationLastAccessSet(browser) {
|
||||||
|
let timestamp = await new Promise(resolve => {
|
||||||
|
let lastAccess = null;
|
||||||
|
CP.getByDomainAndName(
|
||||||
|
gBrowser.currentURI.spec,
|
||||||
|
GEO_CONTENT_PREF_KEY,
|
||||||
|
browser.loadContext,
|
||||||
|
{
|
||||||
|
handleResult(pref) {
|
||||||
|
lastAccess = pref.value;
|
||||||
|
},
|
||||||
|
handleCompletion() {
|
||||||
|
resolve(lastAccess);
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
ok(timestamp != null, "Geo last access timestamp set");
|
||||||
|
|
||||||
|
let parseSuccess = true;
|
||||||
|
try {
|
||||||
|
timestamp = new Date(timestamp);
|
||||||
|
} catch (e) {
|
||||||
|
parseSuccess = false;
|
||||||
|
}
|
||||||
|
ok(
|
||||||
|
parseSuccess && !isNaN(timestamp),
|
||||||
|
"Geo last access timestamp is valid Date"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function cleanup(tab) {
|
||||||
|
await setGeoLastAccess(tab.linkedBrowser, false);
|
||||||
|
SitePermissions.removeFromPrincipal(
|
||||||
|
tab.linkedBrowser.contentPrincipal,
|
||||||
|
"geo",
|
||||||
|
tab.linkedBrowser
|
||||||
|
);
|
||||||
|
gBrowser.resetBrowserSharing(tab.linkedBrowser);
|
||||||
|
BrowserTestUtils.removeTab(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testIndicatorGeoSharingState(active) {
|
||||||
|
let tab = await openExamplePage();
|
||||||
|
gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: active });
|
||||||
|
await testGeoSharingIconVisible(active);
|
||||||
|
|
||||||
|
await cleanup(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testIndicatorExplicitAllow(persistent) {
|
||||||
|
let tab = await openExamplePage();
|
||||||
|
|
||||||
|
let popupShown = BrowserTestUtils.waitForEvent(
|
||||||
|
PopupNotifications.panel,
|
||||||
|
"popupshown"
|
||||||
|
);
|
||||||
|
info("Requesting geolocation");
|
||||||
|
let request = requestGeoLocation(tab.linkedBrowser);
|
||||||
|
await popupShown;
|
||||||
|
info("Allowing geolocation via popup");
|
||||||
|
answerGeoLocationPopup(true, persistent);
|
||||||
|
await request;
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
testGeoSharingIconVisible(true),
|
||||||
|
testIdentityPopupGeoContainer(true, true),
|
||||||
|
testGeoLocationLastAccessSet(tab.linkedBrowser),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await cleanup(tab);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Indicator and identity popup entry shown after explicit PermissionUI geolocation allow
|
||||||
|
add_task(function test_indicator_and_timestamp_after_explicit_allow() {
|
||||||
|
return testIndicatorExplicitAllow(false);
|
||||||
|
});
|
||||||
|
add_task(function test_indicator_and_timestamp_after_explicit_allow_remember() {
|
||||||
|
return testIndicatorExplicitAllow(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Indicator and identity popup entry shown after auto PermissionUI geolocation allow
|
||||||
|
add_task(async function test_indicator_and_timestamp_after_implicit_allow() {
|
||||||
|
SitePermissions.set(
|
||||||
|
EXAMPLE_PAGE_URI,
|
||||||
|
"geo",
|
||||||
|
SitePermissions.ALLOW,
|
||||||
|
SitePermissions.SCOPE_PERSISTENT
|
||||||
|
);
|
||||||
|
let tab = await openExamplePage();
|
||||||
|
let result = await requestGeoLocation(tab.linkedBrowser);
|
||||||
|
ok(result, "Request should be allowed");
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
testGeoSharingIconVisible(true),
|
||||||
|
testIdentityPopupGeoContainer(true, true),
|
||||||
|
testGeoLocationLastAccessSet(tab.linkedBrowser),
|
||||||
|
]);
|
||||||
|
|
||||||
|
await cleanup(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Indicator shown when manually setting sharing state to true
|
||||||
|
add_task(function test_indicator_sharing_state_active() {
|
||||||
|
return testIndicatorGeoSharingState(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Indicator not shown when manually setting sharing state to false
|
||||||
|
add_task(function test_indicator_sharing_state_inactive() {
|
||||||
|
return testIndicatorGeoSharingState(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Identity popup shows permission if geo permission is set to persistent allow
|
||||||
|
add_task(async function test_identity_popup_permission_scope_permanent() {
|
||||||
|
SitePermissions.set(
|
||||||
|
EXAMPLE_PAGE_URI,
|
||||||
|
"geo",
|
||||||
|
SitePermissions.ALLOW,
|
||||||
|
SitePermissions.SCOPE_PERSISTENT
|
||||||
|
);
|
||||||
|
let tab = await openExamplePage();
|
||||||
|
|
||||||
|
await testIdentityPopupGeoContainer(true, false); // Expect permission to be visible, but not lastAccess indicator
|
||||||
|
|
||||||
|
await cleanup(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sharing state set, but no permission
|
||||||
|
add_task(async function test_identity_popup_permission_sharing_state() {
|
||||||
|
let tab = await openExamplePage();
|
||||||
|
gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
|
||||||
|
await testIdentityPopupGeoContainer(true, false);
|
||||||
|
|
||||||
|
await cleanup(tab);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Identity popup has correct state if sharing state and last geo access timestamp are set
|
||||||
|
add_task(
|
||||||
|
async function test_identity_popup_permission_sharing_state_timestamp() {
|
||||||
|
let tab = await openExamplePage();
|
||||||
|
gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
|
||||||
|
await setGeoLastAccess(tab.linkedBrowser, true);
|
||||||
|
|
||||||
|
await testIdentityPopupGeoContainer(true, true);
|
||||||
|
|
||||||
|
await cleanup(tab);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
// Clicking permission clear button clears permission and resets geo sharing state
|
||||||
|
add_task(async function test_identity_popup_permission_clear() {
|
||||||
|
SitePermissions.set(
|
||||||
|
EXAMPLE_PAGE_URI,
|
||||||
|
"geo",
|
||||||
|
SitePermissions.ALLOW,
|
||||||
|
SitePermissions.SCOPE_PERSISTENT
|
||||||
|
);
|
||||||
|
let tab = await openExamplePage();
|
||||||
|
gBrowser.updateBrowserSharing(tab.linkedBrowser, { geo: true });
|
||||||
|
|
||||||
|
await openIdentityPopup();
|
||||||
|
|
||||||
|
let clearButton = document.querySelector(
|
||||||
|
"#identity-popup-geo-container button"
|
||||||
|
);
|
||||||
|
ok(clearButton, "Clear button is visible");
|
||||||
|
clearButton.click();
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
testGeoSharingIconVisible(false),
|
||||||
|
testIdentityPopupGeoContainer(false, false),
|
||||||
|
BrowserTestUtils.waitForCondition(() => {
|
||||||
|
let sharingState = tab._sharingState;
|
||||||
|
return (
|
||||||
|
sharingState == null ||
|
||||||
|
sharingState.geo == null ||
|
||||||
|
sharingState.geo === false
|
||||||
|
);
|
||||||
|
}, "Waiting for geo sharing state to reset"),
|
||||||
|
]);
|
||||||
|
await cleanup(tab);
|
||||||
|
});
|
|
@ -2,6 +2,13 @@ var { XPCOMUtils } = ChromeUtils.import(
|
||||||
"resource://gre/modules/XPCOMUtils.jsm"
|
"resource://gre/modules/XPCOMUtils.jsm"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
function openIdentityPopup() {
|
||||||
|
let mainView = document.getElementById("identity-popup-mainView");
|
||||||
|
let viewShown = BrowserTestUtils.waitForEvent(mainView, "ViewShown");
|
||||||
|
gIdentityHandler._identityBox.click();
|
||||||
|
return viewShown;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waits for a load (or custom) event to finish in a given tab. If provided
|
* Waits for a load (or custom) event to finish in a given tab. If provided
|
||||||
* load an uri into the tab.
|
* load an uri into the tab.
|
||||||
|
|
|
@ -88,7 +88,7 @@ var gTests = [
|
||||||
// wait for it to avoid intermittents.
|
// wait for it to avoid intermittents.
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() =>
|
() =>
|
||||||
window.gIdentityHandler._sharingState.camera ==
|
window.gIdentityHandler._sharingState.webRTC.camera ==
|
||||||
STATE_CAPTURE_DISABLED,
|
STATE_CAPTURE_DISABLED,
|
||||||
"video should be disabled"
|
"video should be disabled"
|
||||||
);
|
);
|
||||||
|
@ -106,7 +106,7 @@ var gTests = [
|
||||||
|
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() =>
|
() =>
|
||||||
window.gIdentityHandler._sharingState.microphone ==
|
window.gIdentityHandler._sharingState.webRTC.microphone ==
|
||||||
STATE_CAPTURE_ENABLED,
|
STATE_CAPTURE_ENABLED,
|
||||||
"audio should be enabled"
|
"audio should be enabled"
|
||||||
);
|
);
|
||||||
|
@ -124,7 +124,8 @@ var gTests = [
|
||||||
|
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() =>
|
() =>
|
||||||
window.gIdentityHandler._sharingState.camera == STATE_CAPTURE_ENABLED,
|
window.gIdentityHandler._sharingState.webRTC.camera ==
|
||||||
|
STATE_CAPTURE_ENABLED,
|
||||||
"video should be enabled"
|
"video should be enabled"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -181,9 +182,9 @@ var gTests = [
|
||||||
// wait for it to avoid intermittents.
|
// wait for it to avoid intermittents.
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() =>
|
() =>
|
||||||
window.gIdentityHandler._sharingState.camera ==
|
window.gIdentityHandler._sharingState.webRTC.camera ==
|
||||||
STATE_CAPTURE_DISABLED &&
|
STATE_CAPTURE_DISABLED &&
|
||||||
window.gIdentityHandler._sharingState.microphone ==
|
window.gIdentityHandler._sharingState.webRTC.microphone ==
|
||||||
STATE_CAPTURE_DISABLED,
|
STATE_CAPTURE_DISABLED,
|
||||||
"video and audio should be disabled"
|
"video and audio should be disabled"
|
||||||
);
|
);
|
||||||
|
@ -201,7 +202,7 @@ var gTests = [
|
||||||
|
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() =>
|
() =>
|
||||||
window.gIdentityHandler._sharingState.microphone ==
|
window.gIdentityHandler._sharingState.webRTC.microphone ==
|
||||||
STATE_CAPTURE_ENABLED,
|
STATE_CAPTURE_ENABLED,
|
||||||
"audio should be enabled"
|
"audio should be enabled"
|
||||||
);
|
);
|
||||||
|
@ -219,7 +220,8 @@ var gTests = [
|
||||||
|
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() =>
|
() =>
|
||||||
window.gIdentityHandler._sharingState.camera == STATE_CAPTURE_ENABLED,
|
window.gIdentityHandler._sharingState.webRTC.camera ==
|
||||||
|
STATE_CAPTURE_ENABLED,
|
||||||
"video should be enabled"
|
"video should be enabled"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -276,7 +278,8 @@ var gTests = [
|
||||||
// It sometimes takes a bit longer before the change propagates to the UI,
|
// It sometimes takes a bit longer before the change propagates to the UI,
|
||||||
// wait for it to avoid intermittents.
|
// wait for it to avoid intermittents.
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() => window.gIdentityHandler._sharingState.screen == "ScreenPaused",
|
() =>
|
||||||
|
window.gIdentityHandler._sharingState.webRTC.screen == "ScreenPaused",
|
||||||
"screen should be disabled"
|
"screen should be disabled"
|
||||||
);
|
);
|
||||||
await expectObserverCalled("recording-device-events");
|
await expectObserverCalled("recording-device-events");
|
||||||
|
@ -287,7 +290,7 @@ var gTests = [
|
||||||
await setTrackEnabled(null, true);
|
await setTrackEnabled(null, true);
|
||||||
|
|
||||||
await BrowserTestUtils.waitForCondition(
|
await BrowserTestUtils.waitForCondition(
|
||||||
() => window.gIdentityHandler._sharingState.screen == "Screen",
|
() => window.gIdentityHandler._sharingState.webRTC.screen == "Screen",
|
||||||
"screen should be enabled"
|
"screen should be enabled"
|
||||||
);
|
);
|
||||||
await expectObserverCalled("recording-device-events");
|
await expectObserverCalled("recording-device-events");
|
||||||
|
|
|
@ -567,8 +567,9 @@ async function checkSharingUI(
|
||||||
let doc = aWin.document;
|
let doc = aWin.document;
|
||||||
// First check the icon above the control center (i) icon.
|
// First check the icon above the control center (i) icon.
|
||||||
let identityBox = doc.getElementById("identity-box");
|
let identityBox = doc.getElementById("identity-box");
|
||||||
ok(identityBox.hasAttribute("sharing"), "sharing attribute is set");
|
let webrtcSharingIcon = doc.getElementById("webrtc-sharing-icon");
|
||||||
let sharing = identityBox.getAttribute("sharing");
|
ok(webrtcSharingIcon.hasAttribute("sharing"), "sharing attribute is set");
|
||||||
|
let sharing = webrtcSharingIcon.getAttribute("sharing");
|
||||||
if (aExpected.screen) {
|
if (aExpected.screen) {
|
||||||
is(sharing, "screen", "showing screen icon in the identity block");
|
is(sharing, "screen", "showing screen icon in the identity block");
|
||||||
} else if (aExpected.video == STATE_CAPTURE_ENABLED) {
|
} else if (aExpected.video == STATE_CAPTURE_ENABLED) {
|
||||||
|
@ -583,7 +584,7 @@ async function checkSharingUI(
|
||||||
|
|
||||||
let allStreamsPaused = Object.values(aExpected).every(isPaused);
|
let allStreamsPaused = Object.values(aExpected).every(isPaused);
|
||||||
is(
|
is(
|
||||||
identityBox.hasAttribute("paused"),
|
webrtcSharingIcon.hasAttribute("paused"),
|
||||||
allStreamsPaused,
|
allStreamsPaused,
|
||||||
"sharing icon(s) should be in paused state when paused"
|
"sharing icon(s) should be in paused state when paused"
|
||||||
);
|
);
|
||||||
|
@ -603,7 +604,7 @@ async function checkSharingUI(
|
||||||
};
|
};
|
||||||
let expected = aExpected[convertId(id)];
|
let expected = aExpected[convertId(id)];
|
||||||
is(
|
is(
|
||||||
!!aWin.gIdentityHandler._sharingState[id],
|
!!aWin.gIdentityHandler._sharingState.webRTC[id],
|
||||||
!!expected,
|
!!expected,
|
||||||
"sharing state for " + id + " as expected"
|
"sharing state for " + id + " as expected"
|
||||||
);
|
);
|
||||||
|
@ -642,7 +643,7 @@ async function checkNotSharing() {
|
||||||
);
|
);
|
||||||
|
|
||||||
ok(
|
ok(
|
||||||
!document.getElementById("identity-box").hasAttribute("sharing"),
|
!document.getElementById("webrtc-sharing-icon").hasAttribute("sharing"),
|
||||||
"no sharing indicator on the control center icon"
|
"no sharing indicator on the control center icon"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -9,21 +9,23 @@ add_task(async function test_tabs_mediaIndicators() {
|
||||||
gBrowser,
|
gBrowser,
|
||||||
"http://example.com/"
|
"http://example.com/"
|
||||||
);
|
);
|
||||||
// setBrowserSharing is called when a request for media icons occurs. We're
|
// updateBrowserSharing is called when a request for media icons occurs. We're
|
||||||
// just testing that extension tabs get the info and are updated when it is
|
// just testing that extension tabs get the info and are updated when it is
|
||||||
// called.
|
// called.
|
||||||
gBrowser.setBrowserSharing(tab.linkedBrowser, {
|
gBrowser.updateBrowserSharing(tab.linkedBrowser, {
|
||||||
sharing: "screen",
|
webRTC: {
|
||||||
screen: "Window",
|
sharing: "screen",
|
||||||
microphone: Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED,
|
screen: "Window",
|
||||||
camera: Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED,
|
microphone: Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED,
|
||||||
|
camera: Ci.nsIMediaManagerService.STATE_CAPTURE_ENABLED,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
async function background() {
|
async function background() {
|
||||||
let tabs = await browser.tabs.query({ microphone: true });
|
let tabs = await browser.tabs.query({ microphone: true });
|
||||||
let testTab = tabs[0];
|
let testTab = tabs[0];
|
||||||
|
|
||||||
let state = testTab.sharingState;
|
let state = testTab.sharingState.webRTC;
|
||||||
browser.test.assertTrue(state.camera, "sharing camera was turned on");
|
browser.test.assertTrue(state.camera, "sharing camera was turned on");
|
||||||
browser.test.assertTrue(state.microphone, "sharing mic was turned on");
|
browser.test.assertTrue(state.microphone, "sharing mic was turned on");
|
||||||
browser.test.assertEq(state.screen, "Window", "sharing screen is window");
|
browser.test.assertEq(state.screen, "Window", "sharing screen is window");
|
||||||
|
@ -51,7 +53,7 @@ add_task(async function test_tabs_mediaIndicators() {
|
||||||
if (testTab.id !== tabId) {
|
if (testTab.id !== tabId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let state = tab.sharingState;
|
let state = tab.sharingState.webRTC;
|
||||||
browser.test.assertFalse(state.camera, "sharing camera was turned off");
|
browser.test.assertFalse(state.camera, "sharing camera was turned off");
|
||||||
browser.test.assertFalse(state.microphone, "sharing mic was turned off");
|
browser.test.assertFalse(state.microphone, "sharing mic was turned off");
|
||||||
browser.test.assertFalse(state.screen, "sharing screen was turned off");
|
browser.test.assertFalse(state.screen, "sharing screen was turned off");
|
||||||
|
@ -71,7 +73,7 @@ add_task(async function test_tabs_mediaIndicators() {
|
||||||
// Test that onUpdated is called after the sharing state is changed from
|
// Test that onUpdated is called after the sharing state is changed from
|
||||||
// chrome code.
|
// chrome code.
|
||||||
await extension.awaitMessage("ready");
|
await extension.awaitMessage("ready");
|
||||||
gBrowser.setBrowserSharing(tab.linkedBrowser, {});
|
gBrowser.resetBrowserSharing(tab.linkedBrowser);
|
||||||
|
|
||||||
await extension.awaitFinish("done");
|
await extension.awaitFinish("done");
|
||||||
await extension.unload();
|
await extension.unload();
|
||||||
|
|
|
@ -284,6 +284,9 @@ popupShowPopupPrefix=Show ‘%S’
|
||||||
# #1 is the number of pop-ups blocked.
|
# #1 is the number of pop-ups blocked.
|
||||||
popupShowBlockedPopupsIndicatorText=Show #1 blocked pop-up…;Show #1 blocked pop-ups…
|
popupShowBlockedPopupsIndicatorText=Show #1 blocked pop-up…;Show #1 blocked pop-ups…
|
||||||
|
|
||||||
|
# LOCALIZATION NOTE (geolocationLastAccessIndicatorText): %S is the relative time of the most recent geolocation access (e.g. 5 min. ago)
|
||||||
|
geolocationLastAccessIndicatorText=Last access %S
|
||||||
|
|
||||||
# Bad Content Blocker Doorhanger Notification
|
# Bad Content Blocker Doorhanger Notification
|
||||||
# %S is brandShortName
|
# %S is brandShortName
|
||||||
badContentBlocked.blocked.message=%S is blocking content on this page.
|
badContentBlocked.blocked.message=%S is blocking content on this page.
|
||||||
|
|
|
@ -94,6 +94,13 @@ XPCOMUtils.defineLazyServiceGetter(
|
||||||
"nsIIDNService"
|
"nsIIDNService"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
XPCOMUtils.defineLazyServiceGetter(
|
||||||
|
this,
|
||||||
|
"ContentPrefService2",
|
||||||
|
"@mozilla.org/content-pref/service;1",
|
||||||
|
"nsIContentPrefService2"
|
||||||
|
);
|
||||||
|
|
||||||
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
|
XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
|
||||||
return Services.strings.createBundle(
|
return Services.strings.createBundle(
|
||||||
"chrome://browser/locale/browser.properties"
|
"chrome://browser/locale/browser.properties"
|
||||||
|
@ -809,6 +816,39 @@ GeolocationPermissionPrompt.prototype = {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_updateGeoSharing(state) {
|
||||||
|
let gBrowser = this.browser.ownerGlobal.gBrowser;
|
||||||
|
gBrowser.updateBrowserSharing(this.browser, { geo: state });
|
||||||
|
if (!state) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let host;
|
||||||
|
try {
|
||||||
|
host = this.browser.currentURI.host;
|
||||||
|
} catch (e) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (host == null || host == "") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ContentPrefService2.set(
|
||||||
|
this.browser.currentURI.host,
|
||||||
|
"permissions.geoLocation.lastAccess",
|
||||||
|
new Date().toString(),
|
||||||
|
this.browser.loadContext
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
allow(...args) {
|
||||||
|
this._updateGeoSharing(true);
|
||||||
|
PermissionPromptForRequestPrototype.allow.apply(this, args);
|
||||||
|
},
|
||||||
|
|
||||||
|
cancel(...args) {
|
||||||
|
this._updateGeoSharing(false);
|
||||||
|
PermissionPromptForRequestPrototype.cancel.apply(this, args);
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
PermissionUI.GeolocationPermissionPrompt = GeolocationPermissionPrompt;
|
PermissionUI.GeolocationPermissionPrompt = GeolocationPermissionPrompt;
|
||||||
|
|
|
@ -336,7 +336,9 @@ var webrtcUI = {
|
||||||
}
|
}
|
||||||
let tabbrowser = aMessage.target.ownerGlobal.gBrowser;
|
let tabbrowser = aMessage.target.ownerGlobal.gBrowser;
|
||||||
if (tabbrowser) {
|
if (tabbrowser) {
|
||||||
tabbrowser.setBrowserSharing(aMessage.target, aMessage.data);
|
tabbrowser.updateBrowserSharing(aMessage.target, {
|
||||||
|
webRTC: aMessage.data,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "child-process-shutdown":
|
case "child-process-shutdown":
|
||||||
|
|
|
@ -105,7 +105,7 @@
|
||||||
border-image-slice: 1;
|
border-image-slice: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sharing-icon,
|
.sharing-icon,
|
||||||
#identity-icon,
|
#identity-icon,
|
||||||
#tracking-protection-icon,
|
#tracking-protection-icon,
|
||||||
.notification-anchor-icon,
|
.notification-anchor-icon,
|
||||||
|
@ -167,23 +167,27 @@
|
||||||
|
|
||||||
/* SHARING ICON */
|
/* SHARING ICON */
|
||||||
|
|
||||||
#identity-box[sharing="camera"] > #sharing-icon {
|
#webrtc-sharing-icon[sharing="camera"] {
|
||||||
list-style-image: url("chrome://browser/skin/notification-icons/camera.svg");
|
list-style-image: url("chrome://browser/skin/notification-icons/camera.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
#identity-box[sharing="microphone"] > #sharing-icon {
|
#webrtc-sharing-icon[sharing="microphone"] {
|
||||||
list-style-image: url("chrome://browser/skin/notification-icons/microphone.svg");
|
list-style-image: url("chrome://browser/skin/notification-icons/microphone.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
#identity-box[sharing="screen"] > #sharing-icon {
|
#webrtc-sharing-icon[sharing="screen"] {
|
||||||
list-style-image: url("chrome://browser/skin/notification-icons/screen.svg");
|
list-style-image: url("chrome://browser/skin/notification-icons/screen.svg");
|
||||||
}
|
}
|
||||||
|
|
||||||
#identity-box:not([sharing]) > #sharing-icon {
|
#geo-sharing-icon[sharing] {
|
||||||
|
list-style-image: url("chrome://browser/skin/notification-icons/geo.svg");
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharing-icon:not([sharing]) {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
#identity-box[sharing]:not([paused]) > #sharing-icon {
|
#webrtc-sharing-icon[sharing]:not([paused]) {
|
||||||
animation: 1.5s ease in-use-blink infinite;
|
animation: 1.5s ease in-use-blink infinite;
|
||||||
-moz-context-properties: fill;
|
-moz-context-properties: fill;
|
||||||
fill: rgb(224, 41, 29);
|
fill: rgb(224, 41, 29);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче