From a1be17c1cea81ebb1e8b131a662c698d78f3f7f2 Mon Sep 17 00:00:00 2001 From: wolfbeast Date: Mon, 4 Jun 2018 13:17:38 +0200 Subject: Issue #303 Part 1: Move basilisk files from /browser to /application/basilisk --- browser/modules/AboutHome.jsm | 175 ---- browser/modules/AboutNewTab.jsm | 43 - browser/modules/AttributionCode.jsm | 123 --- browser/modules/BrowserUITelemetry.jsm | 888 ------------------ browser/modules/BrowserUsageTelemetry.jsm | 468 ---------- browser/modules/CastingApps.jsm | 164 ---- browser/modules/ContentClick.jsm | 98 -- browser/modules/ContentCrashHandlers.jsm | 922 ------------------- browser/modules/ContentLinkHandler.jsm | 147 --- browser/modules/ContentObservers.jsm | 55 -- browser/modules/ContentSearch.jsm | 566 ------------ browser/modules/ContentWebRTC.jsm | 393 -------- browser/modules/DirectoryLinksProvider.jsm | 1255 -------------------------- browser/modules/E10SUtils.jsm | 128 --- browser/modules/Feeds.jsm | 104 --- browser/modules/FormSubmitObserver.jsm | 235 ----- browser/modules/FormValidationHandler.jsm | 157 ---- browser/modules/HiddenFrame.jsm | 86 -- browser/modules/LaterRun.jsm | 172 ---- browser/modules/NetworkPrioritizer.jsm | 194 ---- browser/modules/PermissionUI.jsm | 595 ------------ browser/modules/PluginContent.jsm | 1132 ----------------------- browser/modules/ProcessHangMonitor.jsm | 397 -------- browser/modules/ReaderParent.jsm | 102 --- browser/modules/RecentWindow.jsm | 67 -- browser/modules/RemotePrompt.jsm | 110 --- browser/modules/Sanitizer.jsm | 22 - browser/modules/SitePermissions.jsm | 269 ------ browser/modules/TransientPrefs.jsm | 24 - browser/modules/URLBarZoom.jsm | 51 -- browser/modules/Windows8WindowFrameColor.jsm | 53 -- browser/modules/WindowsJumpLists.jsm | 579 ------------ browser/modules/WindowsPreviewPerTab.jsm | 862 ------------------ browser/modules/moz.build | 47 - browser/modules/offlineAppCache.jsm | 20 - browser/modules/webrtcUI.jsm | 969 -------------------- 36 files changed, 11672 deletions(-) delete mode 100644 browser/modules/AboutHome.jsm delete mode 100644 browser/modules/AboutNewTab.jsm delete mode 100644 browser/modules/AttributionCode.jsm delete mode 100644 browser/modules/BrowserUITelemetry.jsm delete mode 100644 browser/modules/BrowserUsageTelemetry.jsm delete mode 100644 browser/modules/CastingApps.jsm delete mode 100644 browser/modules/ContentClick.jsm delete mode 100644 browser/modules/ContentCrashHandlers.jsm delete mode 100644 browser/modules/ContentLinkHandler.jsm delete mode 100644 browser/modules/ContentObservers.jsm delete mode 100644 browser/modules/ContentSearch.jsm delete mode 100644 browser/modules/ContentWebRTC.jsm delete mode 100644 browser/modules/DirectoryLinksProvider.jsm delete mode 100644 browser/modules/E10SUtils.jsm delete mode 100644 browser/modules/Feeds.jsm delete mode 100644 browser/modules/FormSubmitObserver.jsm delete mode 100644 browser/modules/FormValidationHandler.jsm delete mode 100644 browser/modules/HiddenFrame.jsm delete mode 100644 browser/modules/LaterRun.jsm delete mode 100644 browser/modules/NetworkPrioritizer.jsm delete mode 100644 browser/modules/PermissionUI.jsm delete mode 100644 browser/modules/PluginContent.jsm delete mode 100644 browser/modules/ProcessHangMonitor.jsm delete mode 100644 browser/modules/ReaderParent.jsm delete mode 100644 browser/modules/RecentWindow.jsm delete mode 100644 browser/modules/RemotePrompt.jsm delete mode 100644 browser/modules/Sanitizer.jsm delete mode 100644 browser/modules/SitePermissions.jsm delete mode 100644 browser/modules/TransientPrefs.jsm delete mode 100644 browser/modules/URLBarZoom.jsm delete mode 100644 browser/modules/Windows8WindowFrameColor.jsm delete mode 100644 browser/modules/WindowsJumpLists.jsm delete mode 100644 browser/modules/WindowsPreviewPerTab.jsm delete mode 100644 browser/modules/moz.build delete mode 100644 browser/modules/offlineAppCache.jsm delete mode 100644 browser/modules/webrtcUI.jsm (limited to 'browser/modules') diff --git a/browser/modules/AboutHome.jsm b/browser/modules/AboutHome.jsm deleted file mode 100644 index 639194c20..000000000 --- a/browser/modules/AboutHome.jsm +++ /dev/null @@ -1,175 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; - -this.EXPORTED_SYMBOLS = [ "AboutHomeUtils", "AboutHome" ]; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", - "resource://gre/modules/AppConstants.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "AutoMigrate", - "resource:///modules/AutoMigrate.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts", - "resource://gre/modules/FxAccounts.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "Promise", - "resource://gre/modules/Promise.jsm"); - -// Should be bumped up if any data content format changes. -const STARTPAGE_VERSION = 5; - -this.AboutHomeUtils = { - /* - * showKnowYourRights - Determines if the user should be shown the - * about:rights notification. The notification should *not* be shown if - * we've already shown the current version, or if the override pref says to - * never show it. The notification *should* be shown if it's never been seen - * before, if a newer version is available, or if the override pref says to - * always show it. - */ - get showKnowYourRights() { - // Look for an unconditional override pref. If set, do what it says. - // (true --> never show, false --> always show) - try { - return !Services.prefs.getBoolPref("browser.rights.override"); - } catch (e) { } - // Ditto, for the legacy EULA pref. - try { - return !Services.prefs.getBoolPref("browser.EULA.override"); - } catch (e) { } - - if (!AppConstants.MC_OFFICIAL) { - // Non-official builds shouldn't show the notification. - return false; - } - - // Look to see if the user has seen the current version or not. - var currentVersion = Services.prefs.getIntPref("browser.rights.version"); - try { - return !Services.prefs.getBoolPref("browser.rights." + currentVersion + ".shown"); - } catch (e) { } - - // Legacy: If the user accepted a EULA, we won't annoy them with the - // equivalent about:rights page until the version changes. - try { - return !Services.prefs.getBoolPref("browser.EULA." + currentVersion + ".accepted"); - } catch (e) { } - - // We haven't shown the notification before, so do so now. - return true; - } -}; - -/** - * This code provides services to the about:home page. Whenever - * about:home needs to do something chrome-privileged, it sends a - * message that's handled here. - */ -var AboutHome = { - MESSAGES: [ - "AboutHome:RestorePreviousSession", - "AboutHome:Downloads", - "AboutHome:Bookmarks", - "AboutHome:History", - "AboutHome:Addons", - "AboutHome:Sync", - "AboutHome:Settings", - "AboutHome:RequestUpdate", - "AboutHome:MaybeShowAutoMigrationUndoNotification", - ], - - init: function() { - let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); - - for (let msg of this.MESSAGES) { - mm.addMessageListener(msg, this); - } - }, - - receiveMessage: function(aMessage) { - let window = aMessage.target.ownerGlobal; - - switch (aMessage.name) { - case "AboutHome:RestorePreviousSession": - let ss = Cc["@mozilla.org/browser/sessionstore;1"]. - getService(Ci.nsISessionStore); - if (ss.canRestoreLastSession) { - ss.restoreLastSession(); - } - break; - - case "AboutHome:Downloads": - window.BrowserDownloadsUI(); - break; - - case "AboutHome:Bookmarks": - window.PlacesCommandHook.showPlacesOrganizer("UnfiledBookmarks"); - break; - - case "AboutHome:History": - window.PlacesCommandHook.showPlacesOrganizer("History"); - break; - - case "AboutHome:Addons": - window.BrowserOpenAddonsMgr(); - break; - - case "AboutHome:Sync": - window.openPreferences("paneSync", { urlParams: { entrypoint: "abouthome" } }); - break; - - case "AboutHome:Settings": - window.openPreferences(); - break; - - case "AboutHome:RequestUpdate": - this.sendAboutHomeData(aMessage.target); - break; - - case "AboutHome:MaybeShowAutoMigrationUndoNotification": - AutoMigrate.maybeShowUndoNotification(aMessage.target); - break; - } - }, - - // Send all the chrome-privileged data needed by about:home. This - // gets re-sent when the search engine changes. - sendAboutHomeData: function(target) { - let wrapper = {}; - Components.utils.import("resource:///modules/sessionstore/SessionStore.jsm", - wrapper); - let ss = wrapper.SessionStore; - - ss.promiseInitialized.then(function() { - let data = { - showRestoreLastSession: ss.canRestoreLastSession, - showKnowYourRights: AboutHomeUtils.showKnowYourRights - }; - - if (AboutHomeUtils.showKnowYourRights) { - // Set pref to indicate we've shown the notification. - let currentVersion = Services.prefs.getIntPref("browser.rights.version"); - Services.prefs.setBoolPref("browser.rights." + currentVersion + ".shown", true); - } - - if (target && target.messageManager) { - target.messageManager.sendAsyncMessage("AboutHome:Update", data); - } else { - let mm = Cc["@mozilla.org/globalmessagemanager;1"].getService(Ci.nsIMessageListenerManager); - mm.broadcastAsyncMessage("AboutHome:Update", data); - } - }).then(null, function onError(x) { - Cu.reportError("Error in AboutHome.sendAboutHomeData: " + x); - }); - }, - -}; diff --git a/browser/modules/AboutNewTab.jsm b/browser/modules/AboutNewTab.jsm deleted file mode 100644 index 4337c5a2d..000000000 --- a/browser/modules/AboutNewTab.jsm +++ /dev/null @@ -1,43 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cu = Components.utils; - -this.EXPORTED_SYMBOLS = [ "AboutNewTab" ]; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "AutoMigrate", - "resource:///modules/AutoMigrate.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "NewTabUtils", - "resource://gre/modules/NewTabUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "RemotePages", - "resource://gre/modules/RemotePageManager.jsm"); - -var AboutNewTab = { - - pageListener: null, - - init: function() { - this.pageListener = new RemotePages("about:newtab"); - this.pageListener.addMessageListener("NewTab:Customize", this.customize.bind(this)); - this.pageListener.addMessageListener("NewTab:MaybeShowAutoMigrationUndoNotification", - (msg) => AutoMigrate.maybeShowUndoNotification(msg.target.browser)); - }, - - customize: function(message) { - NewTabUtils.allPages.enabled = message.data.enabled; - NewTabUtils.allPages.enhanced = message.data.enhanced; - }, - - uninit: function() { - this.pageListener.destroy(); - this.pageListener = null; - }, -}; diff --git a/browser/modules/AttributionCode.jsm b/browser/modules/AttributionCode.jsm deleted file mode 100644 index dc42b2be4..000000000 --- a/browser/modules/AttributionCode.jsm +++ /dev/null @@ -1,123 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; - -this.EXPORTED_SYMBOLS = ["AttributionCode"]; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, 'AppConstants', - 'resource://gre/modules/AppConstants.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, 'OS', - 'resource://gre/modules/osfile.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, 'Services', - 'resource://gre/modules/Services.jsm'); -XPCOMUtils.defineLazyModuleGetter(this, 'Task', - 'resource://gre/modules/Task.jsm'); - -const ATTR_CODE_MAX_LENGTH = 200; -const ATTR_CODE_KEYS_REGEX = /^source|medium|campaign|content$/; -const ATTR_CODE_VALUE_REGEX = /[a-zA-Z0-9_%\\-\\.\\(\\)]*/; -const ATTR_CODE_FIELD_SEPARATOR = "%26"; // URL-encoded & -const ATTR_CODE_KEY_VALUE_SEPARATOR = "%3D"; // URL-encoded = - -let gCachedAttrData = null; - -/** - * Returns an nsIFile for the file containing the attribution data. - */ -function getAttributionFile() { - let file = Services.dirsvc.get("LocalAppData", Ci.nsIFile); - // appinfo does not exist in xpcshell, so we need defaults. - file.append(Services.appinfo.vendor || "mozilla"); - file.append(AppConstants.MOZ_APP_NAME); - file.append("postSigningData"); - return file; -} - -/** - * Returns an object containing a key-value pair for each piece of attribution - * data included in the passed-in attribution code string. - * If the string isn't a valid attribution code, returns an empty object. - */ -function parseAttributionCode(code) { - if (code.length > ATTR_CODE_MAX_LENGTH) { - return {}; - } - - let isValid = true; - let parsed = {}; - for (let param of code.split(ATTR_CODE_FIELD_SEPARATOR)) { - let [key, value] = param.split(ATTR_CODE_KEY_VALUE_SEPARATOR, 2); - if (key && ATTR_CODE_KEYS_REGEX.test(key)) { - if (value && ATTR_CODE_VALUE_REGEX.test(value)) { - parsed[key] = value; - } - } else { - isValid = false; - break; - } - } - return isValid ? parsed : {}; -} - -var AttributionCode = { - /** - * Reads the attribution code, either from disk or a cached version. - * Returns a promise that fulfills with an object containing the parsed - * attribution data if the code could be read and is valid, - * or an empty object otherwise. - */ - getAttrDataAsync() { - return Task.spawn(function*() { - if (gCachedAttrData != null) { - return gCachedAttrData; - } - - let code = ""; - try { - let bytes = yield OS.File.read(getAttributionFile().path); - let decoder = new TextDecoder(); - code = decoder.decode(bytes); - } catch (ex) { - // The attribution file may already have been deleted, - // or it may have never been installed at all; - // failure to open or read it isn't an error. - } - - gCachedAttrData = parseAttributionCode(code); - return gCachedAttrData; - }); - }, - - /** - * Deletes the attribution data file. - * Returns a promise that resolves when the file is deleted, - * or if the file couldn't be deleted (the promise is never rejected). - */ - deleteFileAsync() { - return Task.spawn(function*() { - try { - yield OS.File.remove(getAttributionFile().path); - } catch (ex) { - // The attribution file may already have been deleted, - // or it may have never been installed at all; - // failure to delete it isn't an error. - } - }); - }, - - /** - * Clears the cached attribution code value, if any. - * Does nothing if called from outside of an xpcshell test. - */ - _clearCache() { - let env = Cc["@mozilla.org/process/environment;1"] - .getService(Ci.nsIEnvironment); - if (env.exists("XPCSHELL_TEST_PROFILE_DIR")) { - gCachedAttrData = null; - } - }, -}; diff --git a/browser/modules/BrowserUITelemetry.jsm b/browser/modules/BrowserUITelemetry.jsm deleted file mode 100644 index 2b7cc8c20..000000000 --- a/browser/modules/BrowserUITelemetry.jsm +++ /dev/null @@ -1,888 +0,0 @@ -// This Source Code Form is subject to the terms of the Mozilla Public -// License, v. 2.0. If a copy of the MPL was not distributed with this -// file, You can obtain one at http://mozilla.org/MPL/2.0/. - -"use strict"; - -this.EXPORTED_SYMBOLS = ["BrowserUITelemetry"]; - -const {interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry", - "resource://gre/modules/UITelemetry.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", - "resource:///modules/RecentWindow.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "CustomizableUI", - "resource:///modules/CustomizableUI.jsm"); -XPCOMUtils.defineLazyGetter(this, "Timer", function() { - let timer = {}; - Cu.import("resource://gre/modules/Timer.jsm", timer); - return timer; -}); - -const MS_SECOND = 1000; -const MS_MINUTE = MS_SECOND * 60; -const MS_HOUR = MS_MINUTE * 60; - -XPCOMUtils.defineLazyGetter(this, "DEFAULT_AREA_PLACEMENTS", function() { - let result = { - "PanelUI-contents": [ - "edit-controls", - "zoom-controls", - "new-window-button", - "privatebrowsing-button", - "save-page-button", - "print-button", - "history-panelmenu", - "fullscreen-button", - "find-button", - "preferences-button", - "add-ons-button", - "sync-button", - "developer-button", - ], - "nav-bar": [ - "urlbar-container", - "search-container", - "bookmarks-menu-button", - "pocket-button", - "downloads-button", - "home-button", - ], - // It's true that toolbar-menubar is not visible - // on OS X, but the XUL node is definitely present - // in the document. - "toolbar-menubar": [ - "menubar-items", - ], - "TabsToolbar": [ - "tabbrowser-tabs", - "new-tab-button", - "alltabs-button", - ], - "PersonalToolbar": [ - "personal-bookmarks", - ], - }; - - let showCharacterEncoding = Services.prefs.getComplexValue( - "browser.menu.showCharacterEncoding", - Ci.nsIPrefLocalizedString - ).data; - if (showCharacterEncoding == "true") { - result["PanelUI-contents"].push("characterencoding-button"); - } - - return result; -}); - -XPCOMUtils.defineLazyGetter(this, "DEFAULT_AREAS", function() { - return Object.keys(DEFAULT_AREA_PLACEMENTS); -}); - -XPCOMUtils.defineLazyGetter(this, "PALETTE_ITEMS", function() { - let result = [ - "open-file-button", - "developer-button", - "feed-button", - "email-link-button", - "containers-panelmenu", - ]; - - let panelPlacements = DEFAULT_AREA_PLACEMENTS["PanelUI-contents"]; - if (panelPlacements.indexOf("characterencoding-button") == -1) { - result.push("characterencoding-button"); - } - - if (Services.prefs.getBoolPref("privacy.panicButton.enabled")) { - result.push("panic-button"); - } - - return result; -}); - -XPCOMUtils.defineLazyGetter(this, "DEFAULT_ITEMS", function() { - let result = []; - for (let [, buttons] of Object.entries(DEFAULT_AREA_PLACEMENTS)) { - result = result.concat(buttons); - } - return result; -}); - -XPCOMUtils.defineLazyGetter(this, "ALL_BUILTIN_ITEMS", function() { - // These special cases are for click events on built-in items that are - // contained within customizable items (like the navigation widget). - const SPECIAL_CASES = [ - "back-button", - "forward-button", - "urlbar-stop-button", - "urlbar-go-button", - "urlbar-reload-button", - "searchbar", - "cut-button", - "copy-button", - "paste-button", - "zoom-out-button", - "zoom-reset-button", - "zoom-in-button", - "BMB_bookmarksPopup", - "BMB_unsortedBookmarksPopup", - "BMB_bookmarksToolbarPopup", - "search-go-button", - "soundplaying-icon", - ] - return DEFAULT_ITEMS.concat(PALETTE_ITEMS) - .concat(SPECIAL_CASES); -}); - -const OTHER_MOUSEUP_MONITORED_ITEMS = [ - "PlacesChevron", - "PlacesToolbarItems", - "menubar-items", -]; - -// Items that open arrow panels will often be overlapped by -// the panel that they're opening by the time the mouseup -// event is fired, so for these items, we monitor mousedown. -const MOUSEDOWN_MONITORED_ITEMS = [ - "PanelUI-menu-button", -]; - -// Weakly maps browser windows to objects whose keys are relative -// timestamps for when some kind of session started. For example, -// when a customization session started. That way, when the window -// exits customization mode, we can determine how long the session -// lasted. -const WINDOW_DURATION_MAP = new WeakMap(); - -// Default bucket name, when no other bucket is active. -const BUCKET_DEFAULT = "__DEFAULT__"; -// Bucket prefix, for named buckets. -const BUCKET_PREFIX = "bucket_"; -// Standard separator to use between different parts of a bucket name, such -// as primary name and the time step string. -const BUCKET_SEPARATOR = "|"; - -this.BrowserUITelemetry = { - init: function() { - UITelemetry.addSimpleMeasureFunction("toolbars", - this.getToolbarMeasures.bind(this)); - UITelemetry.addSimpleMeasureFunction("contextmenu", - this.getContextMenuInfo.bind(this)); - UITelemetry.addSimpleMeasureFunction("syncstate", - this.getSyncState.bind(this)); - - Services.obs.addObserver(this, "sessionstore-windows-restored", false); - Services.obs.addObserver(this, "browser-delayed-startup-finished", false); - Services.obs.addObserver(this, "autocomplete-did-enter-text", false); - CustomizableUI.addListener(this); - }, - - observe: function(aSubject, aTopic, aData) { - switch (aTopic) { - case "sessionstore-windows-restored": - this._gatherFirstWindowMeasurements(); - break; - case "browser-delayed-startup-finished": - this._registerWindow(aSubject); - break; - case "autocomplete-did-enter-text": - let input = aSubject.QueryInterface(Ci.nsIAutoCompleteInput); - if (input && input.id == "urlbar" && !input.inPrivateContext && - input.popup.selectedIndex != -1) { - this._logAwesomeBarSearchResult(input.textValue); - } - break; - } - }, - - /** - * For the _countableEvents object, constructs a chain of - * Javascript Objects with the keys in aKeys, with the final - * key getting the value in aEndWith. If the final key already - * exists in the final object, its value is not set. In either - * case, a reference to the second last object in the chain is - * returned. - * - * Example - suppose I want to store: - * _countableEvents: { - * a: { - * b: { - * c: 0 - * } - * } - * } - * - * And then increment the "c" value by 1, you could call this - * function like this: - * - * let example = this._ensureObjectChain([a, b, c], 0); - * example["c"]++; - * - * Subsequent repetitions of these last two lines would - * simply result in the c value being incremented again - * and again. - * - * @param aKeys the Array of keys to chain Objects together with. - * @param aEndWith the value to assign to the last key. - * @param aRoot the root object onto which we create/get the object chain - * designated by aKeys. - * @returns a reference to the second last object in the chain - - * so in our example, that'd be "b". - */ - _ensureObjectChain: function(aKeys, aEndWith, aRoot) { - let current = aRoot; - let parent = null; - aKeys.unshift(this._bucket); - for (let [i, key] of aKeys.entries()) { - if (!(key in current)) { - if (i == aKeys.length - 1) { - current[key] = aEndWith; - } else { - current[key] = {}; - } - } - parent = current; - current = current[key]; - } - return parent; - }, - - _countableEvents: {}, - _countEvent: function(aKeyArray, root=this._countableEvents) { - let countObject = this._ensureObjectChain(aKeyArray, 0, root); - let lastItemKey = aKeyArray[aKeyArray.length - 1]; - countObject[lastItemKey]++; - }, - - _countMouseUpEvent: function(aCategory, aAction, aButton) { - const BUTTONS = ["left", "middle", "right"]; - let buttonKey = BUTTONS[aButton]; - if (buttonKey) { - this._countEvent([aCategory, aAction, buttonKey]); - } - }, - - _firstWindowMeasurements: null, - _gatherFirstWindowMeasurements: function() { - // We'll gather measurements as soon as the session has restored. - // We do this here instead of waiting for UITelemetry to ask for - // our measurements because at that point all browser windows have - // probably been closed, since the vast majority of saved-session - // pings are gathered during shutdown. - let win = RecentWindow.getMostRecentBrowserWindow({ - private: false, - allowPopups: false, - }); - - Services.search.init(rv => { - // If there are no such windows (or we've just about found one - // but it's closed already), we're out of luck. :( - let hasWindow = win && !win.closed; - this._firstWindowMeasurements = hasWindow ? this._getWindowMeasurements(win, rv) - : {}; - }); - }, - - _registerWindow: function(aWindow) { - aWindow.addEventListener("unload", this); - let document = aWindow.document; - - for (let areaID of CustomizableUI.areas) { - let areaNode = document.getElementById(areaID); - if (areaNode) { - (areaNode.customizationTarget || areaNode).addEventListener("mouseup", this); - } - } - - for (let itemID of OTHER_MOUSEUP_MONITORED_ITEMS) { - let item = document.getElementById(itemID); - if (item) { - item.addEventListener("mouseup", this); - } - } - - for (let itemID of MOUSEDOWN_MONITORED_ITEMS) { - let item = document.getElementById(itemID); - if (item) { - item.addEventListener("mousedown", this); - } - } - - WINDOW_DURATION_MAP.set(aWindow, {}); - }, - - _unregisterWindow: function(aWindow) { - aWindow.removeEventListener("unload", this); - let document = aWindow.document; - - for (let areaID of CustomizableUI.areas) { - let areaNode = document.getElementById(areaID); - if (areaNode) { - (areaNode.customizationTarget || areaNode).removeEventListener("mouseup", this); - } - } - - for (let itemID of OTHER_MOUSEUP_MONITORED_ITEMS) { - let item = document.getElementById(itemID); - if (item) { - item.removeEventListener("mouseup", this); - } - } - - for (let itemID of MOUSEDOWN_MONITORED_ITEMS) { - let item = document.getElementById(itemID); - if (item) { - item.removeEventListener("mousedown", this); - } - } - }, - - handleEvent: function(aEvent) { - switch (aEvent.type) { - case "unload": - this._unregisterWindow(aEvent.currentTarget); - break; - case "mouseup": - this._handleMouseUp(aEvent); - break; - case "mousedown": - this._handleMouseDown(aEvent); - break; - } - }, - - _handleMouseUp: function(aEvent) { - let targetID = aEvent.currentTarget.id; - - switch (targetID) { - case "PlacesToolbarItems": - this._PlacesToolbarItemsMouseUp(aEvent); - break; - case "PlacesChevron": - this._PlacesChevronMouseUp(aEvent); - break; - case "menubar-items": - this._menubarMouseUp(aEvent); - break; - default: - this._checkForBuiltinItem(aEvent); - } - }, - - _handleMouseDown: function(aEvent) { - if (aEvent.currentTarget.id == "PanelUI-menu-button") { - // _countMouseUpEvent expects a detail for the second argument, - // but we don't really have any details to give. Just passing in - // "button" is probably simpler than trying to modify - // _countMouseUpEvent for this particular case. - this._countMouseUpEvent("click-menu-button", "button", aEvent.button); - } - }, - - _PlacesChevronMouseUp: function(aEvent) { - let target = aEvent.originalTarget; - let result = target.id == "PlacesChevron" ? "chevron" : "overflowed-item"; - this._countMouseUpEvent("click-bookmarks-bar", result, aEvent.button); - }, - - _PlacesToolbarItemsMouseUp: function(aEvent) { - let target = aEvent.originalTarget; - // If this isn't a bookmark-item, we don't care about it. - if (!target.classList.contains("bookmark-item")) { - return; - } - - let result = target.hasAttribute("container") ? "container" : "item"; - this._countMouseUpEvent("click-bookmarks-bar", result, aEvent.button); - }, - - _menubarMouseUp: function(aEvent) { - let target = aEvent.originalTarget; - let tag = target.localName - let result = (tag == "menu" || tag == "menuitem") ? tag : "other"; - this._countMouseUpEvent("click-menubar", result, aEvent.button); - }, - - _bookmarksMenuButtonMouseUp: function(aEvent) { - let bookmarksWidget = CustomizableUI.getWidget("bookmarks-menu-button"); - if (bookmarksWidget.areaType == CustomizableUI.TYPE_MENU_PANEL) { - // In the menu panel, only the star is visible, and that opens up the - // bookmarks subview. - this._countMouseUpEvent("click-bookmarks-menu-button", "in-panel", - aEvent.button); - } else { - let clickedItem = aEvent.originalTarget; - // Did we click on the star, or the dropmarker? The star - // has an anonid of "button". If we don't find that, we'll - // assume we clicked on the dropmarker. - let action = "menu"; - if (clickedItem.getAttribute("anonid") == "button") { - // We clicked on the star - now we just need to record - // whether or not we're adding a bookmark or editing an - // existing one. - let bookmarksMenuNode = - bookmarksWidget.forWindow(aEvent.target.ownerGlobal).node; - action = bookmarksMenuNode.hasAttribute("starred") ? "edit" : "add"; - } - this._countMouseUpEvent("click-bookmarks-menu-button", action, - aEvent.button); - } - }, - - _checkForBuiltinItem: function(aEvent) { - let item = aEvent.originalTarget; - - // We don't want to count clicks on the private browsing - // button for privacy reasons. See bug 1176391. - if (item.id == "privatebrowsing-button") { - return; - } - - // We special-case the bookmarks-menu-button, since we want to - // monitor more than just clicks on it. - if (item.id == "bookmarks-menu-button" || - getIDBasedOnFirstIDedAncestor(item) == "bookmarks-menu-button") { - this._bookmarksMenuButtonMouseUp(aEvent); - return; - } - - // Perhaps we're seeing one of the default toolbar items - // being clicked. - if (ALL_BUILTIN_ITEMS.indexOf(item.id) != -1) { - // Base case - we clicked directly on one of our built-in items, - // and we can go ahead and register that click. - this._countMouseUpEvent("click-builtin-item", item.id, aEvent.button); - return; - } - - // If not, we need to check if the item's anonid is in our list - // of built-in items to check. - if (ALL_BUILTIN_ITEMS.indexOf(item.getAttribute("anonid")) != -1) { - this._countMouseUpEvent("click-builtin-item", item.getAttribute("anonid"), aEvent.button); - return; - } - - // If not, we need to check if one of the ancestors of the clicked - // item is in our list of built-in items to check. - let candidate = getIDBasedOnFirstIDedAncestor(item); - if (ALL_BUILTIN_ITEMS.indexOf(candidate) != -1) { - this._countMouseUpEvent("click-builtin-item", candidate, aEvent.button); - } - }, - - _getWindowMeasurements: function(aWindow, searchResult) { - let document = aWindow.document; - let result = {}; - - // Determine if the window is in the maximized, normal or - // fullscreen state. - result.sizemode = document.documentElement.getAttribute("sizemode"); - - // Determine if the Bookmarks bar is currently visible - let bookmarksBar = document.getElementById("PersonalToolbar"); - result.bookmarksBarEnabled = bookmarksBar && !bookmarksBar.collapsed; - - // Determine if the menubar is currently visible. On OS X, the menubar - // is never shown, despite not having the collapsed attribute set. - let menuBar = document.getElementById("toolbar-menubar"); - result.menuBarEnabled = - menuBar && Services.appinfo.OS != "Darwin" - && menuBar.getAttribute("autohide") != "true"; - - // Determine if the titlebar is currently visible. - result.titleBarEnabled = !Services.prefs.getBoolPref("browser.tabs.drawInTitlebar"); - - // Examine all customizable areas and see what default items - // are present and missing. - let defaultKept = []; - let defaultMoved = []; - let nondefaultAdded = []; - - for (let areaID of CustomizableUI.areas) { - let items = CustomizableUI.getWidgetIdsInArea(areaID); - for (let item of items) { - // Is this a default item? - if (DEFAULT_ITEMS.indexOf(item) != -1) { - // Ok, it's a default item - but is it in its default - // toolbar? We use Array.isArray instead of checking for - // toolbarID in DEFAULT_AREA_PLACEMENTS because an add-on might - // be clever and give itself the id of "toString" or something. - if (Array.isArray(DEFAULT_AREA_PLACEMENTS[areaID]) && - DEFAULT_AREA_PLACEMENTS[areaID].indexOf(item) != -1) { - // The item is in its default toolbar - defaultKept.push(item); - } else { - defaultMoved.push(item); - } - } else if (PALETTE_ITEMS.indexOf(item) != -1) { - // It's a palette item that's been moved into a toolbar - nondefaultAdded.push(item); - } - // else, it's provided by an add-on, and we won't record it. - } - } - - // Now go through the items in the palette to see what default - // items are in there. - let paletteItems = - CustomizableUI.getUnusedWidgets(aWindow.gNavToolbox.palette); - let defaultRemoved = []; - for (let item of paletteItems) { - if (DEFAULT_ITEMS.indexOf(item.id) != -1) { - defaultRemoved.push(item.id); - } - } - - result.defaultKept = defaultKept; - result.defaultMoved = defaultMoved; - result.nondefaultAdded = nondefaultAdded; - result.defaultRemoved = defaultRemoved; - - // Next, determine how many add-on provided toolbars exist. - let addonToolbars = 0; - let toolbars = document.querySelectorAll("toolbar[customizable=true]"); - for (let toolbar of toolbars) { - if (DEFAULT_AREAS.indexOf(toolbar.id) == -1) { - addonToolbars++; - } - } - result.addonToolbars = addonToolbars; - - // Find out how many open tabs we have in each window - let winEnumerator = Services.wm.getEnumerator("navigator:browser"); - let visibleTabs = []; - let hiddenTabs = []; - while (winEnumerator.hasMoreElements()) { - let someWin = winEnumerator.getNext(); - if (someWin.gBrowser) { - let visibleTabsNum = someWin.gBrowser.visibleTabs.length; - visibleTabs.push(visibleTabsNum); - hiddenTabs.push(someWin.gBrowser.tabs.length - visibleTabsNum); - } - } - result.visibleTabs = visibleTabs; - result.hiddenTabs = hiddenTabs; - - if (Components.isSuccessCode(searchResult)) { - result.currentSearchEngine = Services.search.currentEngine.name; - } - - return result; - }, - - getToolbarMeasures: function() { - let result = this._firstWindowMeasurements || {}; - result.countableEvents = this._countableEvents; - result.durations = this._durations; - return result; - }, - - getSyncState: function() { - let result = {}; - for (let sub of ["desktop", "mobile"]) { - let count = 0; - try { - count = Services.prefs.getIntPref("services.sync.clients.devices." + sub); - } catch (ex) {} - result[sub] = count; - } - return result; - }, - - countCustomizationEvent: function(aEventType) { - this._countEvent(["customize", aEventType]); - }, - - countSearchEvent: function(source, query, selection) { - this._countEvent(["search", source]); - if ((/^[a-zA-Z]+:[^\/\\]/).test(query)) { - this._countEvent(["search", "urlbar-keyword"]); - } - if (selection) { - this._countEvent(["search", "selection", source, selection.index, selection.kind]); - } - }, - - countOneoffSearchEvent: function(id, type, where) { - this._countEvent(["search-oneoff", id, type, where]); - }, - - countSearchSettingsEvent: function(source) { - this._countEvent(["click-builtin-item", source, "search-settings"]); - }, - - countPanicEvent: function(timeId) { - this._countEvent(["forget-button", timeId]); - }, - - countTabMutingEvent: function(action, reason) { - this._countEvent(["tab-audio-control", action, reason || "no reason given"]); - }, - - countSyncedTabEvent: function(what, where) { - // "what" will be, eg, "open" - // "where" will be "toolbarbutton-subview" or "sidebar" - this._countEvent(["synced-tabs", what, where]); - }, - - countSidebarEvent: function(sidebarID, action) { - // sidebarID is the ID of the sidebar (duh!) - // action will be "hide" or "show" - this._countEvent(["sidebar", sidebarID, action]); - }, - - _logAwesomeBarSearchResult: function (url) { - let spec = Services.search.parseSubmissionURL(url); - if (spec.engine) { - let matchedEngine = "default"; - if (spec.engine.name !== Services.search.currentEngine.name) { - matchedEngine = "other"; - } - this.countSearchEvent("autocomplete-" + matchedEngine); - } - }, - - _durations: { - customization: [], - }, - - onCustomizeStart: function(aWindow) { - this._countEvent(["customize", "start"]); - let durationMap = WINDOW_DURATION_MAP.get(aWindow); - if (!durationMap) { - durationMap = {}; - WINDOW_DURATION_MAP.set(aWindow, durationMap); - } - - durationMap.customization = { - start: aWindow.performance.now(), - bucket: this._bucket, - }; - }, - - onCustomizeEnd: function(aWindow) { - let durationMap = WINDOW_DURATION_MAP.get(aWindow); - if (durationMap && "customization" in durationMap) { - let duration = aWindow.performance.now() - durationMap.customization.start; - this._durations.customization.push({ - duration: duration, - bucket: durationMap.customization.bucket, - }); - delete durationMap.customization; - } - }, - - _contextMenuItemWhitelist: new Set([ - "close-without-interaction", // for closing the menu without clicking it. - "custom-page-item", // The ID we use for page-provided items - "unknown", // The bucket for stuff with no id. - // Everything we know of so far (which will exclude add-on items): - "navigation", "back", "forward", "reload", "stop", "bookmarkpage", - "spell-no-suggestions", "spell-add-to-dictionary", - "spell-undo-add-to-dictionary", "openlinkincurrent", "openlinkintab", - "openlink", - // "openlinkprivate" intentionally omitted for privacy reasons. See bug 1176391. - "bookmarklink", "savelink", - "marklinkMenu", "copyemail", "copylink", "media-play", "media-pause", - "media-mute", "media-unmute", "media-playbackrate", - "media-playbackrate-050x", "media-playbackrate-100x", - "media-playbackrate-125x", "media-playbackrate-150x", "media-playbackrate-200x", - "media-showcontrols", "media-hidecontrols", - "video-fullscreen", "leave-dom-fullscreen", - "reloadimage", "viewimage", "viewvideo", "copyimage-contents", "copyimage", - "copyvideourl", "copyaudiourl", "saveimage", "sendimage", - "setDesktopBackground", "viewimageinfo", "viewimagedesc", "savevideo", - "saveaudio", "video-saveimage", "sendvideo", "sendaudio", - "ctp-play", "ctp-hide", "savepage", "pocket", "markpageMenu", - "viewbgimage", "undo", "cut", "copy", "paste", "delete", "selectall", - "keywordfield", "searchselect", "frame", "showonlythisframe", - "openframeintab", "openframe", "reloadframe", "bookmarkframe", "saveframe", - "printframe", "viewframesource", "viewframeinfo", - "viewpartialsource-selection", "viewpartialsource-mathml", - "viewsource", "viewinfo", "spell-check-enabled", - "spell-add-dictionaries-main", "spell-dictionaries", - "spell-dictionaries-menu", "spell-add-dictionaries", - "bidi-text-direction-toggle", "bidi-page-direction-toggle", "inspect", - "media-eme-learn-more" - ]), - - _contextMenuInteractions: {}, - - registerContextMenuInteraction: function(keys, itemID) { - if (itemID) { - if (itemID == "openlinkprivate") { - // Don't record anything, not even an other-item count - // if the user chose to open in a private window. See - // bug 1176391. - return; - } - - if (!this._contextMenuItemWhitelist.has(itemID)) { - itemID = "other-item"; - } - keys.push(itemID); - } - - this._countEvent(keys, this._contextMenuInteractions); - }, - - getContextMenuInfo: function() { - return this._contextMenuInteractions; - }, - - _bucket: BUCKET_DEFAULT, - _bucketTimer: null, - - /** - * Default bucket name, when no other bucket is active. - */ - get BUCKET_DEFAULT() { - return BUCKET_DEFAULT; - }, - - /** - * Bucket prefix, for named buckets. - */ - get BUCKET_PREFIX() { - return BUCKET_PREFIX; - }, - - /** - * Standard separator to use between different parts of a bucket name, such - * as primary name and the time step string. - */ - get BUCKET_SEPARATOR() { - return BUCKET_SEPARATOR; - }, - - get currentBucket() { - return this._bucket; - }, - - /** - * Sets a named bucket for all countable events and select durections to be - * put into. - * - * @param aName Name of bucket, or null for default bucket name (__DEFAULT__) - */ - setBucket: function(aName) { - if (this._bucketTimer) { - Timer.clearTimeout(this._bucketTimer); - this._bucketTimer = null; - } - - if (aName) - this._bucket = BUCKET_PREFIX + aName; - else - this._bucket = BUCKET_DEFAULT; - }, - - /** - * Sets a bucket that expires at the rate of a given series of time steps. - * Once the bucket expires, the current bucket will automatically revert to - * the default bucket. While the bucket is expiring, it's name is postfixed - * by '|' followed by a short string representation of the time step it's - * currently in. - * If any other bucket (expiring or normal) is set while an expiring bucket is - * still expiring, the old expiring bucket stops expiring and the new bucket - * immediately takes over. - * - * @param aName Name of bucket. - * @param aTimeSteps An array of times in milliseconds to count up to before - * reverting back to the default bucket. The array of times - * is expected to be pre-sorted in ascending order. - * For example, given a bucket name of 'bucket', the times: - * [60000, 300000, 600000] - * will result in the following buckets: - * * bucket|1m - for the first 1 minute - * * bucket|5m - for the following 4 minutes - * (until 5 minutes after the start) - * * bucket|10m - for the following 5 minutes - * (until 10 minutes after the start) - * * __DEFAULT__ - until a new bucket is set - * @param aTimeOffset Time offset, in milliseconds, from which to start - * counting. For example, if the first time step is 1000ms, - * and the time offset is 300ms, then the next time step - * will become active after 700ms. This affects all - * following time steps also, meaning they will also all be - * timed as though they started expiring 300ms before - * setExpiringBucket was called. - */ - setExpiringBucket: function(aName, aTimeSteps, aTimeOffset = 0) { - if (aTimeSteps.length === 0) { - this.setBucket(null); - return; - } - - if (this._bucketTimer) { - Timer.clearTimeout(this._bucketTimer); - this._bucketTimer = null; - } - - // Make a copy of the time steps array, so we can safely modify it without - // modifying the original array that external code has passed to us. - let steps = [...aTimeSteps]; - let msec = steps.shift(); - let postfix = this._toTimeStr(msec); - this.setBucket(aName + BUCKET_SEPARATOR + postfix); - - this._bucketTimer = Timer.setTimeout(() => { - this._bucketTimer = null; - this.setExpiringBucket(aName, steps, aTimeOffset + msec); - }, msec - aTimeOffset); - }, - - /** - * Formats a time interval, in milliseconds, to a minimal non-localized string - * representation. Format is: 'h' for hours, 'm' for minutes, 's' for seconds, - * 'ms' for milliseconds. - * Examples: - * 65 => 65ms - * 1000 => 1s - * 60000 => 1m - * 61000 => 1m01s - * - * @param aTimeMS Time in milliseconds - * - * @return Minimal string representation. - */ - _toTimeStr: function(aTimeMS) { - let timeStr = ""; - - function reduce(aUnitLength, aSymbol) { - if (aTimeMS >= aUnitLength) { - let units = Math.floor(aTimeMS / aUnitLength); - aTimeMS = aTimeMS - (units * aUnitLength) - timeStr += units + aSymbol; - } - } - - reduce(MS_HOUR, "h"); - reduce(MS_MINUTE, "m"); - reduce(MS_SECOND, "s"); - reduce(1, "ms"); - - return timeStr; - }, -}; - -/** - * Returns the id of the first ancestor of aNode that has an id. If aNode - * has no parent, or no ancestor has an id, returns null. - * - * @param aNode the node to find the first ID'd ancestor of - */ -function getIDBasedOnFirstIDedAncestor(aNode) { - while (!aNode.id) { - aNode = aNode.parentNode; - if (!aNode) { - return null; - } - } - - return aNode.id; -} diff --git a/browser/modules/BrowserUsageTelemetry.jsm b/browser/modules/BrowserUsageTelemetry.jsm deleted file mode 100644 index 39012d2ab..000000000 --- a/browser/modules/BrowserUsageTelemetry.jsm +++ /dev/null @@ -1,468 +0,0 @@ -/* -*- js-indent-level: 2; indent-tabs-mode: nil -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -"use strict"; - -this.EXPORTED_SYMBOLS = ["BrowserUsageTelemetry"]; - -const {classes: Cc, interfaces: Ci, utils: Cu} = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); - -XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", - "resource://gre/modules/PrivateBrowsingUtils.jsm"); - -// The upper bound for the count of the visited unique domain names. -const MAX_UNIQUE_VISITED_DOMAINS = 100; - -// Observed topic names. -const WINDOWS_RESTORED_TOPIC = "sessionstore-windows-restored"; -const TAB_RESTORING_TOPIC = "SSTabRestoring"; -const TELEMETRY_SUBSESSIONSPLIT_TOPIC = "internal-telemetry-after-subsession-split"; -const DOMWINDOW_OPENED_TOPIC = "domwindowopened"; - -// Probe names. -const MAX_TAB_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_tab_count"; -const MAX_WINDOW_COUNT_SCALAR_NAME = "browser.engagement.max_concurrent_window_count"; -const TAB_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.tab_open_event_count"; -const WINDOW_OPEN_EVENT_COUNT_SCALAR_NAME = "browser.engagement.window_open_event_count"; -const UNIQUE_DOMAINS_COUNT_SCALAR_NAME = "browser.engagement.unique_domains_count"; -const TOTAL_URI_COUNT_SCALAR_NAME = "browser.engagement.total_uri_count"; -const UNFILTERED_URI_COUNT_SCALAR_NAME = "browser.engagement.unfiltered_uri_count"; - -// A list of known search origins. -const KNOWN_SEARCH_SOURCES = [ - "abouthome", - "contextmenu", - "newtab", - "searchbar", - "urlbar", -]; - -const KNOWN_ONEOFF_SOURCES = [ - "oneoff-urlbar", - "oneoff-searchbar", - "unknown", // Edge case: this is the searchbar (see bug 1195733 comment 7). -]; - -function getOpenTabsAndWinsCounts() { - let tabCount = 0; - let winCount = 0; - - let browserEnum = Services.wm.getEnumerator("navigator:browser"); - while (browserEnum.hasMoreElements()) { - let win = browserEnum.getNext(); - winCount++; - tabCount += win.gBrowser.tabs.length; - } - - return { tabCount, winCount }; -} - -function getSearchEngineId(engine) { - if (engine) { - if (engine.identifier) { - return engine.identifier; - } - // Due to bug 1222070, we can't directly check Services.telemetry.canRecordExtended - // here. - const extendedTelemetry = Services.prefs.getBoolPref("toolkit.telemetry.enabled"); - if (engine.name && extendedTelemetry) { - // If it's a custom search engine only report the engine name - // if extended Telemetry is enabled. - return "other-" + engine.name; - } - } - return "other"; -} - -let URICountListener = { - // A set containing the visited domains, see bug 1271310. - _domainSet: new Set(), - // A map to keep track of the URIs loaded from the restored tabs. - _restoredURIsMap: new WeakMap(), - - isHttpURI(uri) { - // Only consider http(s) schemas. - return uri.schemeIs("http") || uri.schemeIs("https"); - }, - - addRestoredURI(browser, uri) { - if (!this.isHttpURI(uri)) { - return; - } - - this._restoredURIsMap.set(browser, uri.spec); - }, - - onLocationChange(browser, webProgress, request, uri, flags) { - // Don't count this URI if it's an error page. - if (flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_ERROR_PAGE) { - return; - } - - // We only care about top level loads. - if (!webProgress.isTopLevel) { - return; - } - - // The SessionStore sets the URI of a tab first, firing onLocationChange the - // first time, then manages content loading using its scheduler. Once content - // loads, we will hit onLocationChange again. - // We can catch the first case by checking for null requests: be advised that - // this can also happen when navigating page fragments, so account for it. - if (!request && - !(flags & Ci.nsIWebProgressListener.LOCATION_CHANGE_SAME_DOCUMENT)) { - return; - } - - // Track URI loads, even if they're not http(s). - let uriSpec = null; - try { - uriSpec = uri.spec; - } catch (e) { - // If we have troubles parsing the spec, still count this as - // an unfiltered URI. - Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); - return; - } - - - // Don't count about:blank and similar pages, as they would artificially - // inflate the counts. - if (browser.ownerDocument.defaultView.gInitialPages.includes(uriSpec)) { - return; - } - - // If the URI we're loading is in the _restoredURIsMap, then it comes from a - // restored tab. If so, let's skip it and remove it from the map as we want to - // count page refreshes. - if (this._restoredURIsMap.get(browser) === uriSpec) { - this._restoredURIsMap.delete(browser); - return; - } - - // The URI wasn't from a restored tab. Count it among the unfiltered URIs. - // If this is an http(s) URI, this also gets counted by the "total_uri_count" - // probe. - Services.telemetry.scalarAdd(UNFILTERED_URI_COUNT_SCALAR_NAME, 1); - - if (!this.isHttpURI(uri)) { - return; - } - - // Update the URI counts. - Services.telemetry.scalarAdd(TOTAL_URI_COUNT_SCALAR_NAME, 1); - - // We only want to count the unique domains up to MAX_UNIQUE_VISITED_DOMAINS. - if (this._domainSet.size == MAX_UNIQUE_VISITED_DOMAINS) { - return; - } - - // Unique domains should be aggregated by (eTLD + 1): x.test.com and y.test.com - // are counted once as test.com. - try { - // Even if only considering http(s) URIs, |getBaseDomain| could still throw - // due to the URI containing invalid characters or the domain actually being - // an ipv4 or ipv6 address. - this._domainSet.add(Services.eTLD.getBaseDomain(uri)); - } catch (e) { - return; - } - - Services.telemetry.scalarSet(UNIQUE_DOMAINS_COUNT_SCALAR_NAME, this._domainSet.size); - }, - - /** - * Reset the counts. This should be called when breaking a session in Telemetry. - */ - reset() { - this._domainSet.clear(); - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, - Ci.nsISupportsWeakReference]), -}; - -let BrowserUsageTelemetry = { - init() { - Services.obs.addObserver(this, WINDOWS_RESTORED_TOPIC, false); - }, - - /** - * Handle subsession splits in the parent process. - */ - afterSubsessionSplit() { - // Scalars just got cleared due to a subsession split. We need to set the maximum - // concurrent tab and window counts so that they reflect the correct value for the - // new subsession. - const counts = getOpenTabsAndWinsCounts(); - Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, counts.tabCount); - Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount); - - // Reset the URI counter. - URICountListener.reset(); - }, - - uninit() { - Services.obs.removeObserver(this, DOMWINDOW_OPENED_TOPIC, false); - Services.obs.removeObserver(this, TELEMETRY_SUBSESSIONSPLIT_TOPIC, false); - Services.obs.removeObserver(this, WINDOWS_RESTORED_TOPIC, false); - }, - - observe(subject, topic, data) { - switch (topic) { - case WINDOWS_RESTORED_TOPIC: - this._setupAfterRestore(); - break; - case DOMWINDOW_OPENED_TOPIC: - this._onWindowOpen(subject); - break; - case TELEMETRY_SUBSESSIONSPLIT_TOPIC: - this.afterSubsessionSplit(); - break; - } - }, - - handleEvent(event) { - switch (event.type) { - case "TabOpen": - this._onTabOpen(); - break; - case "unload": - this._unregisterWindow(event.target); - break; - case TAB_RESTORING_TOPIC: - // We're restoring a new tab from a previous or crashed session. - // We don't want to track the URIs from these tabs, so let - // |URICountListener| know about them. - let browser = event.target.linkedBrowser; - URICountListener.addRestoredURI(browser, browser.currentURI); - break; - } - }, - - /** - * The main entry point for recording search related Telemetry. This includes - * search counts and engagement measurements. - * - * Telemetry records only search counts per engine and action origin, but - * nothing pertaining to the search contents themselves. - * - * @param {nsISearchEngine} engine - * The engine handling the search. - * @param {String} source - * Where the search originated from. See KNOWN_SEARCH_SOURCES for allowed - * values. - * @param {Object} [details] Options object. - * @param {Boolean} [details.isOneOff=false] - * true if this event was generated by a one-off search. - * @param {Boolean} [details.isSuggestion=false] - * true if this event was generated by a suggested search. - * @param {Boolean} [details.isAlias=false] - * true if this event was generated by a search using an alias. - * @param {Object} [details.type=null] - * The object describing the event that triggered the search. - * @throws if source is not in the known sources list. - */ - recordSearch(engine, source, details={}) { - const isOneOff = !!details.isOneOff; - const countId = getSearchEngineId(engine) + "." + source; - - if (isOneOff) { - if (!KNOWN_ONEOFF_SOURCES.includes(source)) { - // Silently drop the error if this bogus call - // came from 'urlbar' or 'searchbar'. They're - // calling |recordSearch| twice from two different - // code paths because they want to record the search - // in SEARCH_COUNTS. - if (['urlbar', 'searchbar'].includes(source)) { - Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").add(countId); - return; - } - throw new Error("Unknown source for one-off search: " + source); - } - } else { - if (!KNOWN_SEARCH_SOURCES.includes(source)) { - throw new Error("Unknown source for search: " + source); - } - Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS").add(countId); - } - - // Dispatch the search signal to other handlers. - this._handleSearchAction(engine, source, details); - }, - - _recordSearch(engine, source, action = null) { - let scalarKey = action ? "search_" + action : "search"; - Services.telemetry.keyedScalarAdd("browser.engagement.navigation." + source, - scalarKey, 1); - Services.telemetry.recordEvent("navigation", "search", source, action, - { engine: getSearchEngineId(engine) }); - }, - - _handleSearchAction(engine, source, details) { - switch (source) { - case "urlbar": - case "oneoff-urlbar": - case "searchbar": - case "oneoff-searchbar": - case "unknown": // Edge case: this is the searchbar (see bug 1195733 comment 7). - this._handleSearchAndUrlbar(engine, source, details); - break; - case "abouthome": - this._recordSearch(engine, "about_home", "enter"); - break; - case "newtab": - this._recordSearch(engine, "about_newtab", "enter"); - break; - case "contextmenu": - this._recordSearch(engine, "contextmenu"); - break; - } - }, - - /** - * This function handles the "urlbar", "urlbar-oneoff", "searchbar" and - * "searchbar-oneoff" sources. - */ - _handleSearchAndUrlbar(engine, source, details) { - // We want "urlbar" and "urlbar-oneoff" (and similar cases) to go in the same - // scalar, but in a different key. - - // When using one-offs in the searchbar we get an "unknown" source. See bug - // 1195733 comment 7 for the context. Fix-up the label here. - const sourceName = - (source === "unknown") ? "searchbar" : source.replace("oneoff-", ""); - - const isOneOff = !!details.isOneOff; - if (isOneOff) { - // We will receive a signal from the "urlbar"/"searchbar" even when the - // search came from "oneoff-urlbar". That's because both signals - // are propagated from search.xml. Skip it if that's the case. - // Moreover, we skip the "unknown" source that comes from the searchbar - // when performing searches from the default search engine. See bug 1195733 - // comment 7 for context. - if (["urlbar", "searchbar", "unknown"].includes(source)) { - return; - } - - // If that's a legit one-off search signal, record it using the relative key. - this._recordSearch(engine, sourceName, "oneoff"); - return; - } - - // The search was not a one-off. It was a search with the default search engine. - if (details.isSuggestion) { - // It came from a suggested search, so count it as such. - this._recordSearch(engine, sourceName, "suggestion"); - return; - } else if (details.isAlias) { - // This one came from a search that used an alias. - this._recordSearch(engine, sourceName, "alias"); - return; - } - - // The search signal was generated by typing something and pressing enter. - this._recordSearch(engine, sourceName, "enter"); - }, - - /** - * This gets called shortly after the SessionStore has finished restoring - * windows and tabs. It counts the open tabs and adds listeners to all the - * windows. - */ - _setupAfterRestore() { - // Make sure to catch new chrome windows and subsession splits. - Services.obs.addObserver(this, DOMWINDOW_OPENED_TOPIC, false); - Services.obs.addObserver(this, TELEMETRY_SUBSESSIONSPLIT_TOPIC, false); - - // Attach the tabopen handlers to the existing Windows. - let browserEnum = Services.wm.getEnumerator("navigator:browser"); - while (browserEnum.hasMoreElements()) { - this._registerWindow(browserEnum.getNext()); - } - - // Get the initial tab and windows max counts. - const counts = getOpenTabsAndWinsCounts(); - Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, counts.tabCount); - Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount); - }, - - /** - * Adds listeners to a single chrome window. - */ - _registerWindow(win) { - win.addEventListener("unload", this); - win.addEventListener("TabOpen", this, true); - - // Don't include URI and domain counts when in private mode. - if (PrivateBrowsingUtils.isWindowPrivate(win)) { - return; - } - win.gBrowser.tabContainer.addEventListener(TAB_RESTORING_TOPIC, this); - win.gBrowser.addTabsProgressListener(URICountListener); - }, - - /** - * Removes listeners from a single chrome window. - */ - _unregisterWindow(win) { - win.removeEventListener("unload", this); - win.removeEventListener("TabOpen", this, true); - - // Don't include URI and domain counts when in private mode. - if (PrivateBrowsingUtils.isWindowPrivate(win.defaultView)) { - return; - } - win.defaultView.gBrowser.tabContainer.removeEventListener(TAB_RESTORING_TOPIC, this); - win.defaultView.gBrowser.removeTabsProgressListener(URICountListener); - }, - - /** - * Updates the tab counts. - * @param {Number} [newTabCount=0] The count of the opened tabs across all windows. This - * is computed manually if not provided. - */ - _onTabOpen(tabCount = 0) { - // Use the provided tab count if available. Otherwise, go on and compute it. - tabCount = tabCount || getOpenTabsAndWinsCounts().tabCount; - // Update the "tab opened" count and its maximum. - Services.telemetry.scalarAdd(TAB_OPEN_EVENT_COUNT_SCALAR_NAME, 1); - Services.telemetry.scalarSetMaximum(MAX_TAB_COUNT_SCALAR_NAME, tabCount); - }, - - /** - * Tracks the window count and registers the listeners for the tab count. - * @param{Object} win The window object. - */ - _onWindowOpen(win) { - // Make sure to have a |nsIDOMWindow|. - if (!(win instanceof Ci.nsIDOMWindow)) { - return; - } - - let onLoad = () => { - win.removeEventListener("load", onLoad, false); - - // Ignore non browser windows. - if (win.document.documentElement.getAttribute("windowtype") != "navigator:browser") { - return; - } - - this._registerWindow(win); - // Track the window open event and check the maximum. - const counts = getOpenTabsAndWinsCounts(); - Services.telemetry.scalarAdd(WINDOW_OPEN_EVENT_COUNT_SCALAR_NAME, 1); - Services.telemetry.scalarSetMaximum(MAX_WINDOW_COUNT_SCALAR_NAME, counts.winCount); - - // We won't receive the "TabOpen" event for the first tab within a new window. - // Account for that. - this._onTabOpen(counts.tabCount); - }; - win.addEventListener("load", onLoad, false); - }, -}; diff --git a/browser/modules/CastingApps.jsm b/browser/modules/CastingApps.jsm deleted file mode 100644 index 6f32753e8..000000000 --- a/browser/modules/CastingApps.jsm +++ /dev/null @@ -1,164 +0,0 @@ -// -*- Mode: js; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*- -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this file, - * You can obtain one at http://mozilla.org/MPL/2.0/. */ -"use strict"; -this.EXPORTED_SYMBOLS = ["CastingApps"]; - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; - -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/SimpleServiceDiscovery.jsm"); - - -var CastingApps = { - _sendEventToVideo: function (element, data) { - let event = element.ownerDocument.createEvent("CustomEvent"); - event.initCustomEvent("media-videoCasting", false, true, JSON.stringify(data)); - element.dispatchEvent(event); - }, - - makeURI: function (url, charset, baseURI) { - return Services.io.newURI(url, charset, baseURI); - }, - - getVideo: function (element) { - if (!element) { - return null; - } - - let extensions = SimpleServiceDiscovery.getSupportedExtensions(); - let types = SimpleServiceDiscovery.getSupportedMimeTypes(); - - // Grab the poster attribute from the