summaryrefslogtreecommitdiffstats
path: root/mobile/android/components
diff options
context:
space:
mode:
Diffstat (limited to 'mobile/android/components')
-rw-r--r--mobile/android/components/AboutRedirector.js132
-rw-r--r--mobile/android/components/AddonUpdateService.js67
-rw-r--r--mobile/android/components/BlocklistPrompt.js61
-rw-r--r--mobile/android/components/BrowserCLH.js47
-rw-r--r--mobile/android/components/ColorPicker.js55
-rw-r--r--mobile/android/components/ContentDispatchChooser.js83
-rw-r--r--mobile/android/components/ContentPermissionPrompt.js146
-rw-r--r--mobile/android/components/DirectoryProvider.js214
-rw-r--r--mobile/android/components/FilePicker.js302
-rw-r--r--mobile/android/components/HelperAppDialog.js373
-rw-r--r--mobile/android/components/ImageBlockingPolicy.js125
-rw-r--r--mobile/android/components/LoginManagerPrompter.js413
-rw-r--r--mobile/android/components/MobileComponents.manifest123
-rw-r--r--mobile/android/components/NSSDialogService.js276
-rw-r--r--mobile/android/components/PersistentNotificationHandler.js78
-rw-r--r--mobile/android/components/PresentationDevicePrompt.js134
-rw-r--r--mobile/android/components/PresentationRequestUIGlue.js86
-rw-r--r--mobile/android/components/PromptService.js878
-rw-r--r--mobile/android/components/SessionStore.idl86
-rw-r--r--mobile/android/components/SessionStore.js1791
-rw-r--r--mobile/android/components/SiteSpecificUserAgent.js33
-rw-r--r--mobile/android/components/Snippets.js446
-rw-r--r--mobile/android/components/TabSource.js91
-rw-r--r--mobile/android/components/XPIDialogService.js49
-rw-r--r--mobile/android/components/build/moz.build31
-rw-r--r--mobile/android/components/build/nsAndroidHistory.cpp395
-rw-r--r--mobile/android/components/build/nsAndroidHistory.h97
-rw-r--r--mobile/android/components/build/nsBrowserComponents.h7
-rw-r--r--mobile/android/components/build/nsBrowserModule.cpp47
-rw-r--r--mobile/android/components/build/nsIShellService.idl26
-rw-r--r--mobile/android/components/build/nsShellService.cpp30
-rw-r--r--mobile/android/components/build/nsShellService.h29
-rw-r--r--mobile/android/components/extensions/.eslintrc.js5
-rw-r--r--mobile/android/components/extensions/ext-pageAction.js169
-rw-r--r--mobile/android/components/extensions/extensions-mobile.manifest5
-rw-r--r--mobile/android/components/extensions/jar.mn6
-rw-r--r--mobile/android/components/extensions/moz.build16
-rw-r--r--mobile/android/components/extensions/schemas/jar.mn6
-rw-r--r--mobile/android/components/extensions/schemas/moz.build7
-rw-r--r--mobile/android/components/extensions/schemas/page_action.json239
-rw-r--r--mobile/android/components/extensions/test/mochitest/.eslintrc.js10
-rw-r--r--mobile/android/components/extensions/test/mochitest/chrome.ini7
-rw-r--r--mobile/android/components/extensions/test/mochitest/head.js15
-rw-r--r--mobile/android/components/extensions/test/mochitest/mochitest.ini6
-rw-r--r--mobile/android/components/extensions/test/mochitest/test_ext_all_apis.html23
-rw-r--r--mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html99
-rw-r--r--mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html169
-rw-r--r--mobile/android/components/moz.build47
48 files changed, 0 insertions, 7580 deletions
diff --git a/mobile/android/components/AboutRedirector.js b/mobile/android/components/AboutRedirector.js
deleted file mode 100644
index df50864dd..000000000
--- a/mobile/android/components/AboutRedirector.js
+++ /dev/null
@@ -1,132 +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/. */
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-var modules = {
- // about:
- "": {
- uri: "chrome://browser/content/about.xhtml",
- privileged: true
- },
-
- // about:fennec and about:firefox are aliases for about:,
- // but hidden from about:about
- fennec: {
- uri: "chrome://browser/content/about.xhtml",
- privileged: true,
- hide: true
- },
- get firefox() {
- return this.fennec
- },
-
- // about:blank has some bad loading behavior we can avoid, if we use an alias
- empty: {
- uri: "about:blank",
- privileged: false,
- hide: true
- },
-
- rights: {
- uri: "chrome://browser/content/aboutRights.xhtml",
- privileged: false
- },
- blocked: {
- uri: "chrome://browser/content/blockedSite.xhtml",
- privileged: false,
- hide: true
- },
- certerror: {
- uri: "chrome://browser/content/aboutCertError.xhtml",
- privileged: false,
- hide: true
- },
- home: {
- uri: "chrome://browser/content/aboutHome.xhtml",
- privileged: false
- },
- downloads: {
- uri: "chrome://browser/content/aboutDownloads.xhtml",
- privileged: true
- },
- reader: {
- uri: "chrome://global/content/reader/aboutReader.html",
- privileged: false,
- hide: true
- },
- feedback: {
- uri: "chrome://browser/content/aboutFeedback.xhtml",
- privileged: true
- },
- privatebrowsing: {
- uri: "chrome://browser/content/aboutPrivateBrowsing.xhtml",
- privileged: true
- },
- logins: {
- uri: "chrome://browser/content/aboutLogins.xhtml",
- privileged: true
- },
- accounts: {
- uri: "chrome://browser/content/aboutAccounts.xhtml",
- privileged: true
- },
-};
-
-if (AppConstants.MOZ_SERVICES_HEALTHREPORT) {
- modules['healthreport'] = {
- uri: "chrome://browser/content/aboutHealthReport.xhtml",
- privileged: true
- };
-}
-
-function AboutRedirector() {}
-AboutRedirector.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
- classID: Components.ID("{322ba47e-7047-4f71-aebf-cb7d69325cd9}"),
-
- _getModuleInfo: function (aURI) {
- let moduleName = aURI.path.replace(/[?#].*/, "").toLowerCase();
- return modules[moduleName];
- },
-
- // nsIAboutModule
- getURIFlags: function(aURI) {
- let flags;
- let moduleInfo = this._getModuleInfo(aURI);
- if (moduleInfo.hide)
- flags = Ci.nsIAboutModule.HIDE_FROM_ABOUTABOUT;
-
- return flags | Ci.nsIAboutModule.ALLOW_SCRIPT;
- },
-
- newChannel: function(aURI, aLoadInfo) {
- let moduleInfo = this._getModuleInfo(aURI);
-
- var ios = Cc["@mozilla.org/network/io-service;1"].
- getService(Ci.nsIIOService);
-
- var newURI = ios.newURI(moduleInfo.uri, null, null);
-
- var channel = ios.newChannelFromURIWithLoadInfo(newURI, aLoadInfo);
-
- if (!moduleInfo.privileged) {
- // Setting the owner to null means that we'll go through the normal
- // path in GetChannelPrincipal and create a codebase principal based
- // on the channel's originalURI
- channel.owner = null;
- }
-
- channel.originalURI = aURI;
-
- return channel;
- }
-};
-
-const components = [AboutRedirector];
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
diff --git a/mobile/android/components/AddonUpdateService.js b/mobile/android/components/AddonUpdateService.js
deleted file mode 100644
index b2c4732c3..000000000
--- a/mobile/android/components/AddonUpdateService.js
+++ /dev/null
@@ -1,67 +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/. */
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AddonManagerPrivate",
- "resource://gre/modules/AddonManager.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AddonRepository",
- "resource://gre/modules/addons/AddonRepository.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "GMPInstallManager",
- "resource://gre/modules/GMPInstallManager.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Messaging",
- "resource://gre/modules/Messaging.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
-
-// -----------------------------------------------------------------------
-// Add-on auto-update management service
-// -----------------------------------------------------------------------
-
-const PREF_ADDON_UPDATE_ENABLED = "extensions.autoupdate.enabled";
-const PREF_ADDON_UPDATE_INTERVAL = "extensions.autoupdate.interval";
-
-var gNeedsRestart = false;
-
-function AddonUpdateService() {}
-
-AddonUpdateService.prototype = {
- classDescription: "Add-on auto-update management",
- classID: Components.ID("{93c8824c-9b87-45ae-bc90-5b82a1e4d877}"),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITimerCallback]),
-
- notify: function aus_notify(aTimer) {
- if (aTimer && !Services.prefs.getBoolPref(PREF_ADDON_UPDATE_ENABLED, true))
- return;
-
- // If we already auto-upgraded and installed new versions, ignore this check
- if (gNeedsRestart)
- return;
-
- AddonManagerPrivate.backgroundUpdateCheck();
-
- let gmp = new GMPInstallManager();
- gmp.simpleCheckAndInstall().then(null, () => {});
-
- let interval = 1000 * Services.prefs.getIntPref(PREF_ADDON_UPDATE_INTERVAL, 86400);
- Messaging.sendRequest({
- type: "Gecko:ScheduleRun",
- action: "update-addons",
- trigger: interval,
- interval: interval,
- });
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AddonUpdateService]);
-
diff --git a/mobile/android/components/BlocklistPrompt.js b/mobile/android/components/BlocklistPrompt.js
deleted file mode 100644
index ce7b8e011..000000000
--- a/mobile/android/components/BlocklistPrompt.js
+++ /dev/null
@@ -1,61 +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/. */
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cc = Components.classes;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-// -----------------------------------------------------------------------
-// BlocklistPrompt Service
-// -----------------------------------------------------------------------
-
-
-function BlocklistPrompt() { }
-
-BlocklistPrompt.prototype = {
- prompt: function(aAddons, aCount) {
- let win = Services.wm.getMostRecentWindow("navigator:browser");
- if (win.ExtensionsView.visible) {
- win.ExtensionsView.showRestart("blocked");
- } else {
- let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
- let notifyBox = win.getNotificationBox();
- let restartCallback = function(aNotification, aDescription) {
- // Notify all windows that an application quit has been requested
- var cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
- Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart");
-
- // If nothing aborted, quit the app
- if (cancelQuit.data == false) {
- let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup);
- appStartup.quit(Ci.nsIAppStartup.eRestart | Ci.nsIAppStartup.eAttemptQuit);
- }
- };
-
- let buttons = [{accessKey: null,
- label: bundle.GetStringFromName("notificationRestart.button"),
- callback: restartCallback}];
- notifyBox.appendNotification(bundle.GetStringFromName("notificationRestart.blocked"),
- "blocked-add-on",
- "",
- "PRIORITY_CRITICAL_HIGH",
- buttons);
- }
- // Disable softblocked items automatically
- for (let i = 0; i < aAddons.length; i++) {
- if (aAddons[i].item instanceof Ci.nsIPluginTag)
- aAddons[i].item.disabled = true;
- else
- aAddons[i].item.userDisabled = true;
- }
- },
- classID: Components.ID("{4e6ea350-b09a-11df-94e2-0800200c9a66}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIBlocklistPrompt])
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([BlocklistPrompt]);
-
diff --git a/mobile/android/components/BrowserCLH.js b/mobile/android/components/BrowserCLH.js
deleted file mode 100644
index 4cbf03554..000000000
--- a/mobile/android/components/BrowserCLH.js
+++ /dev/null
@@ -1,47 +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/. */
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-function BrowserCLH() {}
-
-BrowserCLH.prototype = {
- /**
- * Register resource://android as the APK root.
- *
- * Consumers can access Android assets using resource://android/assets/FILENAME.
- */
- setResourceSubstitutions: function () {
- let registry = Cc["@mozilla.org/chrome/chrome-registry;1"].getService(Ci["nsIChromeRegistry"]);
- // Like jar:jar:file:///data/app/org.mozilla.fennec-2.apk!/assets/omni.ja!/chrome/chrome/content/aboutHome.xhtml
- let url = registry.convertChromeURL(Services.io.newURI("chrome://browser/content/aboutHome.xhtml", null, null)).spec;
- // Like jar:file:///data/app/org.mozilla.fennec-2.apk!/
- url = url.substring(4, url.indexOf("!/") + 2);
-
- let protocolHandler = Services.io.getProtocolHandler("resource").QueryInterface(Ci.nsIResProtocolHandler);
- protocolHandler.setSubstitution("android", Services.io.newURI(url, null, null));
- },
-
- observe: function (subject, topic, data) {
- switch (topic) {
- case "app-startup":
- this.setResourceSubstitutions();
- break;
- }
- },
-
- // QI
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
-
- // XPCOMUtils factory
- classID: Components.ID("{be623d20-d305-11de-8a39-0800200c9a66}")
-};
-
-var components = [ BrowserCLH ];
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
diff --git a/mobile/android/components/ColorPicker.js b/mobile/android/components/ColorPicker.js
deleted file mode 100644
index 7d478da80..000000000
--- a/mobile/android/components/ColorPicker.js
+++ /dev/null
@@ -1,55 +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/. */
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cc = Components.classes;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Prompt",
- "resource://gre/modules/Prompt.jsm");
-
-function ColorPicker() {
-}
-
-ColorPicker.prototype = {
- _initial: 0,
- _domWin: null,
- _title: "",
-
- get strings() {
- if (!this._strings) {
- this._strings = Services.strings.createBundle("chrome://browser/locale/browser.properties");
- }
- return this._strings;
- },
-
- init: function(aParent, aTitle, aInitial) {
- this._domWin = aParent;
- this._initial = aInitial;
- this._title = aTitle;
- },
-
- open: function(aCallback) {
- let p = new Prompt({ title: this._title,
- buttons: [
- this.strings.GetStringFromName("inputWidgetHelper.set"),
- this.strings.GetStringFromName("inputWidgetHelper.cancel")
- ] })
- .addColorPicker({ value: this._initial })
- .show((data) => {
- if (data.button == 0)
- aCallback.done(data.color0);
- else
- aCallback.done(this._initial);
- });
- },
-
- classID: Components.ID("{430b987f-bb9f-46a3-99a5-241749220b29}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIColorPicker])
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ColorPicker]);
diff --git a/mobile/android/components/ContentDispatchChooser.js b/mobile/android/components/ContentDispatchChooser.js
deleted file mode 100644
index b28e356e0..000000000
--- a/mobile/android/components/ContentDispatchChooser.js
+++ /dev/null
@@ -1,83 +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/. */
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cc = Components.classes;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Messaging.jsm");
-
-function ContentDispatchChooser() {}
-
-ContentDispatchChooser.prototype =
-{
- classID: Components.ID("5a072a22-1e66-4100-afc1-07aed8b62fc5"),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentDispatchChooser]),
-
- get protoSvc() {
- if (!this._protoSvc) {
- this._protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].getService(Ci.nsIExternalProtocolService);
- }
- return this._protoSvc;
- },
-
- _getChromeWin: function getChromeWin() {
- try {
- return Services.wm.getMostRecentWindow("navigator:browser");
- } catch (e) {
- throw Cr.NS_ERROR_FAILURE;
- }
- },
-
- ask: function ask(aHandler, aWindowContext, aURI, aReason) {
- let window = null;
- try {
- if (aWindowContext)
- window = aWindowContext.getInterface(Ci.nsIDOMWindow);
- } catch (e) { /* it's OK to not have a window */ }
-
- // The current list is based purely on the scheme. Redo the query using the url to get more
- // specific results.
- aHandler = this.protoSvc.getProtocolHandlerInfoFromOS(aURI.spec, {});
-
- // The first handler in the set is the Android Application Chooser (which will fall back to a default if one is set)
- // If we have more than one option, let the OS handle showing a list (if needed).
- if (aHandler.possibleApplicationHandlers.length > 1) {
- aHandler.launchWithURI(aURI, aWindowContext);
- } else {
- // xpcshell tests do not have an Android Bridge but we require Android
- // Bridge when using Messaging so we guard against this case. xpcshell
- // tests also do not have a window, so we use this state to guard.
- let win = this._getChromeWin();
- if (!win) {
- return;
- }
-
- let msg = {
- type: "Intent:OpenNoHandler",
- uri: aURI.spec,
- };
-
- Messaging.sendRequestForResult(msg).then(() => {
- // Java opens an app on success: take no action.
- }, (uri) => {
- // We couldn't open this. If this was from a click, it's likely that we just
- // want this to fail silently. If the user entered this on the address bar, though,
- // we want to show the neterror page.
-
- let dwu = window.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
- let millis = dwu.millisSinceLastUserInput;
- if (millis > 0 && millis >= 1000) {
- window.location.href = uri;
- }
- });
- }
- },
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentDispatchChooser]);
diff --git a/mobile/android/components/ContentPermissionPrompt.js b/mobile/android/components/ContentPermissionPrompt.js
deleted file mode 100644
index fd13ce26b..000000000
--- a/mobile/android/components/ContentPermissionPrompt.js
+++ /dev/null
@@ -1,146 +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/. */
-
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
-const Cc = Components.classes;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-const kEntities = {
- "contacts": "contacts",
- "desktop-notification": "desktopNotification2",
- "geolocation": "geolocation",
- "flyweb-publish-server": "flyWebPublishServer",
-};
-
-// For these types, prompt for permission if action is unknown.
-const PROMPT_FOR_UNKNOWN = [
- "desktop-notification",
- "geolocation",
- "flyweb-publish-server",
-];
-
-function ContentPermissionPrompt() {}
-
-ContentPermissionPrompt.prototype = {
- classID: Components.ID("{C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}"),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt]),
-
- handleExistingPermission: function handleExistingPermission(request, type, denyUnknown) {
- let result = Services.perms.testExactPermissionFromPrincipal(request.principal, type);
- if (result == Ci.nsIPermissionManager.ALLOW_ACTION) {
- request.allow();
- return true;
- }
-
- if (result == Ci.nsIPermissionManager.DENY_ACTION) {
- request.cancel();
- return true;
- }
-
- if (denyUnknown && result == Ci.nsIPermissionManager.UNKNOWN_ACTION) {
- request.cancel();
- return true;
- }
-
- return false;
- },
-
- getChromeWindow: function getChromeWindow(aWindow) {
- let chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShellTreeItem)
- .rootTreeItem
- .QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindow)
- .QueryInterface(Ci.nsIDOMChromeWindow);
- return chromeWin;
- },
-
- getChromeForRequest: function getChromeForRequest(request) {
- if (request.window) {
- let requestingWindow = request.window.top;
- return this.getChromeWindow(requestingWindow).wrappedJSObject;
- }
- return request.element.ownerDocument.defaultView;
- },
-
- prompt: function(request) {
- let isApp = request.principal.appId !== Ci.nsIScriptSecurityManager.NO_APP_ID && request.principal.appId !== Ci.nsIScriptSecurityManager.UNKNOWN_APP_ID;
-
- // Only allow exactly one permission rquest here.
- let types = request.types.QueryInterface(Ci.nsIArray);
- if (types.length != 1) {
- request.cancel();
- return;
- }
- let perm = types.queryElementAt(0, Ci.nsIContentPermissionType);
-
- // Returns true if the request was handled
- let access = (perm.access && perm.access !== "unused") ?
- (perm.type + "-" + perm.access) : perm.type;
- if (this.handleExistingPermission(request, access,
- /* denyUnknown */ isApp || PROMPT_FOR_UNKNOWN.indexOf(perm.type) < 0))
- return;
-
- let chromeWin = this.getChromeForRequest(request);
- let tab = chromeWin.BrowserApp.getTabForWindow(request.window.top);
- if (!tab)
- return;
-
- let browserBundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
- let entityName = kEntities[perm.type];
-
- let buttons = [{
- label: browserBundle.GetStringFromName(entityName + ".dontAllow"),
- callback: function(aChecked) {
- // If the user checked "Don't ask again" or this is a desktopNotification, make a permanent exception
- if (aChecked || entityName == "desktopNotification2")
- Services.perms.addFromPrincipal(request.principal, access, Ci.nsIPermissionManager.DENY_ACTION);
-
- request.cancel();
- }
- },
- {
- label: browserBundle.GetStringFromName(entityName + ".allow"),
- callback: function(aChecked) {
- // If the user checked "Don't ask again" or this is a desktopNotification, make a permanent exception
- if (aChecked || entityName == "desktopNotification2") {
- Services.perms.addFromPrincipal(request.principal, access, Ci.nsIPermissionManager.ALLOW_ACTION);
- } else if (isApp) {
- // Otherwise allow the permission for the current session if the request comes from an app
- Services.perms.addFromPrincipal(request.principal, access, Ci.nsIPermissionManager.ALLOW_ACTION, Ci.nsIPermissionManager.EXPIRE_SESSION);
- }
-
- request.allow();
- },
- positive: true
- }];
-
- let requestor = chromeWin.BrowserApp.manifest ? "'" + chromeWin.BrowserApp.manifest.name + "'" : request.principal.URI.host;
- let message = browserBundle.formatStringFromName(entityName + ".ask", [requestor], 1);
- // desktopNotification doesn't have a checkbox
- let options;
- if (entityName == "desktopNotification2") {
- options = {
- link: {
- label: browserBundle.GetStringFromName("doorhanger.learnMore"),
- url: "https://www.mozilla.org/firefox/push/"
- }
- };
- } else {
- options = { checkbox: browserBundle.GetStringFromName(entityName + ".dontAskAgain") };
- }
-
- chromeWin.NativeWindow.doorhanger.show(message, entityName + request.principal.URI.host, buttons, tab.id, options, entityName.toUpperCase());
- }
-};
-
-
-//module initialization
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);
diff --git a/mobile/android/components/DirectoryProvider.js b/mobile/android/components/DirectoryProvider.js
deleted file mode 100644
index 5d0f7974c..000000000
--- a/mobile/android/components/DirectoryProvider.js
+++ /dev/null
@@ -1,214 +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/. */
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/AppConstants.jsm");
-Cu.import("resource://gre/modules/FileUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "JNI", "resource://gre/modules/JNI.jsm");
-
-// -----------------------------------------------------------------------
-// Directory Provider for special browser folders and files
-// -----------------------------------------------------------------------
-
-const NS_APP_CACHE_PARENT_DIR = "cachePDir";
-const NS_APP_SEARCH_DIR = "SrchPlugns";
-const NS_APP_SEARCH_DIR_LIST = "SrchPluginsDL";
-const NS_APP_DISTRIBUTION_SEARCH_DIR_LIST = "SrchPluginsDistDL";
-const NS_APP_USER_SEARCH_DIR = "UsrSrchPlugns";
-const NS_XPCOM_CURRENT_PROCESS_DIR = "XCurProcD";
-const XRE_APP_DISTRIBUTION_DIR = "XREAppDist";
-const XRE_UPDATE_ROOT_DIR = "UpdRootD";
-const ENVVAR_UPDATE_DIR = "UPDATES_DIRECTORY";
-const WEBAPPS_DIR = "webappsDir";
-
-const SYSTEM_DIST_PATH = `/system/${AppConstants.ANDROID_PACKAGE_NAME}/distribution`;
-
-function DirectoryProvider() {}
-
-DirectoryProvider.prototype = {
- classID: Components.ID("{ef0f7a87-c1ee-45a8-8d67-26f586e46a4b}"),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIDirectoryServiceProvider,
- Ci.nsIDirectoryServiceProvider2]),
-
- getFile: function(prop, persistent) {
- if (prop == NS_APP_CACHE_PARENT_DIR) {
- let dirsvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
- let profile = dirsvc.get("ProfD", Ci.nsIFile);
- return profile;
- } else if (prop == WEBAPPS_DIR) {
- // returns the folder that should hold the webapps database file
- // For fennec we will store that in the root profile folder so that all
- // webapps can easily access it
- let dirsvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
- let profile = dirsvc.get("ProfD", Ci.nsIFile);
- return profile.parent;
- } else if (prop == XRE_APP_DISTRIBUTION_DIR) {
- let distributionDirectories = this._getDistributionDirectories();
- for (let i = 0; i < distributionDirectories.length; i++) {
- if (distributionDirectories[i].exists()) {
- return distributionDirectories[i];
- }
- }
- // Fallback: Return default data distribution directory
- return FileUtils.getDir(NS_XPCOM_CURRENT_PROCESS_DIR, ["distribution"], false);
- } else if (prop == XRE_UPDATE_ROOT_DIR) {
- let env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
- if (env.exists(ENVVAR_UPDATE_DIR)) {
- let path = env.get(ENVVAR_UPDATE_DIR);
- if (path) {
- return new FileUtils.File(path);
- }
- }
- return new FileUtils.File(env.get("DOWNLOADS_DIRECTORY"));
- }
-
- // We are retuning null to show failure instead for throwing an error. The
- // interface is called quite a bit and throwing an error is noisy. Returning
- // null works with the way the interface is called [see bug 529077]
- return null;
- },
-
- /**
- * Appends the distribution-specific search engine directories to the array.
- * The distribution directory structure is as follows:
- *
- * \- distribution/
- * \- searchplugins/
- * |- common/
- * \- locale/
- * |- <locale 1>/
- * ...
- * \- <locale N>/
- *
- * Common engines are loaded for all locales. If there is no locale directory for
- * the current locale, there is a pref: "distribution.searchplugins.defaultLocale",
- * which specifies a default locale to use.
- */
- _appendDistroSearchDirs: function(array) {
- let distro = this.getFile(XRE_APP_DISTRIBUTION_DIR);
- if (!distro.exists())
- return;
-
- let searchPlugins = distro.clone();
- searchPlugins.append("searchplugins");
- if (!searchPlugins.exists())
- return;
-
- let commonPlugins = searchPlugins.clone();
- commonPlugins.append("common");
- if (commonPlugins.exists())
- array.push(commonPlugins);
-
- let localePlugins = searchPlugins.clone();
- localePlugins.append("locale");
- if (!localePlugins.exists())
- return;
-
- let curLocale = "";
- try {
- curLocale = Services.prefs.getComplexValue("general.useragent.locale", Ci.nsIPrefLocalizedString).data;
- } catch (e) {
- try {
- curLocale = Services.prefs.getCharPref("general.useragent.locale");
- } catch (ee) {
- }
- }
-
- if (curLocale) {
- let curLocalePlugins = localePlugins.clone();
- curLocalePlugins.append(curLocale);
- if (curLocalePlugins.exists()) {
- array.push(curLocalePlugins);
- return;
- }
- }
-
- // We didn't append the locale dir - try the default one.
- try {
- let defLocale = Services.prefs.getCharPref("distribution.searchplugins.defaultLocale");
- let defLocalePlugins = localePlugins.clone();
- defLocalePlugins.append(defLocale);
- if (defLocalePlugins.exists())
- array.push(defLocalePlugins);
- } catch(e) {
- }
- },
-
- getFiles: function(prop) {
- if (prop != NS_APP_SEARCH_DIR_LIST &&
- prop != NS_APP_DISTRIBUTION_SEARCH_DIR_LIST)
- return null;
-
- let result = [];
-
- if (prop == NS_APP_DISTRIBUTION_SEARCH_DIR_LIST) {
- this._appendDistroSearchDirs(result);
- }
- else {
- /**
- * We want to preserve the following order, since the search service
- * loads engines in first-loaded-wins order.
- * - distro search plugin locations (loaded separately by the search
- * service)
- * - user search plugin locations (profile)
- * - app search plugin location (shipped engines)
- */
- let appUserSearchDir = FileUtils.getDir(NS_APP_USER_SEARCH_DIR, [], false);
- if (appUserSearchDir.exists())
- result.push(appUserSearchDir);
-
- let appSearchDir = FileUtils.getDir(NS_APP_SEARCH_DIR, [], false);
- if (appSearchDir.exists())
- result.push(appSearchDir);
- }
-
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
- hasMoreElements: function() {
- return result.length > 0;
- },
- getNext: function() {
- return result.shift();
- }
- };
- },
-
- _getDistributionDirectories: function() {
- let directories = [];
- let jenv = null;
-
- try {
- jenv = JNI.GetForThread();
-
- let jDistribution = JNI.LoadClass(jenv, "org.mozilla.gecko.distribution.Distribution", {
- static_methods: [
- { name: "getDistributionDirectories", sig: "()[Ljava/lang/String;" }
- ],
- });
-
- let jDirectories = jDistribution.getDistributionDirectories();
-
- for (let i = 0; i < jDirectories.length; i++) {
- directories.push(new FileUtils.File(
- JNI.ReadString(jenv, jDirectories.get(i))
- ));
- }
- } finally {
- if (jenv) {
- JNI.UnloadClasses(jenv);
- }
- }
-
- return directories;
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([DirectoryProvider]);
diff --git a/mobile/android/components/FilePicker.js b/mobile/android/components/FilePicker.js
deleted file mode 100644
index 2de81ca46..000000000
--- a/mobile/android/components/FilePicker.js
+++ /dev/null
@@ -1,302 +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/. */
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cc = Components.classes;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/FileUtils.jsm");
-
-Cu.importGlobalProperties(['File']);
-
-function FilePicker() {
-}
-
-FilePicker.prototype = {
- _mimeTypeFilter: 0,
- _extensionsFilter: "",
- _defaultString: "",
- _domWin: null,
- _defaultExtension: null,
- _displayDirectory: null,
- _filePath: null,
- _promptActive: false,
- _filterIndex: 0,
- _addToRecentDocs: false,
- _title: "",
-
- init: function(aParent, aTitle, aMode) {
- this._domWin = aParent;
- this._mode = aMode;
- this._title = aTitle;
- Services.obs.addObserver(this, "FilePicker:Result", false);
-
- let idService = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
- this.guid = idService.generateUUID().toString();
-
- if (aMode != Ci.nsIFilePicker.modeOpen && aMode != Ci.nsIFilePicker.modeOpenMultiple)
- throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
- },
-
- appendFilters: function(aFilterMask) {
- if (aFilterMask & Ci.nsIFilePicker.filterAudio) {
- this._mimeTypeFilter = "audio/*";
- return;
- }
-
- if (aFilterMask & Ci.nsIFilePicker.filterImages) {
- this._mimeTypeFilter = "image/*";
- return;
- }
-
- if (aFilterMask & Ci.nsIFilePicker.filterVideo) {
- this._mimeTypeFilter = "video/*";
- return;
- }
-
- if (aFilterMask & Ci.nsIFilePicker.filterAll) {
- this._mimeTypeFilter = "*/*";
- return;
- }
-
- /* From BaseFilePicker.cpp */
- if (aFilterMask & Ci.nsIFilePicker.filterHTML) {
- this.appendFilter("*.html; *.htm; *.shtml; *.xhtml");
- }
- if (aFilterMask & Ci.nsIFilePicker.filterText) {
- this.appendFilter("*.txt; *.text");
- }
-
- if (aFilterMask & Ci.nsIFilePicker.filterXML) {
- this.appendFilter("*.xml");
- }
-
- if (aFilterMask & Ci.nsIFilePicker.xulFilter) {
- this.appendFilter("*.xul");
- }
-
- if (aFilterMask & Ci.nsIFilePicker.xulFilter) {
- this.appendFilter("..apps");
- }
- },
-
- appendFilter: function(title, filter) {
- if (this._extensionsFilter)
- this._extensionsFilter += ", ";
- this._extensionsFilter += filter;
- },
-
- get defaultString() {
- return this._defaultString;
- },
-
- set defaultString(defaultString) {
- this._defaultString = defaultString;
- },
-
- get defaultExtension() {
- return this._defaultExtension;
- },
-
- set defaultExtension(defaultExtension) {
- this._defaultExtension = defaultExtension;
- },
-
- get filterIndex() {
- return this._filterIndex;
- },
-
- set filterIndex(val) {
- this._filterIndex = val;
- },
-
- get displayDirectory() {
- return this._displayDirectory;
- },
-
- set displayDirectory(dir) {
- this._displayDirectory = dir;
- },
-
- get file() {
- if (!this._filePath) {
- return null;
- }
-
- return new FileUtils.File(this._filePath);
- },
-
- get fileURL() {
- let file = this.getFile();
- return Services.io.newFileURI(file);
- },
-
- get files() {
- return this.getEnumerator([this.file], function(file) {
- return file;
- });
- },
-
- // We don't support directory selection yet.
- get domFileOrDirectory() {
- let f = this.file;
- if (!f) {
- return null;
- }
-
- let win = this._domWin;
- if (win) {
- let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
- return utils.wrapDOMFile(f);
- }
-
- return File.createFromNsIFile(f);
- },
-
- get domFileOrDirectoryEnumerator() {
- let win = this._domWin;
- return this.getEnumerator([this.file], function(file) {
- if (win) {
- let utils = win.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
- return utils.wrapDOMFile(file);
- }
-
- return File.createFromNsIFile(file);
- });
- },
-
- get addToRecentDocs() {
- return this._addToRecentDocs;
- },
-
- set addToRecentDocs(val) {
- this._addToRecentDocs = val;
- },
-
- get mode() {
- return this._mode;
- },
-
- show: function() {
- if (this._domWin) {
- this.fireDialogEvent(this._domWin, "DOMWillOpenModalDialog");
- let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
- winUtils.enterModalState();
- }
-
- this._promptActive = true;
- this._sendMessage();
-
- let thread = Services.tm.currentThread;
- while (this._promptActive)
- thread.processNextEvent(true);
- delete this._promptActive;
-
- if (this._domWin) {
- let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
- winUtils.leaveModalState();
- this.fireDialogEvent(this._domWin, "DOMModalDialogClosed");
- }
-
- if (this._filePath)
- return Ci.nsIFilePicker.returnOK;
-
- return Ci.nsIFilePicker.returnCancel;
- },
-
- open: function(callback) {
- this._callback = callback;
- this._sendMessage();
- },
-
- _sendMessage: function() {
- let msg = {
- type: "FilePicker:Show",
- guid: this.guid,
- title: this._title,
- };
-
- // Knowing the window lets us destroy any temp files when the tab is closed
- // Other consumers of the file picker may have to either wait for Android
- // to clean up the temp dir (not guaranteed) or clean up after themselves.
- let win = Services.wm.getMostRecentWindow('navigator:browser');
- let tab = win.BrowserApp.getTabForWindow(this._domWin.top)
- if (tab) {
- msg.tabId = tab.id;
- }
-
- if (!this._extensionsFilter && !this._mimeTypeFilter) {
- // If neither filters is set show anything we can.
- msg.mode = "mimeType";
- msg.mimeType = "*/*";
- } else if (this._extensionsFilter) {
- msg.mode = "extension";
- msg.extensions = this._extensionsFilter;
- } else {
- msg.mode = "mimeType";
- msg.mimeType = this._mimeTypeFilter;
- }
-
- this.sendMessageToJava(msg);
- },
-
- sendMessageToJava: function(aMsg) {
- Services.androidBridge.handleGeckoMessage(aMsg);
- },
-
- observe: function(aSubject, aTopic, aData) {
- let data = JSON.parse(aData);
- if (data.guid != this.guid)
- return;
-
- this._filePath = null;
- if (data.file)
- this._filePath = data.file;
-
- this._promptActive = false;
-
- if (this._callback) {
- this._callback.done(this._filePath ? Ci.nsIFilePicker.returnOK : Ci.nsIFilePicker.returnCancel);
- }
- delete this._callback;
- },
-
- getEnumerator: function(files, mapFunction) {
- return {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISimpleEnumerator]),
- mFiles: files,
- mIndex: 0,
- hasMoreElements: function() {
- return (this.mIndex < this.mFiles.length);
- },
- getNext: function() {
- if (this.mIndex >= this.mFiles.length) {
- throw Components.results.NS_ERROR_FAILURE;
- }
- return mapFunction(this.mFiles[this.mIndex++]);
- }
- };
- },
-
- fireDialogEvent: function(aDomWin, aEventName) {
- // accessing the document object can throw if this window no longer exists. See bug 789888.
- try {
- if (!aDomWin.document)
- return;
- let event = aDomWin.document.createEvent("Events");
- event.initEvent(aEventName, true, true);
- let winUtils = aDomWin.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
- winUtils.dispatchEventToChromeOnly(aDomWin, event);
- } catch(ex) {
- }
- },
-
- classID: Components.ID("{18a4e042-7c7c-424b-a583-354e68553a7f}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIFilePicker, Ci.nsIObserver])
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([FilePicker]);
diff --git a/mobile/android/components/HelperAppDialog.js b/mobile/android/components/HelperAppDialog.js
deleted file mode 100644
index f127fb0b3..000000000
--- a/mobile/android/components/HelperAppDialog.js
+++ /dev/null
@@ -1,373 +0,0 @@
-// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
-/* 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/. */
-
-/*globals ContentAreaUtils */
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-const APK_MIME_TYPE = "application/vnd.android.package-archive";
-
-const OMA_DOWNLOAD_DESCRIPTOR_MIME_TYPE = "application/vnd.oma.dd+xml";
-const OMA_DRM_MESSAGE_MIME = "application/vnd.oma.drm.message";
-const OMA_DRM_CONTENT_MIME = "application/vnd.oma.drm.content";
-const OMA_DRM_RIGHTS_MIME = "application/vnd.oma.drm.rights+wbxml";
-
-const PREF_BD_USEDOWNLOADDIR = "browser.download.useDownloadDir";
-const URI_GENERIC_ICON_DOWNLOAD = "drawable://alert_download";
-
-Cu.import("resource://gre/modules/Downloads.jsm");
-Cu.import("resource://gre/modules/FileUtils.jsm");
-Cu.import("resource://gre/modules/HelperApps.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/NetUtil.jsm");
-Cu.import("resource://gre/modules/Task.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "RuntimePermissions", "resource://gre/modules/RuntimePermissions.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Messaging", "resource://gre/modules/Messaging.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Snackbars", "resource://gre/modules/Snackbars.jsm");
-
-// -----------------------------------------------------------------------
-// HelperApp Launcher Dialog
-// -----------------------------------------------------------------------
-
-XPCOMUtils.defineLazyGetter(this, "ContentAreaUtils", function() {
- let ContentAreaUtils = {};
- Services.scriptloader.loadSubScript("chrome://global/content/contentAreaUtils.js", ContentAreaUtils);
- return ContentAreaUtils;
-});
-
-function HelperAppLauncherDialog() { }
-
-HelperAppLauncherDialog.prototype = {
- classID: Components.ID("{e9d277a0-268a-4ec2-bb8c-10fdf3e44611}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog]),
-
- /**
- * Returns false if `url` represents a local or special URL that we don't
- * wish to ever download.
- *
- * Returns true otherwise.
- */
- _canDownload: function (url, alreadyResolved=false) {
- // The common case.
- if (url.schemeIs("http") ||
- url.schemeIs("https") ||
- url.schemeIs("ftp")) {
- return true;
- }
-
- // The less-common opposite case.
- if (url.schemeIs("chrome") ||
- url.schemeIs("jar") ||
- url.schemeIs("resource") ||
- url.schemeIs("wyciwyg") ||
- url.schemeIs("file")) {
- return false;
- }
-
- // For all other URIs, try to resolve them to an inner URI, and check that.
- if (!alreadyResolved) {
- let innerURI = NetUtil.newChannel({
- uri: url,
- loadUsingSystemPrincipal: true
- }).URI;
-
- if (!url.equals(innerURI)) {
- return this._canDownload(innerURI, true);
- }
- }
-
- // Anything else is fine to download.
- return true;
- },
-
- /**
- * Returns true if `launcher` represents a download for which we wish
- * to prompt.
- */
- _shouldPrompt: function (launcher) {
- let mimeType = this._getMimeTypeFromLauncher(launcher);
-
- // Straight equality: nsIMIMEInfo normalizes.
- return APK_MIME_TYPE == mimeType || OMA_DOWNLOAD_DESCRIPTOR_MIME_TYPE == mimeType;
- },
-
- /**
- * Returns true if `launcher` represents a download for which we wish to
- * offer a "Save to disk" option.
- */
- _shouldAddSaveToDiskIntent: function(launcher) {
- let mimeType = this._getMimeTypeFromLauncher(launcher);
-
- // We can't handle OMA downloads. So don't even try. (Bug 1219078)
- return mimeType != OMA_DOWNLOAD_DESCRIPTOR_MIME_TYPE;
- },
-
- /**
- * Returns true if `launcher`represents a download that should not be handled by Firefox
- * or a third-party app and instead be forwarded to Android's download manager.
- */
- _shouldForwardToAndroidDownloadManager: function(aLauncher) {
- let forwardDownload = Services.prefs.getBoolPref('browser.download.forward_oma_android_download_manager');
- if (!forwardDownload) {
- return false;
- }
-
- let mimeType = aLauncher.MIMEInfo.MIMEType;
- if (!mimeType) {
- mimeType = ContentAreaUtils.getMIMETypeForURI(aLauncher.source) || "";
- }
-
- return [
- OMA_DOWNLOAD_DESCRIPTOR_MIME_TYPE,
- OMA_DRM_MESSAGE_MIME,
- OMA_DRM_CONTENT_MIME,
- OMA_DRM_RIGHTS_MIME
- ].indexOf(mimeType) != -1;
- },
-
- show: function hald_show(aLauncher, aContext, aReason) {
- if (!this._canDownload(aLauncher.source)) {
- this._refuseDownload(aLauncher);
- return;
- }
-
- if (this._shouldForwardToAndroidDownloadManager(aLauncher)) {
- Task.spawn(function* () {
- try {
- let hasPermission = yield RuntimePermissions.waitForPermissions(RuntimePermissions.WRITE_EXTERNAL_STORAGE);
- if (hasPermission) {
- this._downloadWithAndroidDownloadManager(aLauncher);
- aLauncher.cancel(Cr.NS_BINDING_ABORTED);
- }
- } finally {
- }
- }.bind(this)).catch(Cu.reportError);
- return;
- }
-
- let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
-
- let defaultHandler = new Object();
- let apps = HelperApps.getAppsForUri(aLauncher.source, {
- mimeType: aLauncher.MIMEInfo.MIMEType,
- });
-
- if (this._shouldAddSaveToDiskIntent(aLauncher)) {
- // Add a fake intent for save to disk at the top of the list.
- apps.unshift({
- name: bundle.GetStringFromName("helperapps.saveToDisk"),
- packageName: "org.mozilla.gecko.Download",
- iconUri: "drawable://icon",
- selected: true, // Default to download for files
- launch: function() {
- // Reset the preferredAction here.
- aLauncher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.saveToDisk;
- aLauncher.saveToDisk(null, false);
- return true;
- }
- });
- }
-
- // We do not handle this download and there are no apps that want to do it
- if (apps.length === 0) {
- this._refuseDownload(aLauncher);
- return;
- }
-
- let callback = function(app) {
- aLauncher.MIMEInfo.preferredAction = Ci.nsIMIMEInfo.useHelperApp;
- if (!app.launch(aLauncher.source)) {
- // Once the app is done we need to get rid of the temp file. This shouldn't
- // get run in the saveToDisk case.
- aLauncher.cancel(Cr.NS_BINDING_ABORTED);
- }
- }
-
- // See if the user already marked something as the default for this mimetype,
- // and if that app is still installed.
- let preferredApp = this._getPreferredApp(aLauncher);
- if (preferredApp) {
- let pref = apps.filter(function(app) {
- return app.packageName === preferredApp;
- });
-
- if (pref.length > 0) {
- callback(pref[0]);
- return;
- }
- }
-
- // If there's only one choice, and we don't want to prompt, go right ahead
- // and choose that app automatically.
- if (!this._shouldPrompt(aLauncher) && (apps.length === 1)) {
- callback(apps[0]);
- return;
- }
-
- // Otherwise, let's go through the prompt.
- HelperApps.prompt(apps, {
- title: bundle.GetStringFromName("helperapps.pick"),
- buttons: [
- bundle.GetStringFromName("helperapps.alwaysUse"),
- bundle.GetStringFromName("helperapps.useJustOnce")
- ],
- // Tapping an app twice should choose "Just once".
- doubleTapButton: 1
- }, (data) => {
- if (data.button < 0) {
- return;
- }
-
- callback(apps[data.icongrid0]);
-
- if (data.button === 0) {
- this._setPreferredApp(aLauncher, apps[data.icongrid0]);
- }
- });
- },
-
- _refuseDownload: function(aLauncher) {
- aLauncher.cancel(Cr.NS_BINDING_ABORTED);
-
- Services.console.logStringMessage("Refusing download of non-downloadable file.");
-
- let bundle = Services.strings.createBundle("chrome://browser/locale/handling.properties");
- let failedText = bundle.GetStringFromName("download.blocked");
-
- Snackbars.show(failedText, Snackbars.LENGTH_LONG);
- },
-
- _downloadWithAndroidDownloadManager(aLauncher) {
- let mimeType = aLauncher.MIMEInfo.MIMEType;
- if (!mimeType) {
- mimeType = ContentAreaUtils.getMIMETypeForURI(aLauncher.source) || "";
- }
-
- Messaging.sendRequest({
- 'type': 'Download:AndroidDownloadManager',
- 'uri': aLauncher.source.spec,
- 'mimeType': mimeType,
- 'filename': aLauncher.suggestedFileName
- });
- },
-
- _getPrefName: function getPrefName(mimetype) {
- return "browser.download.preferred." + mimetype.replace("\\", ".");
- },
-
- _getMimeTypeFromLauncher: function (launcher) {
- let mime = launcher.MIMEInfo.MIMEType;
- if (!mime)
- mime = ContentAreaUtils.getMIMETypeForURI(launcher.source) || "";
- return mime;
- },
-
- _getPreferredApp: function getPreferredApp(launcher) {
- let mime = this._getMimeTypeFromLauncher(launcher);
- if (!mime)
- return;
-
- try {
- return Services.prefs.getCharPref(this._getPrefName(mime));
- } catch(ex) {
- Services.console.logStringMessage("Error getting pref for " + mime + ".");
- }
- return null;
- },
-
- _setPreferredApp: function setPreferredApp(launcher, app) {
- let mime = this._getMimeTypeFromLauncher(launcher);
- if (!mime)
- return;
-
- if (app)
- Services.prefs.setCharPref(this._getPrefName(mime), app.packageName);
- else
- Services.prefs.clearUserPref(this._getPrefName(mime));
- },
-
- promptForSaveToFileAsync: function (aLauncher, aContext, aDefaultFile,
- aSuggestedFileExt, aForcePrompt) {
- Task.spawn(function* () {
- let file = null;
- try {
- let hasPermission = yield RuntimePermissions.waitForPermissions(RuntimePermissions.WRITE_EXTERNAL_STORAGE);
- if (hasPermission) {
- // If we do have the STORAGE permission then pick the public downloads directory as destination
- // for this file. Without the permission saveDestinationAvailable(null) will be called which
- // will effectively cancel the download.
- let preferredDir = yield Downloads.getPreferredDownloadsDirectory();
- file = this.validateLeafName(new FileUtils.File(preferredDir),
- aDefaultFile, aSuggestedFileExt);
- }
- } finally {
- // The file argument will be null in case any exception occurred.
- aLauncher.saveDestinationAvailable(file);
- }
- }.bind(this)).catch(Cu.reportError);
- },
-
- validateLeafName: function hald_validateLeafName(aLocalFile, aLeafName, aFileExt) {
- if (!(aLocalFile && this.isUsableDirectory(aLocalFile)))
- return null;
-
- // Remove any leading periods, since we don't want to save hidden files
- // automatically.
- aLeafName = aLeafName.replace(/^\.+/, "");
-
- if (aLeafName == "")
- aLeafName = "unnamed" + (aFileExt ? "." + aFileExt : "");
- aLocalFile.append(aLeafName);
-
- this.makeFileUnique(aLocalFile);
- return aLocalFile;
- },
-
- makeFileUnique: function hald_makeFileUnique(aLocalFile) {
- try {
- // Note - this code is identical to that in
- // toolkit/content/contentAreaUtils.js.
- // If you are updating this code, update that code too! We can't share code
- // here since this is called in a js component.
- let collisionCount = 0;
- while (aLocalFile.exists()) {
- collisionCount++;
- if (collisionCount == 1) {
- // Append "(2)" before the last dot in (or at the end of) the filename
- // special case .ext.gz etc files so we don't wind up with .tar(2).gz
- if (aLocalFile.leafName.match(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i))
- aLocalFile.leafName = aLocalFile.leafName.replace(/\.[^\.]{1,3}\.(gz|bz2|Z)$/i, "(2)$&");
- else
- aLocalFile.leafName = aLocalFile.leafName.replace(/(\.[^\.]*)?$/, "(2)$&");
- }
- else {
- // replace the last (n) in the filename with (n+1)
- aLocalFile.leafName = aLocalFile.leafName.replace(/^(.*\()\d+\)/, "$1" + (collisionCount+1) + ")");
- }
- }
- aLocalFile.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
- }
- catch (e) {
- dump("*** exception in validateLeafName: " + e + "\n");
-
- if (e.result == Cr.NS_ERROR_FILE_ACCESS_DENIED)
- throw e;
-
- if (aLocalFile.leafName == "" || aLocalFile.isDirectory()) {
- aLocalFile.append("unnamed");
- if (aLocalFile.exists())
- aLocalFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600);
- }
- }
- },
-
- isUsableDirectory: function hald_isUsableDirectory(aDirectory) {
- return aDirectory.exists() && aDirectory.isDirectory() && aDirectory.isWritable();
- },
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([HelperAppLauncherDialog]);
diff --git a/mobile/android/components/ImageBlockingPolicy.js b/mobile/android/components/ImageBlockingPolicy.js
deleted file mode 100644
index 2444bda06..000000000
--- a/mobile/android/components/ImageBlockingPolicy.js
+++ /dev/null
@@ -1,125 +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/. */
-
-const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Timer.jsm");
-
-////////////////////////////////////////////////////////////////////////////////
-//// Constants
-
-//// SVG placeholder image for blocked image content
-const PLACEHOLDER_IMG = "chrome://browser/skin/images/placeholder_image.svg";
-
-//// Telemetry
-const TELEMETRY_TAP_TO_LOAD_ENABLED = "TAP_TO_LOAD_ENABLED";
-const TELEMETRY_SHOW_IMAGE_SIZE = "TAP_TO_LOAD_IMAGE_SIZE";
-const TOPIC_GATHER_TELEMETRY = "gather-telemetry";
-
-//// Gecko preference
-const PREF_IMAGEBLOCKING = "browser.image_blocking";
-
-//// Enabled options
-const OPTION_NEVER = 0;
-const OPTION_ALWAYS = 1;
-const OPTION_WIFI_ONLY = 2;
-
-
-/**
- * Content policy for blocking images
- */
-function ImageBlockingPolicy() {
- Services.obs.addObserver(this, TOPIC_GATHER_TELEMETRY, false);
-}
-
-ImageBlockingPolicy.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPolicy, Ci.nsIObserver]),
- classDescription: "Click-To-Play Image",
- classID: Components.ID("{f55f77f9-d33d-4759-82fc-60db3ee0bb91}"),
- contractID: "@mozilla.org/browser/blockimages-policy;1",
- xpcom_categories: [{category: "content-policy", service: true}],
-
- // nsIContentPolicy interface implementation
- shouldLoad: function(contentType, contentLocation, requestOrigin, node, mimeTypeGuess, extra) {
- // When enabled or when on cellular, and option for cellular-only is selected
- if (this._enabled() == OPTION_NEVER || (this._enabled() == OPTION_WIFI_ONLY && this._usingCellular())) {
- if (contentType === Ci.nsIContentPolicy.TYPE_IMAGE || contentType === Ci.nsIContentPolicy.TYPE_IMAGESET) {
- // Accept any non-http(s) image URLs
- if (!contentLocation.schemeIs("http") && !contentLocation.schemeIs("https")) {
- return Ci.nsIContentPolicy.ACCEPT;
- }
-
- if (node instanceof Ci.nsIDOMHTMLImageElement) {
- // Accept if the user has asked to view the image
- if (node.getAttribute("data-ctv-show") == "true") {
- sendImageSizeTelemetry(node.getAttribute("data-ctv-src"));
- return Ci.nsIContentPolicy.ACCEPT;
- }
-
- setTimeout(() => {
- // Cache the original image URL and swap in our placeholder
- node.setAttribute("data-ctv-src", contentLocation.spec);
- node.setAttribute("src", PLACEHOLDER_IMG);
-
- // For imageset (img + srcset) the "srcset" is used even after we reset the "src" causing a loop.
- // We are given the final image URL anyway, so it's OK to just remove the "srcset" value.
- node.removeAttribute("srcset");
- }, 0);
- }
-
- // Reject any image that is not associated with a DOM element
- return Ci.nsIContentPolicy.REJECT;
- }
- }
-
- // Accept all other content types
- return Ci.nsIContentPolicy.ACCEPT;
- },
-
- shouldProcess: function(contentType, contentLocation, requestOrigin, node, mimeTypeGuess, extra) {
- return Ci.nsIContentPolicy.ACCEPT;
- },
-
- _usingCellular: function() {
- let network = Cc["@mozilla.org/network/network-link-service;1"].getService(Ci.nsINetworkLinkService);
- return !(network.linkType == Ci.nsINetworkLinkService.LINK_TYPE_UNKNOWN ||
- network.linkType == Ci.nsINetworkLinkService.LINK_TYPE_ETHERNET ||
- network.linkType == Ci.nsINetworkLinkService.LINK_TYPE_USB ||
- network.linkType == Ci.nsINetworkLinkService.LINK_TYPE_WIFI);
- },
-
- _enabled: function() {
- return Services.prefs.getIntPref(PREF_IMAGEBLOCKING);
- },
-
- observe : function (subject, topic, data) {
- if (topic == TOPIC_GATHER_TELEMETRY) {
- Services.telemetry.getHistogramById(TELEMETRY_TAP_TO_LOAD_ENABLED).add(this._enabled());
- }
- },
-};
-
-function sendImageSizeTelemetry(imageURL) {
- let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
- xhr.open("HEAD", imageURL, true);
- xhr.onreadystatechange = function (e) {
- if (xhr.readyState != 4) {
- return;
- }
- if (xhr.status != 200) {
- return;
- }
- let contentLength = xhr.getResponseHeader("Content-Length");
- if (!contentLength) {
- return;
- }
- let imageSize = contentLength / 1024;
- Services.telemetry.getHistogramById(TELEMETRY_SHOW_IMAGE_SIZE).add(imageSize);
- };
- xhr.send(null);
-}
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ImageBlockingPolicy]);
diff --git a/mobile/android/components/LoginManagerPrompter.js b/mobile/android/components/LoginManagerPrompter.js
deleted file mode 100644
index e70afbe14..000000000
--- a/mobile/android/components/LoginManagerPrompter.js
+++ /dev/null
@@ -1,413 +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/. */
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cr = Components.results;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-/* Constants for password prompt telemetry.
-* Mirrored in nsLoginManagerPrompter.js */
-const PROMPT_DISPLAYED = 0;
-
-const PROMPT_ADD = 1;
-const PROMPT_NOTNOW = 2;
-const PROMPT_NEVER = 3;
-
-const PROMPT_UPDATE = 1;
-
-/* ==================== LoginManagerPrompter ==================== */
-/*
- * LoginManagerPrompter
- *
- * Implements interfaces for prompting the user to enter/save/change auth info.
- *
- * nsILoginManagerPrompter: Used by Login Manager for saving/changing logins
- * found in HTML forms.
- */
-function LoginManagerPrompter() {
-}
-
-LoginManagerPrompter.prototype = {
- classID : Components.ID("97d12931-abe2-11df-94e2-0800200c9a66"),
- QueryInterface : XPCOMUtils.generateQI([Ci.nsILoginManagerPrompter]),
-
- _factory : null,
- _window : null,
- _debug : false, // mirrors signon.debug
-
- __pwmgr : null, // Password Manager service
- get _pwmgr() {
- if (!this.__pwmgr)
- this.__pwmgr = Cc["@mozilla.org/login-manager;1"].
- getService(Ci.nsILoginManager);
- return this.__pwmgr;
- },
-
- __promptService : null, // Prompt service for user interaction
- get _promptService() {
- if (!this.__promptService)
- this.__promptService = Cc["@mozilla.org/embedcomp/prompt-service;1"].
- getService(Ci.nsIPromptService2);
- return this.__promptService;
- },
-
- __strBundle : null, // String bundle for L10N
- get _strBundle() {
- if (!this.__strBundle) {
- let bunService = Cc["@mozilla.org/intl/stringbundle;1"].
- getService(Ci.nsIStringBundleService);
- this.__strBundle = {
- pwmgr : bunService.createBundle("chrome://passwordmgr/locale/passwordmgr.properties"),
- brand : bunService.createBundle("chrome://branding/locale/brand.properties")
- };
-
- if (!this.__strBundle)
- throw "String bundle for Login Manager not present!";
- }
-
- return this.__strBundle;
- },
-
- __ellipsis : null,
- get _ellipsis() {
- if (!this.__ellipsis) {
- this.__ellipsis = "\u2026";
- try {
- this.__ellipsis = Services.prefs.getComplexValue(
- "intl.ellipsis", Ci.nsIPrefLocalizedString).data;
- } catch (e) { }
- }
- return this.__ellipsis;
- },
-
- /*
- * log
- *
- * Internal function for logging debug messages to the Error Console window.
- */
- log : function (message) {
- if (!this._debug)
- return;
-
- dump("Pwmgr Prompter: " + message + "\n");
- Services.console.logStringMessage("Pwmgr Prompter: " + message);
- },
-
- /* ---------- nsILoginManagerPrompter prompts ---------- */
-
- /*
- * init
- *
- */
- init : function (aWindow, aFactory) {
- this._chromeWindow = this._getChromeWindow(aWindow).wrappedJSObject;
- this._factory = aFactory || null;
- this._browser = null;
-
- var prefBranch = Services.prefs.getBranch("signon.");
- this._debug = prefBranch.getBoolPref("debug");
- this.log("===== initialized =====");
- },
-
- set browser(aBrowser) {
- this._browser = aBrowser;
- },
-
- // setting this attribute is ignored because Android does not consider
- // opener windows when displaying login notifications
- set opener(aOpener) { },
-
- /*
- * promptToSavePassword
- *
- */
- promptToSavePassword : function (aLogin) {
- this._showSaveLoginNotification(aLogin);
- Services.telemetry.getHistogramById("PWMGR_PROMPT_REMEMBER_ACTION").add(PROMPT_DISPLAYED);
- Services.obs.notifyObservers(aLogin, "passwordmgr-prompt-save", null);
- },
-
- /*
- * _showLoginNotification
- *
- * Displays a notification doorhanger.
- * @param aBody
- * String message to be displayed in the doorhanger
- * @param aButtons
- * Buttons to display with the doorhanger
- * @param aUsername
- * Username string used in creating a doorhanger action
- * @param aPassword
- * Password string used in creating a doorhanger action
- */
- _showLoginNotification : function (aBody, aButtons, aUsername, aPassword) {
- let tabID = this._chromeWindow.BrowserApp.getTabForBrowser(this._browser).id;
-
- let actionText = {
- text: aUsername,
- type: "EDIT",
- bundle: { username: aUsername,
- password: aPassword }
- };
-
- // The page we're going to hasn't loaded yet, so we want to persist
- // across the first location change.
-
- // Sites like Gmail perform a funky redirect dance before you end up
- // at the post-authentication page. I don't see a good way to
- // heuristically determine when to ignore such location changes, so
- // we'll try ignoring location changes based on a time interval.
- let options = {
- persistWhileVisible: true,
- timeout: Date.now() + 10000,
- actionText: actionText
- }
-
- var nativeWindow = this._getNativeWindow();
- if (nativeWindow)
- nativeWindow.doorhanger.show(aBody, "password", aButtons, tabID, options, "LOGIN");
- },
-
- /*
- * _showSaveLoginNotification
- *
- * Displays a notification doorhanger (rather than a popup), to allow the user to
- * save the specified login. This allows the user to see the results of
- * their login, and only save a login which they know worked.
- *
- */
- _showSaveLoginNotification : function (aLogin) {
- let brandShortName = this._strBundle.brand.GetStringFromName("brandShortName");
- let notificationText = this._getLocalizedString("saveLogin", [brandShortName]);
-
- let username = aLogin.username ? this._sanitizeUsername(aLogin.username) : "";
-
- // The callbacks in |buttons| have a closure to access the variables
- // in scope here; set one to |this._pwmgr| so we can get back to pwmgr
- // without a getService() call.
- var pwmgr = this._pwmgr;
- let promptHistogram = Services.telemetry.getHistogramById("PWMGR_PROMPT_REMEMBER_ACTION");
-
- var buttons = [
- {
- label: this._getLocalizedString("neverButton"),
- callback: function() {
- promptHistogram.add(PROMPT_NEVER);
- pwmgr.setLoginSavingEnabled(aLogin.hostname, false);
- }
- },
- {
- label: this._getLocalizedString("rememberButton"),
- callback: function(checked, response) {
- if (response) {
- aLogin.username = response["username"] || aLogin.username;
- aLogin.password = response["password"] || aLogin.password;
- }
- pwmgr.addLogin(aLogin);
- promptHistogram.add(PROMPT_ADD);
- },
- positive: true
- }
- ];
-
- this._showLoginNotification(notificationText, buttons, aLogin.username, aLogin.password);
- },
-
- /*
- * promptToChangePassword
- *
- * Called when we think we detect a password change for an existing
- * login, when the form being submitted contains multiple password
- * fields.
- *
- */
- promptToChangePassword : function (aOldLogin, aNewLogin) {
- this._showChangeLoginNotification(aOldLogin, aNewLogin.password);
- Services.telemetry.getHistogramById("PWMGR_PROMPT_UPDATE_ACTION").add(PROMPT_DISPLAYED);
- let oldGUID = aOldLogin.QueryInterface(Ci.nsILoginMetaInfo).guid;
- Services.obs.notifyObservers(aNewLogin, "passwordmgr-prompt-change", oldGUID);
- },
-
- /*
- * _showChangeLoginNotification
- *
- * Shows the Change Password notification doorhanger.
- *
- */
- _showChangeLoginNotification : function (aOldLogin, aNewPassword) {
- var notificationText;
- if (aOldLogin.username) {
- let displayUser = this._sanitizeUsername(aOldLogin.username);
- notificationText = this._getLocalizedString("updatePassword", [displayUser]);
- } else {
- notificationText = this._getLocalizedString("updatePasswordNoUser");
- }
-
- // The callbacks in |buttons| have a closure to access the variables
- // in scope here; set one to |this._pwmgr| so we can get back to pwmgr
- // without a getService() call.
- var self = this;
- let promptHistogram = Services.telemetry.getHistogramById("PWMGR_PROMPT_UPDATE_ACTION");
-
- var buttons = [
- {
- label: this._getLocalizedString("dontUpdateButton"),
- callback: function() {
- promptHistogram.add(PROMPT_NOTNOW);
- // do nothing
- }
- },
- {
- label: this._getLocalizedString("updateButton"),
- callback: function(checked, response) {
- let password = response ? response["password"] : aNewPassword;
- self._updateLogin(aOldLogin, password);
-
- promptHistogram.add(PROMPT_UPDATE);
- },
- positive: true
- }
- ];
-
- this._showLoginNotification(notificationText, buttons, aOldLogin.username, aNewPassword);
- },
-
- /*
- * promptToChangePasswordWithUsernames
- *
- * Called when we detect a password change in a form submission, but we
- * don't know which existing login (username) it's for. Asks the user
- * to select a username and confirm the password change.
- *
- * Note: The caller doesn't know the username for aNewLogin, so this
- * function fills in .username and .usernameField with the values
- * from the login selected by the user.
- *
- * Note; XPCOM stupidity: |count| is just |logins.length|.
- */
- promptToChangePasswordWithUsernames : function (logins, count, aNewLogin) {
- const buttonFlags = Ci.nsIPrompt.STD_YES_NO_BUTTONS;
-
- var usernames = logins.map(l => l.username);
- var dialogText = this._getLocalizedString("userSelectText");
- var dialogTitle = this._getLocalizedString("passwordChangeTitle");
- var selectedIndex = { value: null };
-
- // If user selects ok, outparam.value is set to the index
- // of the selected username.
- var ok = this._promptService.select(null,
- dialogTitle, dialogText,
- usernames.length, usernames,
- selectedIndex);
- if (ok) {
- // Now that we know which login to use, modify its password.
- let selectedLogin = logins[selectedIndex.value];
- this.log("Updating password for user " + selectedLogin.username);
- this._updateLogin(selectedLogin, aNewLogin.password);
- }
- },
-
- /* ---------- Internal Methods ---------- */
-
- /*
- * _updateLogin
- */
- _updateLogin : function (login, newPassword) {
- var now = Date.now();
- var propBag = Cc["@mozilla.org/hash-property-bag;1"].
- createInstance(Ci.nsIWritablePropertyBag);
- if (newPassword) {
- propBag.setProperty("password", newPassword);
- // Explicitly set the password change time here (even though it would
- // be changed automatically), to ensure that it's exactly the same
- // value as timeLastUsed.
- propBag.setProperty("timePasswordChanged", now);
- }
- propBag.setProperty("timeLastUsed", now);
- propBag.setProperty("timesUsedIncrement", 1);
- this._pwmgr.modifyLogin(login, propBag);
- },
-
- /*
- * _getChromeWindow
- *
- * Given a content DOM window, returns the chrome window it's in.
- */
- _getChromeWindow: function (aWindow) {
- if (aWindow instanceof Ci.nsIDOMChromeWindow)
- return aWindow;
- var chromeWin = aWindow.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIWebNavigation)
- .QueryInterface(Ci.nsIDocShell)
- .chromeEventHandler.ownerDocument.defaultView;
- return chromeWin;
- },
-
- /*
- * _getNativeWindow
- *
- * Returns the NativeWindow to this prompter, or null if there isn't
- * a NativeWindow available (w/ error sent to logcat).
- */
- _getNativeWindow : function () {
- let nativeWindow = null;
- try {
- let chromeWin = this._chromeWindow;
- if (chromeWin.NativeWindow) {
- nativeWindow = chromeWin.NativeWindow;
- } else {
- Cu.reportError("NativeWindow not available on window");
- }
-
- } catch (e) {
- // If any errors happen, just assume no native window helper.
- Cu.reportError("No NativeWindow available: " + e);
- }
- return nativeWindow;
- },
-
- /*
- * _getLocalizedString
- *
- * Can be called as:
- * _getLocalizedString("key1");
- * _getLocalizedString("key2", ["arg1"]);
- * _getLocalizedString("key3", ["arg1", "arg2"]);
- * (etc)
- *
- * Returns the localized string for the specified key,
- * formatted if required.
- *
- */
- _getLocalizedString : function (key, formatArgs) {
- if (formatArgs)
- return this._strBundle.pwmgr.formatStringFromName(
- key, formatArgs, formatArgs.length);
- else
- return this._strBundle.pwmgr.GetStringFromName(key);
- },
-
- /*
- * _sanitizeUsername
- *
- * Sanitizes the specified username, by stripping quotes and truncating if
- * it's too long. This helps prevent an evil site from messing with the
- * "save password?" prompt too much.
- */
- _sanitizeUsername : function (username) {
- if (username.length > 30) {
- username = username.substring(0, 30);
- username += this._ellipsis;
- }
- return username.replace(/['"]/g, "");
- },
-}; // end of LoginManagerPrompter implementation
-
-
-var component = [LoginManagerPrompter];
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory(component);
diff --git a/mobile/android/components/MobileComponents.manifest b/mobile/android/components/MobileComponents.manifest
deleted file mode 100644
index fe5deb95f..000000000
--- a/mobile/android/components/MobileComponents.manifest
+++ /dev/null
@@ -1,123 +0,0 @@
-# AboutRedirector.js
-component {322ba47e-7047-4f71-aebf-cb7d69325cd9} AboutRedirector.js
-contract @mozilla.org/network/protocol/about;1?what= {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=fennec {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=firefox {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=empty {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=rights {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=certerror {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=home {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=downloads {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=reader {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=feedback {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=privatebrowsing {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-#ifdef MOZ_SERVICES_HEALTHREPORT
-contract @mozilla.org/network/protocol/about;1?what=healthreport {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-#endif
-#ifdef MOZ_SAFE_BROWSING
-contract @mozilla.org/network/protocol/about;1?what=blocked {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-#endif
-contract @mozilla.org/network/protocol/about;1?what=accounts {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-contract @mozilla.org/network/protocol/about;1?what=logins {322ba47e-7047-4f71-aebf-cb7d69325cd9}
-
-# DirectoryProvider.js
-component {ef0f7a87-c1ee-45a8-8d67-26f586e46a4b} DirectoryProvider.js
-contract @mozilla.org/browser/directory-provider;1 {ef0f7a87-c1ee-45a8-8d67-26f586e46a4b}
-category xpcom-directory-providers browser-directory-provider @mozilla.org/browser/directory-provider;1
-
-# stylesheets
-category agent-style-sheets browser-content-stylesheet chrome://browser/skin/content.css
-
-# SessionStore.js
-component {8c1f07d6-cba3-4226-a315-8bd43d67d032} SessionStore.js
-contract @mozilla.org/browser/sessionstore;1 {8c1f07d6-cba3-4226-a315-8bd43d67d032}
-category app-startup SessionStore service,@mozilla.org/browser/sessionstore;1
-
-# ContentPermissionPrompt.js
-component {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5} ContentPermissionPrompt.js
-contract @mozilla.org/content-permission/prompt;1 {C6E8C44D-9F39-4AF7-BCC0-76E38A8310F5}
-
-# PromptService.js
-component {9a61149b-2276-4a0a-b79c-be994ad106cf} PromptService.js
-contract @mozilla.org/prompter;1 {9a61149b-2276-4a0a-b79c-be994ad106cf}
-contract @mozilla.org/embedcomp/prompt-service;1 {9a61149b-2276-4a0a-b79c-be994ad106cf}
-component {80dae1e9-e0d2-4974-915f-f97050fa8068} PromptService.js
-contract @mozilla.org/network/authprompt-adapter-factory;1 {80dae1e9-e0d2-4974-915f-f97050fa8068}
-
-# PresentationDevicePrompt.js
-component {388bd149-c919-4a43-b646-d7ec57877689} PresentationDevicePrompt.js
-contract @mozilla.org/presentation-device/prompt;1 {388bd149-c919-4a43-b646-d7ec57877689}
-
-# PresentationRequestUIGlue.js
-component {9c550ef7-3ff6-4bd1-9ad1-5a3735b90d21} PresentationRequestUIGlue.js
-contract @mozilla.org/presentation/requestuiglue;1 {9c550ef7-3ff6-4bd1-9ad1-5a3735b90d21}
-
-# ImageBlockingPolicy.js
-component {f55f77f9-d33d-4759-82fc-60db3ee0bb91} ImageBlockingPolicy.js
-contract @mozilla.org/browser/blockimages-policy;1 {f55f77f9-d33d-4759-82fc-60db3ee0bb91}
-category content-policy ImageBlockingPolicy @mozilla.org/browser/blockimages-policy;1
-
-# XPIDialogService.js
-component {c1242012-27d8-477e-a0f1-0b098ffc329b} XPIDialogService.js
-contract @mozilla.org/addons/web-install-prompt;1 {c1242012-27d8-477e-a0f1-0b098ffc329b}
-
-# HelperAppDialog.js
-component {e9d277a0-268a-4ec2-bb8c-10fdf3e44611} HelperAppDialog.js
-contract @mozilla.org/helperapplauncherdialog;1 {e9d277a0-268a-4ec2-bb8c-10fdf3e44611}
-
-# BrowserCLH.js
-component {be623d20-d305-11de-8a39-0800200c9a66} BrowserCLH.js application={aa3c5121-dab2-40e2-81ca-7ea25febc110}
-contract @mozilla.org/browser/browser-clh;1 {be623d20-d305-11de-8a39-0800200c9a66}
-category app-startup BrowserCLH @mozilla.org/browser/browser-clh;1
-
-# ContentDispatchChooser.js
-component {5a072a22-1e66-4100-afc1-07aed8b62fc5} ContentDispatchChooser.js
-contract @mozilla.org/content-dispatch-chooser;1 {5a072a22-1e66-4100-afc1-07aed8b62fc5}
-
-# AddonUpdateService.js
-component {93c8824c-9b87-45ae-bc90-5b82a1e4d877} AddonUpdateService.js
-contract @mozilla.org/browser/addon-update-service;1 {93c8824c-9b87-45ae-bc90-5b82a1e4d877}
-category update-timer AddonUpdateService @mozilla.org/browser/addon-update-service;1,getService,auto-addon-background-update-timer,extensions.autoupdate.interval,86400
-
-# LoginManagerPrompter.js
-component {97d12931-abe2-11df-94e2-0800200c9a66} LoginManagerPrompter.js
-contract @mozilla.org/login-manager/prompter;1 {97d12931-abe2-11df-94e2-0800200c9a66}
-
-# BlocklistPrompt.js
-component {4e6ea350-b09a-11df-94e2-0800200c9a66} BlocklistPrompt.js
-contract @mozilla.org/addons/blocklist-prompt;1 {4e6ea350-b09a-11df-94e2-0800200c9a66}
-
-# NSSDialogService.js
-component {cbc08081-49b6-4561-9c18-a7707a50bda1} NSSDialogService.js
-contract @mozilla.org/nsCertificateDialogs;1 {cbc08081-49b6-4561-9c18-a7707a50bda1}
-contract @mozilla.org/nsClientAuthDialogs;1 {cbc08081-49b6-4561-9c18-a7707a50bda1}
-
-# SiteSpecificUserAgent.js
-component {d5234c9d-0ee2-4b3c-9da3-18be9e5cf7e6} SiteSpecificUserAgent.js
-contract @mozilla.org/dom/site-specific-user-agent;1 {d5234c9d-0ee2-4b3c-9da3-18be9e5cf7e6}
-
-# FilePicker.js
-component {18a4e042-7c7c-424b-a583-354e68553a7f} FilePicker.js
-contract @mozilla.org/filepicker;1 {18a4e042-7c7c-424b-a583-354e68553a7f}
-
-#ifndef RELEASE_OR_BETA
-# TabSource.js
-component {5850c76e-b916-4218-b99a-31f004e0a7e7} TabSource.js
-contract @mozilla.org/tab-source-service;1 {5850c76e-b916-4218-b99a-31f004e0a7e7}
-#endif
-
-# Snippets.js
-component {a78d7e59-b558-4321-a3d6-dffe2f1e76dd} Snippets.js
-contract @mozilla.org/snippets;1 {a78d7e59-b558-4321-a3d6-dffe2f1e76dd}
-category browser-delayed-startup-finished Snippets @mozilla.org/snippets;1
-category update-timer Snippets @mozilla.org/snippets;1,getService,snippets-update-timer,browser.snippets.updateInterval,86400
-
-# ColorPicker.js
-component {430b987f-bb9f-46a3-99a5-241749220b29} ColorPicker.js
-contract @mozilla.org/colorpicker;1 {430b987f-bb9f-46a3-99a5-241749220b29}
-
-# PersistentNotificationHandler.js
-component {75390fe7-f8a3-423a-b3b1-258d7eabed40} PersistentNotificationHandler.js
-contract @mozilla.org/persistent-notification-handler;1 {75390fe7-f8a3-423a-b3b1-258d7eabed40}
-category persistent-notification-click PersistentNotificationHandler @mozilla.org/persistent-notification-handler;1
-category persistent-notification-close PersistentNotificationHandler @mozilla.org/persistent-notification-handler;1
diff --git a/mobile/android/components/NSSDialogService.js b/mobile/android/components/NSSDialogService.js
deleted file mode 100644
index 671cc8c35..000000000
--- a/mobile/android/components/NSSDialogService.js
+++ /dev/null
@@ -1,276 +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/. */
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cc = Components.classes;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Prompt",
- "resource://gre/modules/Prompt.jsm");
-
-// -----------------------------------------------------------------------
-// NSS Dialog Service
-// -----------------------------------------------------------------------
-
-function NSSDialogs() { }
-
-NSSDialogs.prototype = {
- classID: Components.ID("{cbc08081-49b6-4561-9c18-a7707a50bda1}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs, Ci.nsIClientAuthDialogs]),
-
- /**
- * Escapes the given input via HTML entity encoding. Used to prevent HTML
- * injection when the input is to be placed inside an HTML body, but not in
- * any other context.
- *
- * @param {String} input The input to interpret as a plain string.
- * @returns {String} The escaped input.
- */
- escapeHTML: function(input) {
- return input.replace(/&/g, "&amp;")
- .replace(/</g, "&lt;")
- .replace(/>/g, "&gt;")
- .replace(/"/g, "&quot;")
- .replace(/'/g, "&#x27;")
- .replace(/\//g, "&#x2F;");
- },
-
- getString: function(aName) {
- if (!this.bundle) {
- this.bundle = Services.strings.createBundle("chrome://browser/locale/pippki.properties");
- }
- return this.bundle.GetStringFromName(aName);
- },
-
- formatString: function(aName, argList) {
- if (!this.bundle) {
- this.bundle =
- Services.strings.createBundle("chrome://browser/locale/pippki.properties");
- }
- let escapedArgList = Array.from(argList, x => this.escapeHTML(x));
- return this.bundle.formatStringFromName(aName, escapedArgList,
- escapedArgList.length);
- },
-
- getPrompt: function(aTitle, aText, aButtons) {
- return new Prompt({
- title: aTitle,
- text: aText,
- buttons: aButtons,
- });
- },
-
- showPrompt: function(aPrompt) {
- let response = null;
- aPrompt.show(function(data) {
- response = data;
- });
-
- // Spin this thread while we wait for a result
- let thread = Services.tm.currentThread;
- while (response === null)
- thread.processNextEvent(true);
-
- return response;
- },
-
- confirmDownloadCACert: function(aCtx, aCert, aTrust) {
- while (true) {
- let prompt = this.getPrompt(this.getString("downloadCert.title"),
- this.getString("downloadCert.message1"),
- [ this.getString("nssdialogs.ok.label"),
- this.getString("downloadCert.viewCert.label"),
- this.getString("nssdialogs.cancel.label")
- ]);
-
- prompt.addCheckbox({ id: "trustSSL", label: this.getString("downloadCert.trustSSL"), checked: false })
- .addCheckbox({ id: "trustEmail", label: this.getString("downloadCert.trustEmail"), checked: false })
- .addCheckbox({ id: "trustSign", label: this.getString("downloadCert.trustObjSign"), checked: false });
- let response = this.showPrompt(prompt);
-
- // they hit the "view cert" button, so show the cert and try again
- if (response.button == 1) {
- this.viewCert(aCtx, aCert);
- continue;
- } else if (response.button != 0) {
- return false;
- }
-
- aTrust.value = Ci.nsIX509CertDB.UNTRUSTED;
- if (response.trustSSL) aTrust.value |= Ci.nsIX509CertDB.TRUSTED_SSL;
- if (response.trustEmail) aTrust.value |= Ci.nsIX509CertDB.TRUSTED_EMAIL;
- if (response.trustSign) aTrust.value |= Ci.nsIX509CertDB.TRUSTED_OBJSIGN;
- return true;
- }
- },
-
- setPKCS12FilePassword: function(aCtx, aPassword) {
- // this dialog is never shown in Fennec; in Desktop it is shown while backing up a personal
- // certificate to a file via Preferences->Advanced->Encryption->View Certificates->Your Certificates
- throw "Unimplemented";
- },
-
- getPKCS12FilePassword: function(aCtx, aPassword) {
- let prompt = this.getPrompt(this.getString("pkcs12.getpassword.title"),
- this.getString("pkcs12.getpassword.message"),
- [ this.getString("nssdialogs.ok.label"),
- this.getString("nssdialogs.cancel.label")
- ]).addPassword({id: "pw"});
- let response = this.showPrompt(prompt);
- if (response.button != 0) {
- return false;
- }
-
- aPassword.value = response.pw;
- return true;
- },
-
- certInfoSection: function(aHeading, aDataPairs, aTrailingNewline = true) {
- let certInfoStrings = [
- "<big>" + this.getString(aHeading) + "</big>",
- ];
-
- for (let i = 0; i < aDataPairs.length; i += 2) {
- let key = aDataPairs[i];
- let value = aDataPairs[i + 1];
- certInfoStrings.push(this.formatString(key, [value]));
- }
-
- if (aTrailingNewline) {
- certInfoStrings.push("<br/>");
- }
-
- return certInfoStrings.join("<br/>");
- },
-
- viewCert: function(aCtx, aCert) {
- let p = this.getPrompt(this.getString("certmgr.title"), "", [
- this.getString("nssdialogs.ok.label"),
- ]);
- p.addLabel({ label: this.certInfoSection("certmgr.subjectinfo.label",
- ["certdetail.cn", aCert.commonName,
- "certdetail.o", aCert.organization,
- "certdetail.ou", aCert.organizationalUnit,
- "certdetail.serialnumber", aCert.serialNumber])})
- .addLabel({ label: this.certInfoSection("certmgr.issuerinfo.label",
- ["certdetail.cn", aCert.issuerCommonName,
- "certdetail.o", aCert.issuerOrganization,
- "certdetail.ou", aCert.issuerOrganizationUnit])})
- .addLabel({ label: this.certInfoSection("certmgr.periodofvalidity.label",
- ["certdetail.notBefore", aCert.validity.notBeforeLocalDay,
- "certdetail.notAfter", aCert.validity.notAfterLocalDay])})
- .addLabel({ label: this.certInfoSection("certmgr.fingerprints.label",
- ["certdetail.sha256fingerprint", aCert.sha256Fingerprint,
- "certdetail.sha1fingerprint", aCert.sha1Fingerprint],
- false) });
- this.showPrompt(p);
- },
-
- /**
- * Returns a list of details of the given cert relevant for TLS client
- * authentication.
- *
- * @param {nsIX509Cert} cert Cert to get the details of.
- * @returns {String} <br/> delimited list of details.
- */
- getCertDetails: function(cert) {
- let detailLines = [
- this.formatString("clientAuthAsk.issuedTo", [cert.subjectName]),
- this.formatString("clientAuthAsk.serial", [cert.serialNumber]),
- this.formatString("clientAuthAsk.validityPeriod",
- [cert.validity.notBeforeLocalTime,
- cert.validity.notAfterLocalTime]),
- ];
- let keyUsages = cert.keyUsages;
- if (keyUsages) {
- detailLines.push(this.formatString("clientAuthAsk.keyUsages",
- [keyUsages]));
- }
- let emailAddresses = cert.getEmailAddresses({});
- if (emailAddresses.length > 0) {
- let joinedAddresses = emailAddresses.join(", ");
- detailLines.push(this.formatString("clientAuthAsk.emailAddresses",
- [joinedAddresses]));
- }
- detailLines.push(this.formatString("clientAuthAsk.issuedBy",
- [cert.issuerName]));
- detailLines.push(this.formatString("clientAuthAsk.storedOn",
- [cert.tokenName]));
-
- return detailLines.join("<br/>");
- },
-
- viewCertDetails: function(details) {
- let p = this.getPrompt(this.getString("clientAuthAsk.message3"),
- '',
- [ this.getString("nssdialogs.ok.label") ]);
- p.addLabel({ label: details });
- this.showPrompt(p);
- },
-
- chooseCertificate: function(ctx, hostname, port, organization, issuerOrg,
- certList, selectedIndex) {
- let rememberSetting =
- Services.prefs.getBoolPref("security.remember_cert_checkbox_default_setting");
-
- let serverRequestedDetails = [
- this.formatString("clientAuthAsk.hostnameAndPort",
- [hostname, port.toString()]),
- this.formatString("clientAuthAsk.organization", [organization]),
- this.formatString("clientAuthAsk.issuer", [issuerOrg]),
- ].join("<br/>");
-
- let certNickList = [];
- let certDetailsList = [];
- for (let i = 0; i < certList.length; i++) {
- let cert = certList.queryElementAt(i, Ci.nsIX509Cert);
- certNickList.push(this.formatString("clientAuthAsk.nickAndSerial",
- [cert.nickname, cert.serialNumber]));
- certDetailsList.push(this.getCertDetails(cert));
- }
-
- selectedIndex.value = 0;
- while (true) {
- let buttons = [
- this.getString("nssdialogs.ok.label"),
- this.getString("clientAuthAsk.viewCert.label"),
- this.getString("nssdialogs.cancel.label"),
- ];
- let prompt = this.getPrompt(this.getString("clientAuthAsk.title"),
- this.getString("clientAuthAsk.message1"),
- buttons)
- .addLabel({ id: "requestedDetails", label: serverRequestedDetails } )
- .addMenulist({
- id: "nicknames",
- label: this.getString("clientAuthAsk.message2"),
- values: certNickList,
- selected: selectedIndex.value,
- }).addCheckbox({
- id: "rememberBox",
- label: this.getString("clientAuthAsk.remember.label"),
- checked: rememberSetting
- });
- let response = this.showPrompt(prompt);
- selectedIndex.value = response.nicknames;
- if (response.button == 1 /* buttons[1] */) {
- this.viewCertDetails(certDetailsList[selectedIndex.value]);
- continue;
- } else if (response.button == 0 /* buttons[0] */) {
- if (response.rememberBox == true) {
- let caud = ctx.QueryInterface(Ci.nsIClientAuthUserDecision);
- if (caud) {
- caud.rememberClientAuthCertificate = true;
- }
- }
- return true;
- }
- return false;
- }
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([NSSDialogs]);
diff --git a/mobile/android/components/PersistentNotificationHandler.js b/mobile/android/components/PersistentNotificationHandler.js
deleted file mode 100644
index 2a3529f5f..000000000
--- a/mobile/android/components/PersistentNotificationHandler.js
+++ /dev/null
@@ -1,78 +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";
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Messaging.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, 'Services', // jshint ignore:line
- 'resource://gre/modules/Services.jsm');
-XPCOMUtils.defineLazyServiceGetter(this, "notificationStorage",
- "@mozilla.org/notificationStorage;1",
- "nsINotificationStorage");
-XPCOMUtils.defineLazyServiceGetter(this, "serviceWorkerManager",
- "@mozilla.org/serviceworkers/manager;1",
- "nsIServiceWorkerManager");
-
-function PersistentNotificationHandler() {
-}
-
-PersistentNotificationHandler.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver]),
- classID: Components.ID("{75390fe7-f8a3-423a-b3b1-258d7eabed40}"),
-
- observe(subject, topic, data) {
- if (Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_DEFAULT) {
- Cu.import("resource://gre/modules/NotificationDB.jsm");
- }
- const persistentInfo = JSON.parse(data);
-
- if (topic === 'persistent-notification-click') {
- notificationStorage.getByID(persistentInfo.origin, persistentInfo.id, {
- handle(id, title, dir, lang, body, tag, icon, data, behavior, serviceWorkerRegistrationScope) {
- serviceWorkerManager.sendNotificationClickEvent(
- persistentInfo.originSuffix,
- serviceWorkerRegistrationScope,
- id,
- title,
- dir,
- lang,
- body,
- tag,
- icon,
- data,
- behavior
- );
- notificationStorage.delete(persistentInfo.origin, persistentInfo.id);
- }
- });
- } else if (topic === 'persistent-notification-close') {
- notificationStorage.getByID(persistentInfo.origin, persistentInfo.id, {
- handle(id, title, dir, lang, body, tag, icon, data, behavior, serviceWorkerRegistrationScope) {
- serviceWorkerManager.sendNotificationCloseEvent(
- persistentInfo.originSuffix,
- serviceWorkerRegistrationScope,
- id,
- title,
- dir,
- lang,
- body,
- tag,
- icon,
- data,
- behavior
- );
- notificationStorage.delete(persistentInfo.origin, persistentInfo.id);
- }
- });
- }
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([
- PersistentNotificationHandler
-]);
diff --git a/mobile/android/components/PresentationDevicePrompt.js b/mobile/android/components/PresentationDevicePrompt.js
deleted file mode 100644
index e3e063373..000000000
--- a/mobile/android/components/PresentationDevicePrompt.js
+++ /dev/null
@@ -1,134 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* 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";
-
-const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
-
-Cu.import('resource://gre/modules/XPCOMUtils.jsm');
-Cu.import('resource://gre/modules/Services.jsm');
-
-XPCOMUtils.defineLazyModuleGetter(this, "Prompt",
- "resource://gre/modules/Prompt.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry",
- "resource://gre/modules/UITelemetry.jsm");
-
-const kPRESENTATIONDEVICEPROMPT_CONTRACTID = "@mozilla.org/presentation-device/prompt;1";
-const kPRESENTATIONDEVICEPROMPT_CID = Components.ID("{388bd149-c919-4a43-b646-d7ec57877689}");
-
-function debug(aMsg) {
- // dump("-*- PresentationDevicePrompt: " + aMsg + "\n");
-}
-
-// nsIPresentationDevicePrompt
-function PresentationDevicePrompt() {
- debug("PresentationDevicePrompt init");
-}
-
-PresentationDevicePrompt.prototype = {
- classID: kPRESENTATIONDEVICEPROMPT_CID,
- contractID: kPRESENTATIONDEVICEPROMPT_CONTRACTID,
- classDescription: "Fennec Presentation Device Prompt",
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationDevicePrompt]),
-
- _devices: [], // Store all available presentation devices
- _request: null, // Store the request from presentation api
-
- _getString: function(aName) {
- debug("_getString");
-
- if (!this.bundle) {
- this.bundle = Services.strings.createBundle("chrome://browser/locale/devicePrompt.properties");
- }
- return this.bundle.GetStringFromName(aName);
- },
-
- _loadDevices: function(requestURLs) {
- debug("_loadDevices");
-
- let deviceManager = Cc["@mozilla.org/presentation-device/manager;1"]
- .getService(Ci.nsIPresentationDeviceManager);
- let devices = deviceManager.getAvailableDevices(requestURLs).QueryInterface(Ci.nsIArray);
-
- // Re-load the available devices
- this._devices = [];
- for (let i = 0; i < devices.length; i++) {
- let device = devices.queryElementAt(i, Ci.nsIPresentationDevice);
- this._devices.push(device);
- }
- },
-
- _getPromptMenu: function(aDevices) {
- debug("_getPromptMenu");
-
- return aDevices.map(function(device) {
- return { label: device.name };
- });
- },
-
- _getPrompt: function(aTitle, aMenu) {
- debug("_getPrompt");
-
- let p = new Prompt({
- title: aTitle,
- });
-
- p.setSingleChoiceItems(aMenu);
-
- return p;
- },
-
- _showPrompt: function(aPrompt, aCallback) {
- debug("_showPrompt");
-
- aPrompt.show(function(data) {
- let buttonIndex = data.button;
- aCallback(buttonIndex);
- });
- },
-
- _selectDevice: function(aIndex) {
- debug("_selectDevice");
-
- if (!this._request) {
- return;
- }
-
- if (aIndex < 0) { // Cancel request if no selected device,
- this._request.cancel(Cr.NS_ERROR_DOM_NOT_ALLOWED_ERR);
- return;
- } else if (!this._devices.length) { // or there is no available devices
- this._request.cancel(Cr.NS_ERROR_DOM_NOT_FOUND_ERR);
- return;
- }
-
- this._request.select(this._devices[aIndex]);
- },
-
- // This will be fired when window.PresentationRequest(URL).start() is called
- promptDeviceSelection: function(aRequest) {
- debug("promptDeviceSelection");
-
- // Load available presentation devices into this._devices
- this._loadDevices(aRequest.requestURLs);
-
- if (!this._devices.length) { // Cancel request if no available device
- aRequest.cancel(Cr.NS_ERROR_DOM_NOT_FOUND_ERR);
- return;
- }
-
- this._request = aRequest;
-
- let prompt = this._getPrompt(this._getString("deviceMenu.title"),
- this._getPromptMenu(this._devices));
-
- this._showPrompt(prompt, this._selectDevice.bind(this));
-
- UITelemetry.addEvent("show.1", "dialog", null, "prompt_device_selection");
- },
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationDevicePrompt]);
diff --git a/mobile/android/components/PresentationRequestUIGlue.js b/mobile/android/components/PresentationRequestUIGlue.js
deleted file mode 100644
index af252c875..000000000
--- a/mobile/android/components/PresentationRequestUIGlue.js
+++ /dev/null
@@ -1,86 +0,0 @@
-/* -*- Mode: tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* 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"
-
-const { interfaces: Ci, utils: Cu, classes: Cc } = Components;
-
-const TOPIC_PRESENTATION_RECEIVER_LAUNCH = "presentation-receiver:launch";
-const TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE = "presentation-receiver:launch:response";
-
-// globals XPCOMUtils
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-// globals Services
-Cu.import("resource://gre/modules/Services.jsm");
-
-function log(str) {
- // dump("-*- PresentationRequestUIGlue.js -*-: " + str + "\n");
-}
-
-function PresentationRequestUIGlue() { }
-
-PresentationRequestUIGlue.prototype = {
- sendRequest: function sendRequest(aURL, aSessionId, aDevice) {
- log("PresentationRequestUIGlue - sendRequest aURL=" + aURL +
- " aSessionId=" + aSessionId);
-
- let localDevice;
- try {
- localDevice = aDevice.QueryInterface(Ci.nsIPresentationLocalDevice);
- } catch (e) {
- /* XXX: Currently, Fennec only support 1-UA devices. Remove this
- * Promise.reject() when it starts to support 2-UA devices.
- */
- log("Not an 1-UA device.")
- return new Promise.reject();
- }
-
- return new Promise((aResolve, aReject) => {
-
- let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"]
- .getService(Ci.nsIUUIDGenerator);
- let requestId = uuidGenerator.generateUUID().toString();
-
- let handleObserve = (aSubject, aTopic, aData) => {
- log("Got observe: aTopic=" + aTopic);
-
- let data = JSON.parse(aData);
- if (data.requestId != requestId) {
- return;
- }
-
- Services.obs.removeObserver(handleObserve,
- TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE);
- switch(data.result) {
- case "success":
- aResolve(aSubject);
- break;
- case "error":
- aReject();
- break;
- };
- };
-
- Services.obs.addObserver(handleObserve,
- TOPIC_PRESENTATION_RECEIVER_LAUNCH_RESPONSE,
- false);
-
- let data = {
- url: aURL,
- windowId: localDevice.windowId,
- requestId: requestId
- };
- Services.obs.notifyObservers(null,
- TOPIC_PRESENTATION_RECEIVER_LAUNCH,
- JSON.stringify(data));
- })
- },
-
- classID: Components.ID("9c550ef7-3ff6-4bd1-9ad1-5a3735b90d21"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPresentationRequestUIGlue])
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PresentationRequestUIGlue]);
diff --git a/mobile/android/components/PromptService.js b/mobile/android/components/PromptService.js
deleted file mode 100644
index 93aff67ee..000000000
--- a/mobile/android/components/PromptService.js
+++ /dev/null
@@ -1,878 +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/. */
-const Ci = Components.interfaces;
-const Cc = Components.classes;
-const Cr = Components.results;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Prompt",
- "resource://gre/modules/Prompt.jsm");
-
-var gPromptService = null;
-
-function PromptService() {
- gPromptService = this;
-}
-
-PromptService.prototype = {
- classID: Components.ID("{9a61149b-2276-4a0a-b79c-be994ad106cf}"),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptFactory, Ci.nsIPromptService, Ci.nsIPromptService2]),
-
- /* ---------- nsIPromptFactory ---------- */
- // XXX Copied from nsPrompter.js.
- getPrompt: function getPrompt(domWin, iid) {
- // This is still kind of dumb; the C++ code delegated to login manager
- // here, which in turn calls back into us via nsIPromptService2.
- if (iid.equals(Ci.nsIAuthPrompt2) || iid.equals(Ci.nsIAuthPrompt)) {
- try {
- let pwmgr = Cc["@mozilla.org/passwordmanager/authpromptfactory;1"].getService(Ci.nsIPromptFactory);
- return pwmgr.getPrompt(domWin, iid);
- } catch (e) {
- Cu.reportError("nsPrompter: Delegation to password manager failed: " + e);
- }
- }
-
- let p = new InternalPrompt(domWin);
- p.QueryInterface(iid);
- return p;
- },
-
- /* ---------- private memebers ---------- */
-
- // nsIPromptService and nsIPromptService2 methods proxy to our Prompt class
- callProxy: function(aMethod, aArguments) {
- let prompt;
- let domWin = aArguments[0];
- prompt = new InternalPrompt(domWin);
- return prompt[aMethod].apply(prompt, Array.prototype.slice.call(aArguments, 1));
- },
-
- /* ---------- nsIPromptService ---------- */
-
- alert: function() {
- return this.callProxy("alert", arguments);
- },
- alertCheck: function() {
- return this.callProxy("alertCheck", arguments);
- },
- confirm: function() {
- return this.callProxy("confirm", arguments);
- },
- confirmCheck: function() {
- return this.callProxy("confirmCheck", arguments);
- },
- confirmEx: function() {
- return this.callProxy("confirmEx", arguments);
- },
- prompt: function() {
- return this.callProxy("prompt", arguments);
- },
- promptUsernameAndPassword: function() {
- return this.callProxy("promptUsernameAndPassword", arguments);
- },
- promptPassword: function() {
- return this.callProxy("promptPassword", arguments);
- },
- select: function() {
- return this.callProxy("select", arguments);
- },
-
- /* ---------- nsIPromptService2 ---------- */
- promptAuth: function() {
- return this.callProxy("promptAuth", arguments);
- },
- asyncPromptAuth: function() {
- return this.callProxy("asyncPromptAuth", arguments);
- }
-};
-
-function InternalPrompt(aDomWin) {
- this._domWin = aDomWin;
-}
-
-InternalPrompt.prototype = {
- _domWin: null,
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt, Ci.nsIAuthPrompt, Ci.nsIAuthPrompt2]),
-
- /* ---------- internal methods ---------- */
- _getPrompt: function _getPrompt(aTitle, aText, aButtons, aCheckMsg, aCheckState) {
- let p = new Prompt({
- window: this._domWin,
- title: aTitle,
- message: aText,
- buttons: aButtons || [
- PromptUtils.getLocaleString("OK"),
- PromptUtils.getLocaleString("Cancel")
- ]
- });
- return p;
- },
-
- addCheckbox: function addCheckbox(aPrompt, aCheckMsg, aCheckState) {
- // Don't bother to check for aCheckSate. For nsIPomptService interfaces, aCheckState is an
- // out param and is required to be defined. If we've gotten here without it, something
- // has probably gone wrong and we should fail
- if (aCheckMsg) {
- aPrompt.addCheckbox({
- label: PromptUtils.cleanUpLabel(aCheckMsg),
- checked: aCheckState.value
- });
- }
-
- return aPrompt;
- },
-
- addTextbox: function(prompt, value, autofocus, hint) {
- prompt.addTextbox({
- value: (value !== null) ? value : "",
- autofocus: autofocus,
- hint: hint
- });
- },
-
- addPassword: function(prompt, value, autofocus, hint) {
- prompt.addPassword({
- value: (value !== null) ? value : "",
- autofocus: autofocus,
- hint: hint
- });
- },
-
- /* Shows a native prompt, and then spins the event loop for this thread while we wait
- * for a response
- */
- showPrompt: function showPrompt(aPrompt) {
- if (this._domWin) {
- PromptUtils.fireDialogEvent(this._domWin, "DOMWillOpenModalDialog");
- let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
- winUtils.enterModalState();
- }
-
- let retval = null;
- aPrompt.show(function(data) {
- retval = data;
- });
-
- // Spin this thread while we wait for a result
- let thread = Services.tm.currentThread;
- while (retval == null)
- thread.processNextEvent(true);
-
- if (this._domWin) {
- let winUtils = this._domWin.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
- winUtils.leaveModalState();
- PromptUtils.fireDialogEvent(this._domWin, "DOMModalDialogClosed");
- }
-
- return retval;
- },
-
- /*
- * ---------- interface disambiguation ----------
- *
- * XXX Copied from nsPrompter.js.
- *
- * nsIPrompt and nsIAuthPrompt share 3 method names with slightly
- * different arguments. All but prompt() have the same number of
- * arguments, so look at the arg types to figure out how we're being
- * called. :-(
- */
- prompt: function prompt() {
- if (gPromptService.inContentProcess)
- return gPromptService.callProxy("prompt", [null].concat(Array.prototype.slice.call(arguments)));
-
- // also, the nsIPrompt flavor has 5 args instead of 6.
- if (typeof arguments[2] == "object")
- return this.nsIPrompt_prompt.apply(this, arguments);
- else
- return this.nsIAuthPrompt_prompt.apply(this, arguments);
- },
-
- promptUsernameAndPassword: function promptUsernameAndPassword() {
- // Both have 6 args, so use types.
- if (typeof arguments[2] == "object")
- return this.nsIPrompt_promptUsernameAndPassword.apply(this, arguments);
- else
- return this.nsIAuthPrompt_promptUsernameAndPassword.apply(this, arguments);
- },
-
- promptPassword: function promptPassword() {
- // Both have 5 args, so use types.
- if (typeof arguments[2] == "object")
- return this.nsIPrompt_promptPassword.apply(this, arguments);
- else
- return this.nsIAuthPrompt_promptPassword.apply(this, arguments);
- },
-
- /* ---------- nsIPrompt ---------- */
-
- alert: function alert(aTitle, aText) {
- let p = this._getPrompt(aTitle, aText, [ PromptUtils.getLocaleString("OK") ]);
- p.setHint("alert");
- this.showPrompt(p);
- },
-
- alertCheck: function alertCheck(aTitle, aText, aCheckMsg, aCheckState) {
- let p = this._getPrompt(aTitle, aText, [ PromptUtils.getLocaleString("OK") ]);
- this.addCheckbox(p, aCheckMsg, aCheckState);
- let data = this.showPrompt(p);
- if (aCheckState && data.button > -1)
- aCheckState.value = data.checkbox0;
- },
-
- confirm: function confirm(aTitle, aText) {
- let p = this._getPrompt(aTitle, aText);
- p.setHint("confirm");
- let data = this.showPrompt(p);
- return (data.button == 0);
- },
-
- confirmCheck: function confirmCheck(aTitle, aText, aCheckMsg, aCheckState) {
- let p = this._getPrompt(aTitle, aText, null);
- this.addCheckbox(p, aCheckMsg, aCheckState);
- let data = this.showPrompt(p);
- let ok = data.button == 0;
- if (aCheckState && data.button > -1)
- aCheckState.value = data.checkbox0;
- return ok;
- },
-
- confirmEx: function confirmEx(aTitle, aText, aButtonFlags, aButton0,
- aButton1, aButton2, aCheckMsg, aCheckState) {
- let buttons = [];
- let titles = [aButton0, aButton1, aButton2];
- for (let i = 0; i < 3; i++) {
- let bTitle = null;
- switch (aButtonFlags & 0xff) {
- case Ci.nsIPromptService.BUTTON_TITLE_OK :
- bTitle = PromptUtils.getLocaleString("OK");
- break;
- case Ci.nsIPromptService.BUTTON_TITLE_CANCEL :
- bTitle = PromptUtils.getLocaleString("Cancel");
- break;
- case Ci.nsIPromptService.BUTTON_TITLE_YES :
- bTitle = PromptUtils.getLocaleString("Yes");
- break;
- case Ci.nsIPromptService.BUTTON_TITLE_NO :
- bTitle = PromptUtils.getLocaleString("No");
- break;
- case Ci.nsIPromptService.BUTTON_TITLE_SAVE :
- bTitle = PromptUtils.getLocaleString("Save");
- break;
- case Ci.nsIPromptService.BUTTON_TITLE_DONT_SAVE :
- bTitle = PromptUtils.getLocaleString("DontSave");
- break;
- case Ci.nsIPromptService.BUTTON_TITLE_REVERT :
- bTitle = PromptUtils.getLocaleString("Revert");
- break;
- case Ci.nsIPromptService.BUTTON_TITLE_IS_STRING :
- bTitle = PromptUtils.cleanUpLabel(titles[i]);
- break;
- }
-
- if (bTitle)
- buttons.push(bTitle);
-
- aButtonFlags >>= 8;
- }
-
- let p = this._getPrompt(aTitle, aText, buttons);
- this.addCheckbox(p, aCheckMsg, aCheckState);
- let data = this.showPrompt(p);
- if (aCheckState && data.button > -1)
- aCheckState.value = data.checkbox0;
- return data.button;
- },
-
- nsIPrompt_prompt: function nsIPrompt_prompt(aTitle, aText, aValue, aCheckMsg, aCheckState) {
- let p = this._getPrompt(aTitle, aText, null, aCheckMsg, aCheckState);
- p.setHint("prompt");
- this.addTextbox(p, aValue.value, true);
- this.addCheckbox(p, aCheckMsg, aCheckState);
- let data = this.showPrompt(p);
-
- let ok = data.button == 0;
- if (aCheckState && data.button > -1)
- aCheckState.value = data.checkbox0;
- if (ok)
- aValue.value = data.textbox0;
- return ok;
- },
-
- nsIPrompt_promptPassword: function nsIPrompt_promptPassword(
- aTitle, aText, aPassword, aCheckMsg, aCheckState) {
- let p = this._getPrompt(aTitle, aText, null);
- this.addPassword(p, aPassword.value, true, PromptUtils.getLocaleString("password", "passwdmgr"));
- this.addCheckbox(p, aCheckMsg, aCheckState);
- let data = this.showPrompt(p);
-
- let ok = data.button == 0;
- if (aCheckState && data.button > -1)
- aCheckState.value = data.checkbox0;
- if (ok)
- aPassword.value = data.password0;
- return ok;
- },
-
- nsIPrompt_promptUsernameAndPassword: function nsIPrompt_promptUsernameAndPassword(
- aTitle, aText, aUsername, aPassword, aCheckMsg, aCheckState) {
- let p = this._getPrompt(aTitle, aText, null);
- this.addTextbox(p, aUsername.value, true, PromptUtils.getLocaleString("username", "passwdmgr"));
- this.addPassword(p, aPassword.value, false, PromptUtils.getLocaleString("password", "passwdmgr"));
- this.addCheckbox(p, aCheckMsg, aCheckState);
- let data = this.showPrompt(p);
-
- let ok = data.button == 0;
- if (aCheckState && data.button > -1)
- aCheckState.value = data.checkbox0;
-
- if (ok) {
- aUsername.value = data.textbox0;
- aPassword.value = data.password0;
- }
- return ok;
- },
-
- select: function select(aTitle, aText, aCount, aSelectList, aOutSelection) {
- let p = this._getPrompt(aTitle, aText, [ PromptUtils.getLocaleString("OK") ]);
- p.addMenulist({ values: aSelectList });
- let data = this.showPrompt(p);
-
- let ok = data.button == 0;
- if (ok)
- aOutSelection.value = data.menulist0;
-
- return ok;
- },
-
- /* ---------- nsIAuthPrompt ---------- */
-
- nsIAuthPrompt_prompt : function (title, text, passwordRealm, savePassword, defaultText, result) {
- // TODO: Port functions from nsLoginManagerPrompter.js to here
- if (defaultText)
- result.value = defaultText;
- return this.nsIPrompt_prompt(title, text, result, null, {});
- },
-
- nsIAuthPrompt_promptUsernameAndPassword : function(aTitle, aText, aPasswordRealm, aSavePassword, aUser, aPass) {
- return this.nsIAuthPrompt_loginPrompt(aTitle, aText, aPasswordRealm, aSavePassword, aUser, aPass);
- },
-
- nsIAuthPrompt_promptPassword : function(aTitle, aText, aPasswordRealm, aSavePassword, aPass) {
- return this.nsIAuthPrompt_loginPrompt(aTitle, aText, aPasswordRealm, aSavePassword, null, aPass);
- },
-
- nsIAuthPrompt_loginPrompt: function(aTitle, aPasswordRealm, aSavePassword, aUser, aPass) {
- let checkMsg = null;
- let check = { value: false };
- let hostname, realm;
- [hostname, realm, aUser] = PromptUtils.getHostnameAndRealm(aPasswordRealm);
-
- let canSave = PromptUtils.canSaveLogin(hostname, aSavePassword);
- if (canSave) {
- // Look for existing logins.
- let foundLogins = PromptUtils.pwmgr.findLogins({}, hostname, null, realm);
- [checkMsg, check] = PromptUtils.getUsernameAndPassword(foundLogins, aUser, aPass);
- }
-
- // (eslint-disable: see bug 1177904)
- let ok = false;
- if (aUser)
- ok = this.nsIPrompt_promptUsernameAndPassword(aTitle, aText, aUser, aPass, checkMsg, check); // eslint-disable-line no-undef
- else
- ok = this.nsIPrompt_promptPassword(aTitle, aText, aPass, checkMsg, check); // eslint-disable-line no-undef
-
- if (ok && canSave && check.value)
- PromptUtils.savePassword(hostname, realm, aUser, aPass);
-
- return ok;
- },
-
- /* ---------- nsIAuthPrompt2 ---------- */
-
- promptAuth: function promptAuth(aChannel, aLevel, aAuthInfo) {
- let checkMsg = null;
- let check = { value: false };
- let message = PromptUtils.makeDialogText(aChannel, aAuthInfo);
- let [username, password] = PromptUtils.getAuthInfo(aAuthInfo);
- let [hostname, httpRealm] = PromptUtils.getAuthTarget(aChannel, aAuthInfo);
- let foundLogins = PromptUtils.pwmgr.findLogins({}, hostname, null, httpRealm);
-
- let canSave = PromptUtils.canSaveLogin(hostname, null);
- if (canSave)
- [checkMsg, check] = PromptUtils.getUsernameAndPassword(foundLogins, username, password);
-
- if (username.value && password.value) {
- PromptUtils.setAuthInfo(aAuthInfo, username.value, password.value);
- }
-
- let canAutologin = false;
- if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY &&
- !(aAuthInfo.flags & Ci.nsIAuthInformation.PREVIOUS_FAILED) &&
- Services.prefs.getBoolPref("signon.autologin.proxy"))
- canAutologin = true;
-
- let ok = canAutologin;
- if (!ok && aAuthInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD)
- ok = this.nsIPrompt_promptPassword(null, message, password, checkMsg, check);
- else if (!ok)
- ok = this.nsIPrompt_promptUsernameAndPassword(null, message, username, password, checkMsg, check);
-
- PromptUtils.setAuthInfo(aAuthInfo, username.value, password.value);
-
- if (ok && canSave && check.value)
- PromptUtils.savePassword(foundLogins, username, password, hostname, httpRealm);
-
- return ok;
- },
-
- _asyncPrompts: {},
- _asyncPromptInProgress: false,
-
- _doAsyncPrompt : function() {
- if (this._asyncPromptInProgress)
- return;
-
- // Find the first prompt key we have in the queue
- let hashKey = null;
- for (hashKey in this._asyncPrompts)
- break;
-
- if (!hashKey)
- return;
-
- // If login manger has logins for this host, defer prompting if we're
- // already waiting on a master password entry.
- let prompt = this._asyncPrompts[hashKey];
- let prompter = prompt.prompter;
- let [hostname, httpRealm] = PromptUtils.getAuthTarget(prompt.channel, prompt.authInfo);
- let foundLogins = PromptUtils.pwmgr.findLogins({}, hostname, null, httpRealm);
- if (foundLogins.length > 0 && PromptUtils.pwmgr.uiBusy)
- return;
-
- this._asyncPromptInProgress = true;
- prompt.inProgress = true;
-
- let self = this;
-
- let runnable = {
- run: function() {
- let ok = false;
- try {
- ok = prompter.promptAuth(prompt.channel, prompt.level, prompt.authInfo);
- } catch (e) {
- Cu.reportError("_doAsyncPrompt:run: " + e + "\n");
- }
-
- delete self._asyncPrompts[hashKey];
- prompt.inProgress = false;
- self._asyncPromptInProgress = false;
-
- for (let consumer of prompt.consumers) {
- if (!consumer.callback)
- // Not having a callback means that consumer didn't provide it
- // or canceled the notification
- continue;
-
- try {
- if (ok)
- consumer.callback.onAuthAvailable(consumer.context, prompt.authInfo);
- else
- consumer.callback.onAuthCancelled(consumer.context, true);
- } catch (e) { /* Throw away exceptions caused by callback */ }
- }
- self._doAsyncPrompt();
- }
- }
-
- Services.tm.mainThread.dispatch(runnable, Ci.nsIThread.DISPATCH_NORMAL);
- },
-
- asyncPromptAuth: function asyncPromptAuth(aChannel, aCallback, aContext, aLevel, aAuthInfo) {
- let cancelable = null;
- try {
- // If the user submits a login but it fails, we need to remove the
- // notification bar that was displayed. Conveniently, the user will
- // be prompted for authentication again, which brings us here.
- //this._removeLoginNotifications();
-
- cancelable = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable]),
- callback: aCallback,
- context: aContext,
- cancel: function() {
- this.callback.onAuthCancelled(this.context, false);
- this.callback = null;
- this.context = null;
- }
- };
- let [hostname, httpRealm] = PromptUtils.getAuthTarget(aChannel, aAuthInfo);
- let hashKey = aLevel + "|" + hostname + "|" + httpRealm;
- let asyncPrompt = this._asyncPrompts[hashKey];
- if (asyncPrompt) {
- asyncPrompt.consumers.push(cancelable);
- return cancelable;
- }
-
- asyncPrompt = {
- consumers: [cancelable],
- channel: aChannel,
- authInfo: aAuthInfo,
- level: aLevel,
- inProgress : false,
- prompter: this
- }
-
- this._asyncPrompts[hashKey] = asyncPrompt;
- this._doAsyncPrompt();
- } catch (e) {
- Cu.reportError("PromptService: " + e + "\n");
- throw e;
- }
- return cancelable;
- }
-};
-
-var PromptUtils = {
- getLocaleString: function pu_getLocaleString(aKey, aService) {
- if (aService == "passwdmgr")
- return this.cleanUpLabel(this.passwdBundle.GetStringFromName(aKey));
-
- return this.cleanUpLabel(this.bundle.GetStringFromName(aKey));
- },
-
- //
- // Copied from chrome://global/content/commonDialog.js
- //
- cleanUpLabel: function cleanUpLabel(aLabel) {
- // This is for labels which may contain embedded access keys.
- // If we end in (&X) where X represents the access key, optionally preceded
- // by spaces and/or followed by the ':' character,
- // remove the access key placeholder + leading spaces from the label.
- // Otherwise a character preceded by one but not two &s is the access key.
-
- // Note that if you change the following code, see the comment of
- // nsTextBoxFrame::UpdateAccessTitle.
- if (!aLabel)
- return "";
-
- if (/ *\(\&([^&])\)(:?)$/.test(aLabel)) {
- aLabel = RegExp.leftContext + RegExp.$2;
- } else if (/^([^&]*)\&(([^&]).*$)/.test(aLabel)) {
- aLabel = RegExp.$1 + RegExp.$2;
- }
-
- // Special code for using that & symbol
- aLabel = aLabel.replace(/\&\&/g, "&");
-
- return aLabel;
- },
-
- get pwmgr() {
- delete this.pwmgr;
- return this.pwmgr = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
- },
-
- getHostnameAndRealm: function pu_getHostnameAndRealm(aRealmString) {
- let httpRealm = /^.+ \(.+\)$/;
- if (httpRealm.test(aRealmString))
- return [null, null, null];
-
- let uri = Services.io.newURI(aRealmString, null, null);
- let pathname = "";
-
- if (uri.path != "/")
- pathname = uri.path;
-
- let formattedHostname = this._getFormattedHostname(uri);
- return [formattedHostname, formattedHostname + pathname, uri.username];
- },
-
- canSaveLogin: function pu_canSaveLogin(aHostname, aSavePassword) {
- let canSave = !this._inPrivateBrowsing && this.pwmgr.getLoginSavingEnabled(aHostname)
- if (aSavePassword)
- canSave = canSave && (aSavePassword == Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY)
- return canSave;
- },
-
- getUsernameAndPassword: function pu_getUsernameAndPassword(aFoundLogins, aUser, aPass) {
- let checkLabel = null;
- let check = { value: false };
- let selectedLogin;
-
- checkLabel = this.getLocaleString("rememberButton", "passwdmgr");
-
- // XXX Like the original code, we can't deal with multiple
- // account selection. (bug 227632)
- if (aFoundLogins.length > 0) {
- selectedLogin = aFoundLogins[0];
-
- // If the caller provided a username, try to use it. If they
- // provided only a password, this will try to find a password-only
- // login (or return null if none exists).
- if (aUser.value)
- selectedLogin = this.findLogin(aFoundLogins, "username", aUser.value);
-
- if (selectedLogin) {
- check.value = true;
- aUser.value = selectedLogin.username;
- // If the caller provided a password, prefer it.
- if (!aPass.value)
- aPass.value = selectedLogin.password;
- }
- }
-
- return [checkLabel, check];
- },
-
- findLogin: function pu_findLogin(aLogins, aName, aValue) {
- for (let i = 0; i < aLogins.length; i++)
- if (aLogins[i][aName] == aValue)
- return aLogins[i];
- return null;
- },
-
- savePassword: function pu_savePassword(aLogins, aUser, aPass, aHostname, aRealm) {
- let selectedLogin = this.findLogin(aLogins, "username", aUser.value);
-
- // If we didn't find an existing login, or if the username
- // changed, save as a new login.
- if (!selectedLogin) {
- // add as new
- var newLogin = Cc["@mozilla.org/login-manager/loginInfo;1"].createInstance(Ci.nsILoginInfo);
- newLogin.init(aHostname, null, aRealm, aUser.value, aPass.value, "", "");
- this.pwmgr.addLogin(newLogin);
- } else if (aPass.value != selectedLogin.password) {
- // update password
- this.updateLogin(selectedLogin, aPass.value);
- } else {
- this.updateLogin(selectedLogin);
- }
- },
-
- updateLogin: function pu_updateLogin(aLogin, aPassword) {
- let now = Date.now();
- let propBag = Cc["@mozilla.org/hash-property-bag;1"].createInstance(Ci.nsIWritablePropertyBag);
- if (aPassword) {
- propBag.setProperty("password", aPassword);
- // Explicitly set the password change time here (even though it would
- // be changed automatically), to ensure that it's exactly the same
- // value as timeLastUsed.
- propBag.setProperty("timePasswordChanged", now);
- }
- propBag.setProperty("timeLastUsed", now);
- propBag.setProperty("timesUsedIncrement", 1);
-
- this.pwmgr.modifyLogin(aLogin, propBag);
- },
-
- // JS port of http://mxr.mozilla.org/mozilla-central/source/embedding/components/windowwatcher/nsPrompt.cpp#388
- makeDialogText: function pu_makeDialogText(aChannel, aAuthInfo) {
- let isProxy = (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY);
- let isPassOnly = (aAuthInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD);
- let isCrossOrig = (aAuthInfo.flags &
- Ci.nsIAuthInformation.CROSS_ORIGIN_SUB_RESOURCE);
-
- let username = aAuthInfo.username;
- let [displayHost, realm] = this.getAuthTarget(aChannel, aAuthInfo);
-
- // Suppress "the site says: $realm" when we synthesized a missing realm.
- if (!aAuthInfo.realm && !isProxy)
- realm = "";
-
- // Trim obnoxiously long realms.
- if (realm.length > 150) {
- realm = realm.substring(0, 150);
- // Append "..." (or localized equivalent).
- realm += this.ellipsis;
- }
-
- let text;
- if (isProxy) {
- text = this.bundle.formatStringFromName("EnterLoginForProxy3", [realm, displayHost], 2);
- } else if (isPassOnly) {
- text = this.bundle.formatStringFromName("EnterPasswordFor", [username, displayHost], 2);
- } else if (isCrossOrig) {
- text = this.bundle.formatStringFromName("EnterUserPasswordForCrossOrigin2", [displayHost], 1);
- } else if (!realm) {
- text = this.bundle.formatStringFromName("EnterUserPasswordFor2", [displayHost], 1);
- } else {
- text = this.bundle.formatStringFromName("EnterLoginForRealm3", [realm, displayHost], 2);
- }
-
- return text;
- },
-
- // JS port of http://mxr.mozilla.org/mozilla-central/source/embedding/components/windowwatcher/nsPromptUtils.h#89
- getAuthHostPort: function pu_getAuthHostPort(aChannel, aAuthInfo) {
- let uri = aChannel.URI;
- let res = { host: null, port: -1 };
- if (aAuthInfo.flags & aAuthInfo.AUTH_PROXY) {
- let proxy = aChannel.QueryInterface(Ci.nsIProxiedChannel);
- res.host = proxy.proxyInfo.host;
- res.port = proxy.proxyInfo.port;
- } else {
- res.host = uri.host;
- res.port = uri.port;
- }
- return res;
- },
-
- getAuthTarget : function pu_getAuthTarget(aChannel, aAuthInfo) {
- let hostname, realm;
- // If our proxy is demanding authentication, don't use the
- // channel's actual destination.
- if (aAuthInfo.flags & Ci.nsIAuthInformation.AUTH_PROXY) {
- if (!(aChannel instanceof Ci.nsIProxiedChannel))
- throw "proxy auth needs nsIProxiedChannel";
-
- let info = aChannel.proxyInfo;
- if (!info)
- throw "proxy auth needs nsIProxyInfo";
-
- // Proxies don't have a scheme, but we'll use "moz-proxy://"
- // so that it's more obvious what the login is for.
- let idnService = Cc["@mozilla.org/network/idn-service;1"].getService(Ci.nsIIDNService);
- hostname = "moz-proxy://" + idnService.convertUTF8toACE(info.host) + ":" + info.port;
- realm = aAuthInfo.realm;
- if (!realm)
- realm = hostname;
-
- return [hostname, realm];
- }
- hostname = this.getFormattedHostname(aChannel.URI);
-
- // If a HTTP WWW-Authenticate header specified a realm, that value
- // will be available here. If it wasn't set or wasn't HTTP, we'll use
- // the formatted hostname instead.
- realm = aAuthInfo.realm;
- if (!realm)
- realm = hostname;
-
- return [hostname, realm];
- },
-
- getAuthInfo : function pu_getAuthInfo(aAuthInfo) {
- let flags = aAuthInfo.flags;
- let username = {value: ""};
- let password = {value: ""};
-
- if (flags & Ci.nsIAuthInformation.NEED_DOMAIN && aAuthInfo.domain)
- username.value = aAuthInfo.domain + "\\" + aAuthInfo.username;
- else
- username.value = aAuthInfo.username;
-
- password.value = aAuthInfo.password
-
- return [username, password];
- },
-
- setAuthInfo : function (aAuthInfo, username, password) {
- var flags = aAuthInfo.flags;
- if (flags & Ci.nsIAuthInformation.NEED_DOMAIN) {
- // Domain is separated from username by a backslash
- var idx = username.indexOf("\\");
- if (idx == -1) {
- aAuthInfo.username = username;
- } else {
- aAuthInfo.domain = username.substring(0, idx);
- aAuthInfo.username = username.substring(idx+1);
- }
- } else {
- aAuthInfo.username = username;
- }
- aAuthInfo.password = password;
- },
-
- /**
- * Strip out things like userPass and path for display.
- */
- getFormattedHostname : function pu_getFormattedHostname(uri) {
- return uri.scheme + "://" + uri.hostPort;
- },
-
- fireDialogEvent: function(aDomWin, aEventName) {
- // accessing the document object can throw if this window no longer exists. See bug 789888.
- try {
- if (!aDomWin.document)
- return;
- let event = aDomWin.document.createEvent("Events");
- event.initEvent(aEventName, true, true);
- let winUtils = aDomWin.QueryInterface(Ci.nsIInterfaceRequestor)
- .getInterface(Ci.nsIDOMWindowUtils);
- winUtils.dispatchEventToChromeOnly(aDomWin, event);
- } catch(ex) {
- }
- }
-};
-
-XPCOMUtils.defineLazyGetter(PromptUtils, "passwdBundle", function () {
- return Services.strings.createBundle("chrome://passwordmgr/locale/passwordmgr.properties");
-});
-
-XPCOMUtils.defineLazyGetter(PromptUtils, "bundle", function () {
- return Services.strings.createBundle("chrome://global/locale/commonDialogs.properties");
-});
-
-
-// Factory for wrapping nsIAuthPrompt interfaces to make them usable via an nsIAuthPrompt2 interface.
-// XXX Copied from nsPrompter.js.
-function AuthPromptAdapterFactory() {
-}
-
-AuthPromptAdapterFactory.prototype = {
- classID: Components.ID("{80dae1e9-e0d2-4974-915f-f97050fa8068}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIAuthPromptAdapterFactory]),
-
- /* ---------- nsIAuthPromptAdapterFactory ---------- */
-
- createAdapter: function(aPrompt) {
- return new AuthPromptAdapter(aPrompt);
- }
-};
-
-
-// Takes an nsIAuthPrompt implementation, wraps it with a nsIAuthPrompt2 shell.
-// XXX Copied from nsPrompter.js.
-function AuthPromptAdapter(aPrompt) {
- this.prompt = aPrompt;
-}
-
-AuthPromptAdapter.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIAuthPrompt2]),
- prompt: null,
-
- /* ---------- nsIAuthPrompt2 ---------- */
-
- promptAuth: function(aChannel, aLevel, aAuthInfo, aCheckLabel, aCheckValue) {
- let message = PromptUtils.makeDialogText(aChannel, aAuthInfo);
-
- let [username, password] = PromptUtils.getAuthInfo(aAuthInfo);
- let [host, realm] = PromptUtils.getAuthTarget(aChannel, aAuthInfo);
- let authTarget = host + " (" + realm + ")";
-
- let ok;
- if (aAuthInfo.flags & Ci.nsIAuthInformation.ONLY_PASSWORD) {
- ok = this.prompt.promptPassword(null, message, authTarget, Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, password);
- } else {
- ok = this.prompt.promptUsernameAndPassword(null, message, authTarget, Ci.nsIAuthPrompt.SAVE_PASSWORD_PERMANENTLY, username, password);
- }
-
- if (ok) {
- PromptUtils.setAuthInfo(aAuthInfo, username.value, password.value);
- }
- return ok;
- },
-
- asyncPromptAuth: function(aChannel, aCallback, aContext, aLevel, aAuthInfo, aCheckLabel, aCheckValue) {
- throw Cr.NS_ERROR_NOT_IMPLEMENTED;
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([PromptService, AuthPromptAdapterFactory]);
diff --git a/mobile/android/components/SessionStore.idl b/mobile/android/components/SessionStore.idl
deleted file mode 100644
index 14ddd5834..000000000
--- a/mobile/android/components/SessionStore.idl
+++ /dev/null
@@ -1,86 +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/. */
-
-#include "nsISupports.idl"
-
-interface nsIDOMWindow;
-interface nsIDOMNode;
-
-/**
- * nsISessionStore keeps track of the current browsing state.
- *
- * The nsISessionStore API operates mostly on browser windows and the browser
- * tabs contained in them.
- */
-
-[scriptable, uuid(da9ffc70-d444-47d4-b4ab-df3fb0fd24d0)]
-interface nsISessionStore : nsISupports
-{
- /**
- * Get the current browsing state.
- * @returns a JSON string representing the session state.
- */
- AString getBrowserState();
-
- /**
- * Get the number of restore-able tabs for a browser window
- */
- unsigned long getClosedTabCount(in nsIDOMWindow aWindow);
-
- /**
- * Get closed tab data
- *
- * @param aWindow is the browser window for which to get closed tab data
- * @returns a JS array of closed tabs.
- */
- jsval getClosedTabs(in nsIDOMWindow aWindow);
-
- /**
- * @param aWindow is the browser window to reopen a closed tab in.
- * @param aCloseTabData is the data of the tab to be restored.
- * @returns a reference to the reopened tab.
- */
- nsIDOMNode undoCloseTab(in nsIDOMWindow aWindow, in jsval aCloseTabData);
-
- /**
- * @param aWindow is the browser window associated with the closed tab.
- * @param aIndex is the index of the closed tab to be removed (FIFO ordered).
- */
- nsIDOMNode forgetClosedTab(in nsIDOMWindow aWindow, in unsigned long aIndex);
-
- /**
- * @param aTab is the browser tab to get the value for.
- * @param aKey is the value's name.
- *
- * @returns A string value or an empty string if none is set.
- */
- AString getTabValue(in jsval aTab, in AString aKey);
-
- /**
- * @param aTab is the browser tab to set the value for.
- * @param aKey is the value's name.
- * @param aStringValue is the value itself (use JSON.stringify/parse before setting JS objects).
- */
- void setTabValue(in jsval aTab, in AString aKey, in AString aStringValue);
-
- /**
- * @param aTab is the browser tab to get the value for.
- * @param aKey is the value's name.
- */
- void deleteTabValue(in jsval aTab, in AString aKey);
-
- /**
- * Restores the previous browser session using a fast, lightweight strategy
- * @param aSessionString The session string to restore from. If null, the
- * backup session file is read from.
- */
- void restoreLastSession(in AString aSessionString);
-
- /**
- * Removes a window from the current session history. Data from this window
- * won't be saved when its closed.
- * @param aWindow The window to remove
- */
- void removeWindow(in nsIDOMWindow aWindow);
-};
diff --git a/mobile/android/components/SessionStore.js b/mobile/android/components/SessionStore.js
deleted file mode 100644
index a23c52fe3..000000000
--- a/mobile/android/components/SessionStore.js
+++ /dev/null
@@ -1,1791 +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/. */
-
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-const Cr = Components.results;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Messaging", "resource://gre/modules/Messaging.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "FormData", "resource://gre/modules/FormData.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ScrollPosition", "resource://gre/modules/ScrollPosition.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Log", "resource://gre/modules/AndroidLog.jsm", "AndroidLog");
-XPCOMUtils.defineLazyModuleGetter(this, "SharedPreferences", "resource://gre/modules/SharedPreferences.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Utils", "resource://gre/modules/sessionstore/Utils.jsm");
-XPCOMUtils.defineLazyServiceGetter(this, "serializationHelper",
- "@mozilla.org/network/serialization-helper;1",
- "nsISerializationHelper");
-
-function dump(a) {
- Services.console.logStringMessage(a);
-}
-
-let loggingEnabled = false;
-
-function log(a) {
- if (!loggingEnabled) {
- return;
- }
- Log.d("SessionStore", a);
-}
-
-// -----------------------------------------------------------------------
-// Session Store
-// -----------------------------------------------------------------------
-
-const STATE_STOPPED = 0;
-const STATE_RUNNING = 1;
-const STATE_QUITTING = -1;
-const STATE_QUITTING_FLUSHED = -2;
-
-const PRIVACY_NONE = 0;
-const PRIVACY_ENCRYPTED = 1;
-const PRIVACY_FULL = 2;
-
-const PREFS_RESTORE_FROM_CRASH = "browser.sessionstore.resume_from_crash";
-const PREFS_MAX_CRASH_RESUMES = "browser.sessionstore.max_resumed_crashes";
-
-const MINIMUM_SAVE_DELAY = 2000;
-// We reduce the delay in background because we could be killed at any moment,
-// however we don't set it to 0 in order to allow for multiple events arriving
-// one after the other to be batched together in one write operation.
-const MINIMUM_SAVE_DELAY_BACKGROUND = 200;
-
-function SessionStore() { }
-
-SessionStore.prototype = {
- classID: Components.ID("{8c1f07d6-cba3-4226-a315-8bd43d67d032}"),
-
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISessionStore,
- Ci.nsIDOMEventListener,
- Ci.nsIObserver,
- Ci.nsISupportsWeakReference]),
-
- _windows: {},
- _lastSaveTime: 0,
- _lastBackupTime: 0,
- _interval: 10000,
- _backupInterval: 120000, // 2 minutes
- _minSaveDelay: MINIMUM_SAVE_DELAY,
- _maxTabsUndo: 5,
- _pendingWrite: 0,
- _scrollSavePending: null,
- _writeInProgress: false,
-
- // We only want to start doing backups if we've successfully
- // written the session data at least once.
- _sessionDataIsGood: false,
-
- // The index where the most recently closed tab was in the tabs array
- // when it was closed.
- _lastClosedTabIndex: -1,
-
- // Whether or not to send notifications for changes to the closed tabs.
- _notifyClosedTabs: false,
-
- // If we're simultaneously closing both a tab and Firefox, we don't want
- // to bother reloading the newly selected tab if it is zombified.
- // The Java UI will tell us which tab to watch out for.
- _keepAsZombieTabId: -1,
-
- init: function ss_init() {
- loggingEnabled = Services.prefs.getBoolPref("browser.sessionstore.debug_logging");
-
- // Get file references
- this._sessionFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
- this._sessionFileBackup = this._sessionFile.clone();
- this._sessionFilePrevious = this._sessionFile.clone();
- this._sessionFileTemp = this._sessionFile.clone();
- this._sessionFile.append("sessionstore.js"); // The main session store save file.
- this._sessionFileBackup.append("sessionstore.bak"); // A backup copy to guard against interrupted writes.
- this._sessionFilePrevious.append("sessionstore.old"); // The previous session's file, used for what used to be the "Tabs from last time".
- this._sessionFileTemp.append(this._sessionFile.leafName + ".tmp"); // Temporary file for writing changes to disk.
-
- this._loadState = STATE_STOPPED;
- this._startupRestoreFinished = false;
-
- this._interval = Services.prefs.getIntPref("browser.sessionstore.interval");
- this._backupInterval = Services.prefs.getIntPref("browser.sessionstore.backupInterval");
- this._maxTabsUndo = Services.prefs.getIntPref("browser.sessionstore.max_tabs_undo");
-
- // Copy changes in Gecko settings to their Java counterparts,
- // so the startup code can access them
- Services.prefs.addObserver(PREFS_RESTORE_FROM_CRASH, function() {
- SharedPreferences.forApp().setBoolPref(PREFS_RESTORE_FROM_CRASH,
- Services.prefs.getBoolPref(PREFS_RESTORE_FROM_CRASH));
- }, false);
- Services.prefs.addObserver(PREFS_MAX_CRASH_RESUMES, function() {
- SharedPreferences.forApp().setIntPref(PREFS_MAX_CRASH_RESUMES,
- Services.prefs.getIntPref(PREFS_MAX_CRASH_RESUMES));
- }, false);
- },
-
- _clearDisk: function ss_clearDisk() {
- this._sessionDataIsGood = false;
-
- if (this._loadState > STATE_QUITTING) {
- OS.File.remove(this._sessionFile.path);
- OS.File.remove(this._sessionFileBackup.path);
- OS.File.remove(this._sessionFilePrevious.path);
- OS.File.remove(this._sessionFileTemp.path);
- } else { // We're shutting down and must delete synchronously
- if (this._sessionFile.exists()) { this._sessionFile.remove(false); }
- if (this._sessionFileBackup.exists()) { this._sessionFileBackup.remove(false); }
- if (this._sessionFileBackup.exists()) { this._sessionFilePrevious.remove(false); }
- if (this._sessionFileBackup.exists()) { this._sessionFileTemp.remove(false); }
- }
- },
-
- observe: function ss_observe(aSubject, aTopic, aData) {
- let self = this;
- let observerService = Services.obs;
- switch (aTopic) {
- case "app-startup":
- observerService.addObserver(this, "final-ui-startup", true);
- observerService.addObserver(this, "domwindowopened", true);
- observerService.addObserver(this, "domwindowclosed", true);
- observerService.addObserver(this, "browser:purge-session-history", true);
- observerService.addObserver(this, "quit-application-requested", true);
- observerService.addObserver(this, "quit-application-proceeding", true);
- observerService.addObserver(this, "quit-application", true);
- observerService.addObserver(this, "Session:Restore", true);
- observerService.addObserver(this, "Session:NotifyLocationChange", true);
- observerService.addObserver(this, "Tab:KeepZombified", true);
- observerService.addObserver(this, "application-background", true);
- observerService.addObserver(this, "application-foreground", true);
- observerService.addObserver(this, "ClosedTabs:StartNotifications", true);
- observerService.addObserver(this, "ClosedTabs:StopNotifications", true);
- observerService.addObserver(this, "last-pb-context-exited", true);
- observerService.addObserver(this, "Session:RestoreRecentTabs", true);
- observerService.addObserver(this, "Tabs:OpenMultiple", true);
- break;
- case "final-ui-startup":
- observerService.removeObserver(this, "final-ui-startup");
- this.init();
- break;
- case "domwindowopened": {
- let window = aSubject;
- window.addEventListener("load", function() {
- self.onWindowOpen(window);
- window.removeEventListener("load", arguments.callee, false);
- }, false);
- break;
- }
- case "domwindowclosed": // catch closed windows
- this.onWindowClose(aSubject);
- break;
- case "quit-application-requested":
- log("quit-application-requested");
- // Get a current snapshot of all windows
- if (this._pendingWrite) {
- this._forEachBrowserWindow(function(aWindow) {
- self._collectWindowData(aWindow);
- });
- }
- break;
- case "quit-application-proceeding":
- log("quit-application-proceeding");
- // Freeze the data at what we've got (ignoring closing windows)
- this._loadState = STATE_QUITTING;
- break;
- case "quit-application":
- log("quit-application");
- observerService.removeObserver(this, "domwindowopened");
- observerService.removeObserver(this, "domwindowclosed");
- observerService.removeObserver(this, "quit-application-requested");
- observerService.removeObserver(this, "quit-application-proceeding");
- observerService.removeObserver(this, "quit-application");
-
- // Flush all pending writes to disk now
- this.flushPendingState();
- this._loadState = STATE_QUITTING_FLUSHED;
-
- break;
- case "browser:purge-session-history": // catch sanitization
- log("browser:purge-session-history");
- this._clearDisk();
-
- // Clear all data about closed tabs
- for (let [ssid, win] of Object.entries(this._windows))
- win.closedTabs = [];
-
- this._lastClosedTabIndex = -1;
-
- if (this._loadState == STATE_RUNNING) {
- // Save the purged state immediately
- this.saveState();
- } else if (this._loadState <= STATE_QUITTING) {
- this.saveStateDelayed();
- if (this._loadState == STATE_QUITTING_FLUSHED) {
- this.flushPendingState();
- }
- }
-
- Services.obs.notifyObservers(null, "sessionstore-state-purge-complete", "");
- if (this._notifyClosedTabs) {
- this._sendClosedTabsToJava(Services.wm.getMostRecentWindow("navigator:browser"));
- }
- break;
- case "timer-callback":
- if (this._loadState == STATE_RUNNING) {
- // Timer call back for delayed saving
- this._saveTimer = null;
- log("timer-callback, pendingWrite = " + this._pendingWrite);
- if (this._pendingWrite) {
- this.saveState();
- }
- }
- break;
- case "Session:Restore": {
- Services.obs.removeObserver(this, "Session:Restore");
- if (aData) {
- // Be ready to handle any restore failures by making sure we have a valid tab opened
- let window = Services.wm.getMostRecentWindow("navigator:browser");
- let restoreCleanup = {
- observe: function (aSubject, aTopic, aData) {
- Services.obs.removeObserver(restoreCleanup, "sessionstore-windows-restored");
-
- if (window.BrowserApp.tabs.length == 0) {
- window.BrowserApp.addTab("about:home", {
- selected: true
- });
- }
- // Normally, _restoreWindow() will have set this to true already,
- // but we want to make sure it's set even in case of a restore failure.
- this._startupRestoreFinished = true;
- log("startupRestoreFinished = true (through notification)");
- }.bind(this)
- };
- Services.obs.addObserver(restoreCleanup, "sessionstore-windows-restored", false);
-
- // Do a restore, triggered by Java
- let data = JSON.parse(aData);
- this.restoreLastSession(data.sessionString);
- } else {
- // Not doing a restore; just send restore message
- this._startupRestoreFinished = true;
- log("startupRestoreFinished = true");
- Services.obs.notifyObservers(null, "sessionstore-windows-restored", "");
- }
- break;
- }
- case "Session:NotifyLocationChange": {
- let browser = aSubject;
-
- if (browser.__SS_restoreReloadPending && this._startupRestoreFinished) {
- delete browser.__SS_restoreReloadPending;
- log("remove restoreReloadPending");
- }
-
- if (browser.__SS_restoreDataOnLocationChange) {
- delete browser.__SS_restoreDataOnLocationChange;
- this._restoreZoom(browser.__SS_data.scrolldata, browser);
- }
- break;
- }
- case "Tabs:OpenMultiple": {
- let data = JSON.parse(aData);
-
- this._openTabs(data);
-
- if (data.shouldNotifyTabsOpenedToJava) {
- Messaging.sendRequest({
- type: "Tabs:TabsOpened"
- });
- }
- break;
- }
- case "Tab:KeepZombified": {
- if (aData >= 0) {
- this._keepAsZombieTabId = aData;
- log("Tab:KeepZombified " + aData);
- }
- break;
- }
- case "application-background":
- // We receive this notification when Android's onPause callback is
- // executed. After onPause, the application may be terminated at any
- // point without notice; therefore, we must synchronously write out any
- // pending save state to ensure that this data does not get lost.
- log("application-background");
- // Tab events dispatched immediately before the application was backgrounded
- // might actually arrive after this point, therefore save them without delay.
- if (this._loadState == STATE_RUNNING) {
- this._interval = 0;
- this._minSaveDelay = MINIMUM_SAVE_DELAY_BACKGROUND; // A small delay allows successive tab events to be batched together.
- this.flushPendingState();
- }
- break;
- case "application-foreground":
- // Reset minimum interval between session store writes back to default.
- log("application-foreground");
- this._interval = Services.prefs.getIntPref("browser.sessionstore.interval");
- this._minSaveDelay = MINIMUM_SAVE_DELAY;
-
- // If we skipped restoring a zombified tab before backgrounding,
- // we might have to do it now instead.
- let window = Services.wm.getMostRecentWindow("navigator:browser");
- if (window) { // Might not yet be ready during a cold startup.
- let tab = window.BrowserApp.selectedTab;
- if (tab.browser.__SS_restore) {
- this._restoreZombieTab(tab.browser, tab.id);
- }
- }
- break;
- case "ClosedTabs:StartNotifications":
- this._notifyClosedTabs = true;
- log("ClosedTabs:StartNotifications");
- this._sendClosedTabsToJava(Services.wm.getMostRecentWindow("navigator:browser"));
- break;
- case "ClosedTabs:StopNotifications":
- this._notifyClosedTabs = false;
- log("ClosedTabs:StopNotifications");
- break;
- case "last-pb-context-exited":
- // Clear private closed tab data when we leave private browsing.
- for (let window of Object.values(this._windows)) {
- window.closedTabs = window.closedTabs.filter(tab => !tab.isPrivate);
- }
- this._lastClosedTabIndex = -1;
- break;
- case "Session:RestoreRecentTabs": {
- let data = JSON.parse(aData);
- this._restoreTabs(data);
- break;
- }
- }
- },
-
- handleEvent: function ss_handleEvent(aEvent) {
- let window = aEvent.currentTarget.ownerDocument.defaultView;
- switch (aEvent.type) {
- case "TabOpen": {
- let browser = aEvent.target;
- log("TabOpen for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- this.onTabAdd(window, browser);
- break;
- }
- case "TabClose": {
- let browser = aEvent.target;
- log("TabClose for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- this.onTabClose(window, browser, aEvent.detail);
- this.onTabRemove(window, browser);
- break;
- }
- case "TabPreZombify": {
- let browser = aEvent.target;
- log("TabPreZombify for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- this.onTabRemove(window, browser, true);
- break;
- }
- case "TabPostZombify": {
- let browser = aEvent.target;
- log("TabPostZombify for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- this.onTabAdd(window, browser, true);
- break;
- }
- case "TabSelect": {
- let browser = aEvent.target;
- log("TabSelect for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- this.onTabSelect(window, browser);
- break;
- }
- case "DOMTitleChanged": {
- // Use DOMTitleChanged to detect page loads over alternatives.
- // onLocationChange happens too early, so we don't have the page title
- // yet; pageshow happens too late, so we could lose session data if the
- // browser were killed.
- let browser = aEvent.currentTarget;
- log("DOMTitleChanged for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- this.onTabLoad(window, browser);
- break;
- }
- case "load": {
- let browser = aEvent.currentTarget;
-
- // Skip subframe loads.
- if (browser.contentDocument !== aEvent.originalTarget) {
- return;
- }
-
- // Handle restoring the text data into the content and frames.
- // We wait until the main content and all frames are loaded
- // before trying to restore this data.
- log("load for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- if (browser.__SS_restoreDataOnLoad) {
- delete browser.__SS_restoreDataOnLoad;
- this._restoreTextData(browser.__SS_data.formdata, browser);
- }
- break;
- }
- case "pageshow":
- case "AboutReaderContentReady": {
- let browser = aEvent.currentTarget;
-
- // Skip subframe pageshows.
- if (browser.contentDocument !== aEvent.originalTarget) {
- return;
- }
-
- if (browser.currentURI.spec.startsWith("about:reader") &&
- !browser.contentDocument.body.classList.contains("loaded")) {
- // Don't restore the scroll position of an about:reader page at this point;
- // wait for the custom event dispatched from AboutReader.jsm instead.
- return;
- }
-
- // Restoring the scroll position needs to happen after the zoom level has been
- // restored, which is done by the MobileViewportManager either on first paint
- // or on load, whichever comes first.
- // In the latter case, our load handler runs before the MVM's one, which is the
- // wrong way around, so we have to use a later event instead.
- log(aEvent.type + " for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- if (browser.__SS_restoreDataOnPageshow) {
- delete browser.__SS_restoreDataOnPageshow;
- this._restoreScrollPosition(browser.__SS_data.scrolldata, browser);
- } else {
- // We're not restoring, capture the initial scroll position on pageshow.
- this.onTabScroll(window, browser);
- }
- break;
- }
- case "change":
- case "input":
- case "DOMAutoComplete": {
- let browser = aEvent.currentTarget;
- log("TabInput for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- this.onTabInput(window, browser);
- break;
- }
- case "resize":
- case "scroll": {
- let browser = aEvent.currentTarget;
- // Duplicated logging check to avoid calling getTabForBrowser on each scroll event.
- if (loggingEnabled) {
- log(aEvent.type + " for tab " + window.BrowserApp.getTabForBrowser(browser).id);
- }
- if (!this._scrollSavePending) {
- this._scrollSavePending =
- window.setTimeout(() => {
- this._scrollSavePending = null;
- this.onTabScroll(window, browser);
- }, 500);
- }
- break;
- }
- }
- },
-
- onWindowOpen: function ss_onWindowOpen(aWindow) {
- // Return if window has already been initialized
- if (aWindow && aWindow.__SSID && this._windows[aWindow.__SSID]) {
- return;
- }
-
- // Ignore non-browser windows and windows opened while shutting down
- if (aWindow.document.documentElement.getAttribute("windowtype") != "navigator:browser" || this._loadState <= STATE_QUITTING) {
- return;
- }
-
- // Assign it a unique identifier (timestamp) and create its data object
- aWindow.__SSID = "window" + Date.now();
- this._windows[aWindow.__SSID] = { tabs: [], selected: 0, closedTabs: [] };
-
- // Perform additional initialization when the first window is loading
- if (this._loadState == STATE_STOPPED) {
- this._loadState = STATE_RUNNING;
- this._lastSaveTime = Date.now();
- }
-
- // Add tab change listeners to all already existing tabs
- let tabs = aWindow.BrowserApp.tabs;
- for (let i = 0; i < tabs.length; i++)
- this.onTabAdd(aWindow, tabs[i].browser, true);
-
- // Notification of tab add/remove/selection/zombification
- let browsers = aWindow.document.getElementById("browsers");
- browsers.addEventListener("TabOpen", this, true);
- browsers.addEventListener("TabClose", this, true);
- browsers.addEventListener("TabSelect", this, true);
- browsers.addEventListener("TabPreZombify", this, true);
- browsers.addEventListener("TabPostZombify", this, true);
- },
-
- onWindowClose: function ss_onWindowClose(aWindow) {
- // Ignore windows not tracked by SessionStore
- if (!aWindow.__SSID || !this._windows[aWindow.__SSID]) {
- return;
- }
-
- let browsers = aWindow.document.getElementById("browsers");
- browsers.removeEventListener("TabOpen", this, true);
- browsers.removeEventListener("TabClose", this, true);
- browsers.removeEventListener("TabSelect", this, true);
- browsers.removeEventListener("TabPreZombify", this, true);
- browsers.removeEventListener("TabPostZombify", this, true);
-
- if (this._loadState == STATE_RUNNING) {
- // Update all window data for a last time
- this._collectWindowData(aWindow);
-
- // Clear this window from the list
- delete this._windows[aWindow.__SSID];
-
- // Save the state without this window to disk
- this.saveStateDelayed();
- }
-
- let tabs = aWindow.BrowserApp.tabs;
- for (let i = 0; i < tabs.length; i++)
- this.onTabRemove(aWindow, tabs[i].browser, true);
-
- delete aWindow.__SSID;
- },
-
- onTabAdd: function ss_onTabAdd(aWindow, aBrowser, aNoNotification) {
- // Use DOMTitleChange to catch the initial load and restore history
- aBrowser.addEventListener("DOMTitleChanged", this, true);
-
- // Use load to restore text data
- aBrowser.addEventListener("load", this, true);
-
- // Gecko might set the initial zoom level after the JS "load" event,
- // so we have to restore zoom and scroll position after that.
- aBrowser.addEventListener("pageshow", this, true);
- aBrowser.addEventListener("AboutReaderContentReady", this, true);
-
- // Use a combination of events to watch for text data changes
- aBrowser.addEventListener("change", this, true);
- aBrowser.addEventListener("input", this, true);
- aBrowser.addEventListener("DOMAutoComplete", this, true);
-
- // Record the current scroll position and zoom level.
- aBrowser.addEventListener("scroll", this, true);
- aBrowser.addEventListener("resize", this, true);
-
- log("onTabAdd() ran for tab " + aWindow.BrowserApp.getTabForBrowser(aBrowser).id +
- ", aNoNotification = " + aNoNotification);
- if (!aNoNotification) {
- this.saveStateDelayed();
- }
- this._updateCrashReportURL(aWindow);
- },
-
- onTabRemove: function ss_onTabRemove(aWindow, aBrowser, aNoNotification) {
- // Cleanup event listeners
- aBrowser.removeEventListener("DOMTitleChanged", this, true);
- aBrowser.removeEventListener("load", this, true);
- aBrowser.removeEventListener("pageshow", this, true);
- aBrowser.removeEventListener("AboutReaderContentReady", this, true);
- aBrowser.removeEventListener("change", this, true);
- aBrowser.removeEventListener("input", this, true);
- aBrowser.removeEventListener("DOMAutoComplete", this, true);
- aBrowser.removeEventListener("scroll", this, true);
- aBrowser.removeEventListener("resize", this, true);
-
- delete aBrowser.__SS_data;
-
- log("onTabRemove() ran for tab " + aWindow.BrowserApp.getTabForBrowser(aBrowser).id +
- ", aNoNotification = " + aNoNotification);
- if (!aNoNotification) {
- this.saveStateDelayed();
- }
- },
-
- onTabClose: function ss_onTabClose(aWindow, aBrowser, aTabIndex) {
- if (this._maxTabsUndo == 0) {
- return;
- }
-
- if (aWindow.BrowserApp.tabs.length > 0) {
- // Bundle this browser's data and extra data and save in the closedTabs
- // window property
- let data = aBrowser.__SS_data || {};
- data.extData = aBrowser.__SS_extdata || {};
-
- this._windows[aWindow.__SSID].closedTabs.unshift(data);
- let length = this._windows[aWindow.__SSID].closedTabs.length;
- if (length > this._maxTabsUndo) {
- this._windows[aWindow.__SSID].closedTabs.splice(this._maxTabsUndo, length - this._maxTabsUndo);
- }
-
- this._lastClosedTabIndex = aTabIndex;
-
- if (this._notifyClosedTabs) {
- this._sendClosedTabsToJava(aWindow);
- }
-
- log("onTabClose() ran for tab " + aWindow.BrowserApp.getTabForBrowser(aBrowser).id);
- let evt = new Event("SSTabCloseProcessed", {"bubbles":true, "cancelable":false});
- aBrowser.dispatchEvent(evt);
- }
- },
-
- onTabLoad: function ss_onTabLoad(aWindow, aBrowser) {
- // If this browser belongs to a zombie tab or the initial restore hasn't yet finished,
- // skip any session save activity.
- if (aBrowser.__SS_restore || !this._startupRestoreFinished || aBrowser.__SS_restoreReloadPending) {
- return;
- }
-
- // Ignore a transient "about:blank"
- if (!aBrowser.canGoBack && aBrowser.currentURI.spec == "about:blank") {
- return;
- }
-
- let history = aBrowser.sessionHistory;
-
- // Serialize the tab data
- let entries = [];
- let index = history.index + 1;
- for (let i = 0; i < history.count; i++) {
- let historyEntry = history.getEntryAtIndex(i, false);
- // Don't try to restore wyciwyg URLs
- if (historyEntry.URI.schemeIs("wyciwyg")) {
- // Adjust the index to account for skipped history entries
- if (i <= history.index) {
- index--;
- }
- continue;
- }
- let entry = this._serializeHistoryEntry(historyEntry);
- entries.push(entry);
- }
- let data = { entries: entries, index: index };
-
- let formdata;
- let scrolldata;
- if (aBrowser.__SS_data) {
- formdata = aBrowser.__SS_data.formdata;
- scrolldata = aBrowser.__SS_data.scrolldata;
- }
- delete aBrowser.__SS_data;
-
- this._collectTabData(aWindow, aBrowser, data);
- if (aBrowser.__SS_restoreDataOnLoad || aBrowser.__SS_restoreDataOnPageshow) {
- // If the tab has been freshly restored and the "load" or "pageshow"
- // events haven't yet fired, we need to preserve any form data and
- // scroll positions that might have been present.
- aBrowser.__SS_data.formdata = formdata;
- aBrowser.__SS_data.scrolldata = scrolldata;
- } else {
- // When navigating via the forward/back buttons, Gecko restores
- // the form data all by itself and doesn't invoke any input events.
- // As _collectTabData() doesn't save any form data, we need to manually
- // capture it to bridge the time until the next input event arrives.
- this.onTabInput(aWindow, aBrowser);
- }
-
- log("onTabLoad() ran for tab " + aWindow.BrowserApp.getTabForBrowser(aBrowser).id);
- let evt = new Event("SSTabDataUpdated", {"bubbles":true, "cancelable":false});
- aBrowser.dispatchEvent(evt);
- this.saveStateDelayed();
-
- this._updateCrashReportURL(aWindow);
- },
-
- onTabSelect: function ss_onTabSelect(aWindow, aBrowser) {
- if (this._loadState != STATE_RUNNING) {
- return;
- }
-
- let browsers = aWindow.document.getElementById("browsers");
- let index = browsers.selectedIndex;
- this._windows[aWindow.__SSID].selected = parseInt(index) + 1; // 1-based
-
- let tabId = aWindow.BrowserApp.getTabForBrowser(aBrowser).id;
-
- // Restore the resurrected browser
- if (aBrowser.__SS_restore) {
- if (tabId != this._keepAsZombieTabId) {
- this._restoreZombieTab(aBrowser, tabId);
- } else {
- log("keeping as zombie tab " + tabId);
- }
- }
- // The tab id passed through Tab:KeepZombified is valid for one TabSelect only.
- this._keepAsZombieTabId = -1;
-
- log("onTabSelect() ran for tab " + tabId);
- this.saveStateDelayed();
- this._updateCrashReportURL(aWindow);
-
- // If the selected tab has changed while listening for closed tab
- // notifications, we may have switched between different private browsing
- // modes.
- if (this._notifyClosedTabs) {
- this._sendClosedTabsToJava(aWindow);
- }
- },
-
- _restoreZombieTab: function ss_restoreZombieTab(aBrowser, aTabId) {
- let data = aBrowser.__SS_data;
- this._restoreTab(data, aBrowser);
-
- delete aBrowser.__SS_restore;
- aBrowser.removeAttribute("pending");
- log("restoring zombie tab " + aTabId);
- },
-
- onTabInput: function ss_onTabInput(aWindow, aBrowser) {
- // If this browser belongs to a zombie tab or the initial restore hasn't yet finished,
- // skip any session save activity.
- if (aBrowser.__SS_restore || !this._startupRestoreFinished || aBrowser.__SS_restoreReloadPending) {
- return;
- }
-
- // Don't bother trying to save text data if we don't have history yet
- let data = aBrowser.__SS_data;
- if (!data || data.entries.length == 0) {
- return;
- }
-
- // Start with storing the main content
- let content = aBrowser.contentWindow;
-
- // If the main content document has an associated URL that we are not
- // allowed to store data for, bail out. We explicitly discard data for any
- // children as well even if storing data for those frames would be allowed.
- if (!this.checkPrivacyLevel(content.document.documentURI)) {
- return;
- }
-
- // Store the main content
- let formdata = FormData.collect(content) || {};
-
- // Loop over direct child frames, and store the text data
- let children = [];
- for (let i = 0; i < content.frames.length; i++) {
- let frame = content.frames[i];
- if (!this.checkPrivacyLevel(frame.document.documentURI)) {
- continue;
- }
-
- let result = FormData.collect(frame);
- if (result && Object.keys(result).length) {
- children[i] = result;
- }
- }
-
- // If any frame had text data, add it to the main form data
- if (children.length) {
- formdata.children = children;
- }
-
- // If we found any form data, main content or frames, let's save it
- if (Object.keys(formdata).length) {
- data.formdata = formdata;
- log("onTabInput() ran for tab " + aWindow.BrowserApp.getTabForBrowser(aBrowser).id);
- this.saveStateDelayed();
- }
- },
-
- onTabScroll: function ss_onTabScroll(aWindow, aBrowser) {
- // If we've been called directly, cancel any pending timeouts.
- if (this._scrollSavePending) {
- aWindow.clearTimeout(this._scrollSavePending);
- this._scrollSavePending = null;
- log("onTabScroll() clearing pending timeout");
- }
-
- // If this browser belongs to a zombie tab or the initial restore hasn't yet finished,
- // skip any session save activity.
- if (aBrowser.__SS_restore || !this._startupRestoreFinished || aBrowser.__SS_restoreReloadPending) {
- return;
- }
-
- // Don't bother trying to save scroll positions if we don't have history yet.
- let data = aBrowser.__SS_data;
- if (!data || data.entries.length == 0) {
- return;
- }
-
- // Neither bother if we're yet to restore the previous scroll position.
- if (aBrowser.__SS_restoreDataOnLoad || aBrowser.__SS_restoreDataOnPageshow) {
- return;
- }
-
- // Start with storing the main content.
- let content = aBrowser.contentWindow;
-
- // Store the main content.
- let scrolldata = ScrollPosition.collect(content) || {};
-
- // Loop over direct child frames, and store the scroll positions.
- let children = [];
- for (let i = 0; i < content.frames.length; i++) {
- let frame = content.frames[i];
-
- let result = ScrollPosition.collect(frame);
- if (result && Object.keys(result).length) {
- children[i] = result;
- }
- }
-
- // If any frame had scroll positions, add them to the main scroll data.
- if (children.length) {
- scrolldata.children = children;
- }
-
- // Save the current document resolution.
- let zoom = { value: 1 };
- content.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(
- Ci.nsIDOMWindowUtils).getResolution(zoom);
- scrolldata.zoom = {};
- scrolldata.zoom.resolution = zoom.value;
- log("onTabScroll() zoom level: " + zoom.value);
-
- // Save some data that'll help in adjusting the zoom level
- // when restoring in a different screen orientation.
- scrolldata.zoom.displaySize = this._getContentViewerSize(content);
- log("onTabScroll() displayWidth: " + scrolldata.zoom.displaySize.width);
-
- // Save zoom and scroll data.
- data.scrolldata = scrolldata;
- log("onTabScroll() ran for tab " + aWindow.BrowserApp.getTabForBrowser(aBrowser).id);
- let evt = new Event("SSTabScrollCaptured", {"bubbles":true, "cancelable":false});
- aBrowser.dispatchEvent(evt);
- this.saveStateDelayed();
- },
-
- _getContentViewerSize: function ss_getContentViewerSize(aWindow) {
- let displaySize = {};
- let width = {}, height = {};
- aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(
- Ci.nsIDOMWindowUtils).getContentViewerSize(width, height);
-
- displaySize.width = width.value;
- displaySize.height = height.value;
-
- return displaySize;
- },
-
- saveStateDelayed: function ss_saveStateDelayed() {
- if (!this._saveTimer) {
- // Interval until the next disk operation is allowed
- let currentDelay = this._lastSaveTime + this._interval - Date.now();
-
- // If we have to wait, set a timer, otherwise saveState directly
- let delay = Math.max(currentDelay, this._minSaveDelay);
- if (delay > 0) {
- this._pendingWrite++;
- this._saveTimer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
- this._saveTimer.init(this, delay, Ci.nsITimer.TYPE_ONE_SHOT);
- log("saveStateDelayed() timer delay = " + delay +
- ", incrementing _pendingWrite to " + this._pendingWrite);
- } else {
- log("saveStateDelayed() no delay");
- this.saveState();
- }
- } else {
- log("saveStateDelayed() timer already running, taking no action");
- }
- },
-
- saveState: function ss_saveState() {
- this._pendingWrite++;
- log("saveState(), incrementing _pendingWrite to " + this._pendingWrite);
- this._saveState(true);
- },
-
- // Immediately and synchronously writes any pending state to disk.
- flushPendingState: function ss_flushPendingState() {
- log("flushPendingState(), _pendingWrite = " + this._pendingWrite);
- if (this._pendingWrite) {
- this._saveState(false);
- }
- },
-
- _saveState: function ss_saveState(aAsync) {
- log("_saveState(aAsync = " + aAsync + ")");
- // Kill any queued timer and save immediately
- if (this._saveTimer) {
- this._saveTimer.cancel();
- this._saveTimer = null;
- log("_saveState() killed queued timer");
- }
-
- // Periodically save a "known good" copy of the session store data.
- if (!this._writeInProgress && Date.now() - this._lastBackupTime > this._backupInterval &&
- this._sessionDataIsGood && this._sessionFile.exists()) {
- if (this._sessionFileBackup.exists()) {
- this._sessionFileBackup.remove(false);
- }
-
- log("_saveState() backing up session data");
- this._sessionFile.copyTo(null, this._sessionFileBackup.leafName);
- this._lastBackupTime = Date.now();
- }
-
- let data = this._getCurrentState();
- let normalData = { windows: [] };
- let privateData = { windows: [] };
- log("_saveState() current state collected");
-
- for (let winIndex = 0; winIndex < data.windows.length; ++winIndex) {
- let win = data.windows[winIndex];
- let normalWin = {};
- for (let prop in win) {
- normalWin[prop] = data[prop];
- }
- normalWin.tabs = [];
-
- // Save normal closed tabs. Forget about private closed tabs.
- normalWin.closedTabs = win.closedTabs.filter(tab => !tab.isPrivate);
-
- normalData.windows.push(normalWin);
- privateData.windows.push({ tabs: [] });
-
- // Split the session data into private and non-private data objects.
- // Non-private session data will be saved to disk, and private session
- // data will be sent to Java for Android to hold it in memory.
- for (let i = 0; i < win.tabs.length; ++i) {
- let tab = win.tabs[i];
- let savedWin = tab.isPrivate ? privateData.windows[winIndex] : normalData.windows[winIndex];
- savedWin.tabs.push(tab);
- if (win.selected == i + 1) {
- savedWin.selected = savedWin.tabs.length;
- }
- }
- }
-
- // Write only non-private data to disk
- if (normalData.windows[0] && normalData.windows[0].tabs) {
- log("_saveState() writing normal data, " +
- normalData.windows[0].tabs.length + " tabs in window[0]");
- } else {
- log("_saveState() writing empty normal data");
- }
- this._writeFile(this._sessionFile, this._sessionFileTemp, normalData, aAsync);
-
- // If we have private data, send it to Java; otherwise, send null to
- // indicate that there is no private data
- Messaging.sendRequest({
- type: "PrivateBrowsing:Data",
- session: (privateData.windows.length > 0 && privateData.windows[0].tabs.length > 0) ? JSON.stringify(privateData) : null
- });
-
- this._lastSaveTime = Date.now();
- },
-
- _getCurrentState: function ss_getCurrentState() {
- let self = this;
- this._forEachBrowserWindow(function(aWindow) {
- self._collectWindowData(aWindow);
- });
-
- let data = { windows: [] };
- for (let index in this._windows) {
- data.windows.push(this._windows[index]);
- }
-
- return data;
- },
-
- _collectTabData: function ss__collectTabData(aWindow, aBrowser, aHistory) {
- // If this browser is being restored, skip any session save activity
- if (aBrowser.__SS_restore) {
- return;
- }
-
- aHistory = aHistory || { entries: [{ url: aBrowser.currentURI.spec, title: aBrowser.contentTitle }], index: 1 };
-
- let tabData = {};
- tabData.entries = aHistory.entries;
- tabData.index = aHistory.index;
- tabData.attributes = { image: aBrowser.mIconURL };
- tabData.desktopMode = aWindow.BrowserApp.getTabForBrowser(aBrowser).desktopMode;
- tabData.isPrivate = aBrowser.docShell.QueryInterface(Ci.nsILoadContext).usePrivateBrowsing;
-
- aBrowser.__SS_data = tabData;
- },
-
- _collectWindowData: function ss__collectWindowData(aWindow) {
- // Ignore windows not tracked by SessionStore
- if (!aWindow.__SSID || !this._windows[aWindow.__SSID]) {
- return;
- }
-
- let winData = this._windows[aWindow.__SSID];
- winData.tabs = [];
-
- let browsers = aWindow.document.getElementById("browsers");
- let index = browsers.selectedIndex;
- winData.selected = parseInt(index) + 1; // 1-based
-
- let tabs = aWindow.BrowserApp.tabs;
- for (let i = 0; i < tabs.length; i++) {
- let browser = tabs[i].browser;
- if (browser.__SS_data) {
- let tabData = browser.__SS_data;
- if (browser.__SS_extdata) {
- tabData.extData = browser.__SS_extdata;
- }
- winData.tabs.push(tabData);
- }
- }
- },
-
- _forEachBrowserWindow: function ss_forEachBrowserWindow(aFunc) {
- let windowsEnum = Services.wm.getEnumerator("navigator:browser");
- while (windowsEnum.hasMoreElements()) {
- let window = windowsEnum.getNext();
- if (window.__SSID && !window.closed) {
- aFunc.call(this, window);
- }
- }
- },
-
- /**
- * Writes the session state to a disk file, while doing some telemetry and notification
- * bookkeeping.
- * @param aFile nsIFile used for saving the session
- * @param aFileTemp nsIFile used as a temporary file in writing the data
- * @param aData JSON session state
- * @param aAsync boolelan used to determine the method of saving the state
- */
- _writeFile: function ss_writeFile(aFile, aFileTemp, aData, aAsync) {
- let state = JSON.stringify(aData);
-
- // Convert data string to a utf-8 encoded array buffer
- let buffer = new TextEncoder().encode(state);
- Services.telemetry.getHistogramById("FX_SESSION_RESTORE_FILE_SIZE_BYTES").add(buffer.byteLength);
-
- Services.obs.notifyObservers(null, "sessionstore-state-write", "");
- let startWriteMs = Cu.now();
-
- log("_writeFile(aAsync = " + aAsync + "), _pendingWrite = " + this._pendingWrite);
- this._writeInProgress = true;
- let pendingWrite = this._pendingWrite;
- this._write(aFile, aFileTemp, buffer, aAsync).then(() => {
- let stopWriteMs = Cu.now();
-
- // Make sure this._pendingWrite is the same value it was before we
- // fired off the async write. If the count is different, another write
- // is pending, so we shouldn't reset this._pendingWrite yet.
- if (pendingWrite === this._pendingWrite) {
- this._pendingWrite = 0;
- this._writeInProgress = false;
- }
-
- log("_writeFile() _write() returned, _pendingWrite = " + this._pendingWrite);
-
- // We don't use a stopwatch here since the calls are async and stopwatches can only manage
- // a single timer per histogram.
- Services.telemetry.getHistogramById("FX_SESSION_RESTORE_WRITE_FILE_MS").add(Math.round(stopWriteMs - startWriteMs));
- Services.obs.notifyObservers(null, "sessionstore-state-write-complete", "");
- this._sessionDataIsGood = true;
- });
- },
-
- /**
- * Writes the session state to a disk file, using async or sync methods
- * @param aFile nsIFile used for saving the session
- * @param aFileTemp nsIFile used as a temporary file in writing the data
- * @param aBuffer UTF-8 encoded ArrayBuffer of the session state
- * @param aAsync boolelan used to determine the method of saving the state
- * @return Promise that resolves when the file has been written
- */
- _write: function ss_write(aFile, aFileTemp, aBuffer, aAsync) {
- // Use async file writer and just return it's promise
- if (aAsync) {
- log("_write() writing asynchronously");
- return OS.File.writeAtomic(aFile.path, aBuffer, { tmpPath: aFileTemp.path });
- }
-
- // Convert buffer to an encoded string and sync write to disk
- let bytes = String.fromCharCode.apply(null, new Uint16Array(aBuffer));
- let stream = Cc["@mozilla.org/network/file-output-stream;1"].createInstance(Ci.nsIFileOutputStream);
- stream.init(aFileTemp, 0x02 | 0x08 | 0x20, 0o666, 0);
- stream.write(bytes, bytes.length);
- stream.close();
- // Mimic writeAtomic behaviour when tmpPath is set and write
- // to a temp file which is then renamed at the end.
- aFileTemp.renameTo(null, aFile.leafName);
- log("_write() writing synchronously");
-
- // Return a resolved promise to make the caller happy
- return Promise.resolve();
- },
-
- _updateCrashReportURL: function ss_updateCrashReportURL(aWindow) {
- let crashReporterBuilt = "nsICrashReporter" in Ci && Services.appinfo instanceof Ci.nsICrashReporter;
- if (!crashReporterBuilt) {
- return;
- }
-
- if (!aWindow.BrowserApp.selectedBrowser) {
- return;
- }
-
- try {
- let currentURI = aWindow.BrowserApp.selectedBrowser.currentURI.clone();
- // if the current URI contains a username/password, remove it
- try {
- currentURI.userPass = "";
- } catch (ex) { } // ignore failures on about: URIs
-
- Services.appinfo.annotateCrashReport("URL", currentURI.spec);
- } catch (ex) {
- // don't make noise when crashreporter is built but not enabled
- if (ex.result != Cr.NS_ERROR_NOT_INITIALIZED) {
- Cu.reportError("SessionStore:" + ex);
- }
- }
- },
-
- /**
- * Determines whether a given session history entry has been added dynamically.
- */
- isDynamic: function(aEntry) {
- // aEntry.isDynamicallyAdded() is true for dynamically added
- // <iframe> and <frameset>, but also for <html> (the root of the
- // document) so we use aEntry.parent to ensure that we're not looking
- // at the root of the document
- return aEntry.parent && aEntry.isDynamicallyAdded();
- },
-
- /**
- * Get an object that is a serialized representation of a History entry.
- */
- _serializeHistoryEntry: function _serializeHistoryEntry(aEntry) {
- let entry = { url: aEntry.URI.spec };
-
- if (aEntry.title && aEntry.title != entry.url) {
- entry.title = aEntry.title;
- }
-
- if (!(aEntry instanceof Ci.nsISHEntry)) {
- return entry;
- }
-
- let cacheKey = aEntry.cacheKey;
- if (cacheKey && cacheKey instanceof Ci.nsISupportsPRUint32 && cacheKey.data != 0) {
- entry.cacheKey = cacheKey.data;
- }
-
- entry.ID = aEntry.ID;
- entry.docshellID = aEntry.docshellID;
-
- if (aEntry.referrerURI) {
- entry.referrer = aEntry.referrerURI.spec;
- }
-
- if (aEntry.originalURI) {
- entry.originalURI = aEntry.originalURI.spec;
- }
-
- if (aEntry.loadReplace) {
- entry.loadReplace = aEntry.loadReplace;
- }
-
- if (aEntry.contentType) {
- entry.contentType = aEntry.contentType;
- }
-
- if (aEntry.scrollRestorationIsManual) {
- entry.scrollRestorationIsManual = true;
- } else {
- let x = {}, y = {};
- aEntry.getScrollPosition(x, y);
- if (x.value != 0 || y.value != 0) {
- entry.scroll = x.value + "," + y.value;
- }
- }
-
- // Collect triggeringPrincipal data for the current history entry.
- // Please note that before Bug 1297338 there was no concept of a
- // principalToInherit. To remain backward/forward compatible we
- // serialize the principalToInherit as triggeringPrincipal_b64.
- // Once principalToInherit is well established (within FF55)
- // we can update this code, remove triggeringPrincipal_b64 and
- // just keep triggeringPrincipal_base64 as well as
- // principalToInherit_base64; see Bug 1301666.
- if (aEntry.principalToInherit) {
- try {
- let principalToInherit = Utils.serializePrincipal(aEntry.principalToInherit);
- if (principalToInherit) {
- entry.triggeringPrincipal_b64 = principalToInherit;
- entry.principalToInherit_base64 = principalToInherit;
- }
- } catch (e) {
- dump(e);
- }
- }
-
- if (aEntry.triggeringPrincipal) {
- try {
- let triggeringPrincipal = Utils.serializePrincipal(aEntry.triggeringPrincipal);
- if (triggeringPrincipal) {
- entry.triggeringPrincipal_base64 = triggeringPrincipal;
- }
- } catch (e) {
- dump(e);
- }
- }
-
- entry.docIdentifier = aEntry.BFCacheEntry.ID;
-
- if (aEntry.stateData != null) {
- entry.structuredCloneState = aEntry.stateData.getDataAsBase64();
- entry.structuredCloneVersion = aEntry.stateData.formatVersion;
- }
-
- if (!(aEntry instanceof Ci.nsISHContainer)) {
- return entry;
- }
-
- if (aEntry.childCount > 0) {
- let children = [];
- for (let i = 0; i < aEntry.childCount; i++) {
- let child = aEntry.GetChildAt(i);
-
- if (child && !this.isDynamic(child)) {
- // don't try to restore framesets containing wyciwyg URLs (cf. bug 424689 and bug 450595)
- if (child.URI.schemeIs("wyciwyg")) {
- children = [];
- break;
- }
- children.push(this._serializeHistoryEntry(child));
- }
- }
-
- if (children.length) {
- entry.children = children;
- }
- }
-
- return entry;
- },
-
- _deserializeHistoryEntry: function _deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) {
- let shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].createInstance(Ci.nsISHEntry);
-
- shEntry.setURI(Services.io.newURI(aEntry.url, null, null));
- shEntry.setTitle(aEntry.title || aEntry.url);
- if (aEntry.subframe) {
- shEntry.setIsSubFrame(aEntry.subframe || false);
- }
- shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
- if (aEntry.contentType) {
- shEntry.contentType = aEntry.contentType;
- }
- if (aEntry.referrer) {
- shEntry.referrerURI = Services.io.newURI(aEntry.referrer, null, null);
- }
-
- if (aEntry.originalURI) {
- shEntry.originalURI = Services.io.newURI(aEntry.originalURI, null, null);
- }
-
- if (aEntry.loadReplace) {
- shEntry.loadReplace = aEntry.loadReplace;
- }
-
- if (aEntry.cacheKey) {
- let cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].createInstance(Ci.nsISupportsPRUint32);
- cacheKey.data = aEntry.cacheKey;
- shEntry.cacheKey = cacheKey;
- }
-
- if (aEntry.ID) {
- // get a new unique ID for this frame (since the one from the last
- // start might already be in use)
- let id = aIdMap[aEntry.ID] || 0;
- if (!id) {
- for (id = Date.now(); id in aIdMap.used; id++);
- aIdMap[aEntry.ID] = id;
- aIdMap.used[id] = true;
- }
- shEntry.ID = id;
- }
-
- if (aEntry.docshellID) {
- shEntry.docshellID = aEntry.docshellID;
- }
-
- if (aEntry.structuredCloneState && aEntry.structuredCloneVersion) {
- shEntry.stateData =
- Cc["@mozilla.org/docshell/structured-clone-container;1"].
- createInstance(Ci.nsIStructuredCloneContainer);
-
- shEntry.stateData.initFromBase64(aEntry.structuredCloneState, aEntry.structuredCloneVersion);
- }
-
- if (aEntry.scrollRestorationIsManual) {
- shEntry.scrollRestorationIsManual = true;
- } else if (aEntry.scroll) {
- let scrollPos = aEntry.scroll.split(",");
- scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
- shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
- }
-
- let childDocIdents = {};
- if (aEntry.docIdentifier) {
- // If we have a serialized document identifier, try to find an SHEntry
- // which matches that doc identifier and adopt that SHEntry's
- // BFCacheEntry. If we don't find a match, insert shEntry as the match
- // for the document identifier.
- let matchingEntry = aDocIdentMap[aEntry.docIdentifier];
- if (!matchingEntry) {
- matchingEntry = {shEntry: shEntry, childDocIdents: childDocIdents};
- aDocIdentMap[aEntry.docIdentifier] = matchingEntry;
- } else {
- shEntry.adoptBFCacheEntry(matchingEntry.shEntry);
- childDocIdents = matchingEntry.childDocIdents;
- }
- }
-
- // The field aEntry.owner_b64 got renamed to aEntry.triggeringPricipal_b64 in
- // Bug 1286472. To remain backward compatible we still have to support that
- // field for a few cycles before we can remove it within Bug 1289785.
- if (aEntry.owner_b64) {
- aEntry.triggeringPricipal_b64 = aEntry.owner_b64;
- delete aEntry.owner_b64;
- }
-
- // Before introducing the concept of principalToInherit we only had
- // a triggeringPrincipal within every entry which basically is the
- // equivalent of the new principalToInherit. To avoid compatibility
- // issues, we first check if the entry has entries for
- // triggeringPrincipal_base64 and principalToInherit_base64. If not
- // we fall back to using the principalToInherit (which is stored
- // as triggeringPrincipal_b64) as the triggeringPrincipal and
- // the principalToInherit.
- // FF55 will remove the triggeringPrincipal_b64, see Bug 1301666.
- if (aEntry.triggeringPrincipal_base64 || aEntry.principalToInherit_base64) {
- if (aEntry.triggeringPrincipal_base64) {
- shEntry.triggeringPrincipal =
- Utils.deserializePrincipal(aEntry.triggeringPrincipal_base64);
- }
- if (aEntry.principalToInherit_base64) {
- shEntry.principalToInherit =
- Utils.deserializePrincipal(aEntry.principalToInherit_base64);
- }
- } else if (aEntry.triggeringPrincipal_b64) {
- shEntry.triggeringPrincipal = Utils.deserializePrincipal(aEntry.triggeringPrincipal_b64);
- shEntry.principalToInherit = shEntry.triggeringPrincipal;
- }
-
- if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
- for (let i = 0; i < aEntry.children.length; i++) {
- if (!aEntry.children[i].url) {
- continue;
- }
-
- // We're getting sessionrestore.js files with a cycle in the
- // doc-identifier graph, likely due to bug 698656. (That is, we have
- // an entry where doc identifier A is an ancestor of doc identifier B,
- // and another entry where doc identifier B is an ancestor of A.)
- //
- // If we were to respect these doc identifiers, we'd create a cycle in
- // the SHEntries themselves, which causes the docshell to loop forever
- // when it looks for the root SHEntry.
- //
- // So as a hack to fix this, we restrict the scope of a doc identifier
- // to be a node's siblings and cousins, and pass childDocIdents, not
- // aDocIdents, to _deserializeHistoryEntry. That is, we say that two
- // SHEntries with the same doc identifier have the same document iff
- // they have the same parent or their parents have the same document.
-
- shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap, childDocIdents), i);
- }
- }
-
- return shEntry;
- },
-
- // This function iterates through a list of urls opening a new tab for each.
- _openTabs: function ss_openTabs(aData) {
- let window = Services.wm.getMostRecentWindow("navigator:browser");
- for (let i = 0; i < aData.urls.length; i++) {
- let url = aData.urls[i];
- let params = {
- selected: (i == aData.urls.length - 1),
- isPrivate: false,
- desktopMode: false,
- };
-
- let tab = window.BrowserApp.addTab(url, params);
- }
- },
-
- // This function iterates through a list of tab data restoring session for each of them.
- _restoreTabs: function ss_restoreTabs(aData) {
- let window = Services.wm.getMostRecentWindow("navigator:browser");
- for (let i = 0; i < aData.tabs.length; i++) {
- let tabData = JSON.parse(aData.tabs[i]);
- let isSelectedTab = (i == aData.tabs.length - 1);
- let params = {
- selected: isSelectedTab,
- isPrivate: tabData.isPrivate,
- desktopMode: tabData.desktopMode,
- cancelEditMode: isSelectedTab
- };
-
- let tab = window.BrowserApp.addTab(tabData.entries[tabData.index - 1].url, params);
- tab.browser.__SS_data = tabData;
- tab.browser.__SS_extdata = tabData.extData;
- this._restoreTab(tabData, tab.browser);
- }
- },
-
- /**
- * Don't save sensitive data if the user doesn't want to
- * (distinguishes between encrypted and non-encrypted sites)
- */
- checkPrivacyLevel: function ss_checkPrivacyLevel(aURL) {
- let isHTTPS = aURL.startsWith("https:");
- let pref = "browser.sessionstore.privacy_level";
- return Services.prefs.getIntPref(pref) < (isHTTPS ? PRIVACY_ENCRYPTED : PRIVACY_FULL);
- },
-
- /**
- * Starts the restoration process for a browser. History is restored at this
- * point, but text data must be delayed until the content loads.
- */
- _restoreTab: function ss_restoreTab(aTabData, aBrowser) {
- // aTabData shouldn't be empty here, but if it is,
- // _restoreHistory() will crash otherwise.
- if (!aTabData || aTabData.entries.length == 0) {
- Cu.reportError("SessionStore.js: Error trying to restore tab with empty tabdata");
- return;
- }
- this._restoreHistory(aTabData, aBrowser.sessionHistory);
-
- // Various bits of state can only be restored if page loading has progressed far enough:
- // The MobileViewportManager needs to be told as early as possible about
- // our desired zoom level so it can take it into account during the
- // initial document resolution calculation.
- aBrowser.__SS_restoreDataOnLocationChange = true;
- // Restoring saved form data requires the input fields to be available,
- // so we have to wait for the content to load.
- aBrowser.__SS_restoreDataOnLoad = true;
- // Restoring the scroll position depends on the document resolution having been set,
- // which is only guaranteed to have happened *after* we receive the load event.
- aBrowser.__SS_restoreDataOnPageshow = true;
- },
-
- /**
- * Takes serialized history data and create news entries into the given
- * nsISessionHistory object.
- */
- _restoreHistory: function ss_restoreHistory(aTabData, aHistory) {
- if (aHistory.count > 0) {
- aHistory.PurgeHistory(aHistory.count);
- }
- aHistory.QueryInterface(Ci.nsISHistoryInternal);
-
- // Helper hashes for ensuring unique frame IDs and unique document
- // identifiers.
- let idMap = { used: {} };
- let docIdentMap = {};
-
- for (let i = 0; i < aTabData.entries.length; i++) {
- if (!aTabData.entries[i].url) {
- continue;
- }
- aHistory.addEntry(this._deserializeHistoryEntry(aTabData.entries[i], idMap, docIdentMap), true);
- }
-
- // We need to force set the active history item and cause it to reload since
- // we stop the load above
- let activeIndex = (aTabData.index || aTabData.entries.length) - 1;
- aHistory.getEntryAtIndex(activeIndex, true);
-
- try {
- aHistory.QueryInterface(Ci.nsISHistory).reloadCurrentEntry();
- } catch (e) {
- // This will throw if the current entry is an error page.
- }
- },
-
- /**
- * Takes serialized form text data and restores it into the given browser.
- */
- _restoreTextData: function ss_restoreTextData(aFormData, aBrowser) {
- if (aFormData) {
- log("_restoreTextData()");
- FormData.restoreTree(aBrowser.contentWindow, aFormData);
- }
- },
-
- /**
- * Restores the zoom level of the window. This needs to be called before
- * first paint/load (whichever comes first) to take any effect.
- */
- _restoreZoom: function ss_restoreZoom(aScrollData, aBrowser) {
- if (aScrollData && aScrollData.zoom && aScrollData.zoom.displaySize) {
- log("_restoreZoom(), resolution: " + aScrollData.zoom.resolution +
- ", old displayWidth: " + aScrollData.zoom.displaySize.width);
-
- let utils = aBrowser.contentWindow.QueryInterface(
- Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
- // Restore zoom level.
- utils.setRestoreResolution(aScrollData.zoom.resolution,
- aScrollData.zoom.displaySize.width,
- aScrollData.zoom.displaySize.height);
- }
- },
-
- /**
- * Takes serialized scroll positions and restores them into the given browser.
- */
- _restoreScrollPosition: function ss_restoreScrollPosition(aScrollData, aBrowser) {
- if (aScrollData) {
- log("_restoreScrollPosition()");
- ScrollPosition.restoreTree(aBrowser.contentWindow, aScrollData);
- }
- },
-
- getBrowserState: function ss_getBrowserState() {
- return this._getCurrentState();
- },
-
- _restoreWindow: function ss_restoreWindow(aData) {
- let state;
- try {
- state = JSON.parse(aData);
- } catch (e) {
- throw "Invalid session JSON: " + aData;
- }
-
- // To do a restore, we must have at least one window with one tab
- if (!state || state.windows.length == 0 || !state.windows[0].tabs || state.windows[0].tabs.length == 0) {
- throw "Invalid session JSON: " + aData;
- }
-
- let window = Services.wm.getMostRecentWindow("navigator:browser");
-
- let tabs = state.windows[0].tabs;
- let selected = state.windows[0].selected;
- log("_restoreWindow() selected tab in aData is " + selected + " of " + tabs.length)
- if (selected == null || selected > tabs.length) { // Clamp the selected index if it's bogus
- log("_restoreWindow() resetting selected tab");
- selected = 1;
- }
- log("restoreWindow() window.BrowserApp.selectedTab is " + window.BrowserApp.selectedTab.id);
-
- for (let i = 0; i < tabs.length; i++) {
- let tabData = tabs[i];
- let entry = tabData.entries[tabData.index - 1];
-
- // Use stubbed tab if we've already created it; otherwise, make a new tab
- let tab;
- if (tabData.tabId == null) {
- let params = {
- selected: (selected == i+1),
- delayLoad: true,
- title: entry.title,
- desktopMode: (tabData.desktopMode == true),
- isPrivate: (tabData.isPrivate == true)
- };
- tab = window.BrowserApp.addTab(entry.url, params);
- } else {
- tab = window.BrowserApp.getTabForId(tabData.tabId);
- delete tabData.tabId;
-
- // Don't restore tab if user has closed it
- if (tab == null) {
- continue;
- }
- }
-
- tab.browser.__SS_data = tabData;
- tab.browser.__SS_extdata = tabData.extData;
-
- if (window.BrowserApp.selectedTab == tab) {
- this._restoreTab(tabData, tab.browser);
-
- // We can now lift the general ban on tab data capturing,
- // but we still need to protect the foreground tab until we're
- // sure it's actually reloading after history restoring has finished.
- tab.browser.__SS_restoreReloadPending = true;
- this._startupRestoreFinished = true;
- log("startupRestoreFinished = true");
-
- delete tab.browser.__SS_restore;
- tab.browser.removeAttribute("pending");
- } else {
- // Mark the browser for delay loading
- tab.browser.__SS_restore = true;
- tab.browser.setAttribute("pending", "true");
- }
- }
-
- // Restore the closed tabs array on the current window.
- if (state.windows[0].closedTabs) {
- this._windows[window.__SSID].closedTabs = state.windows[0].closedTabs;
- log("_restoreWindow() loaded " + state.windows[0].closedTabs.length + " closed tabs");
- }
- },
-
- getClosedTabCount: function ss_getClosedTabCount(aWindow) {
- if (!aWindow || !aWindow.__SSID || !this._windows[aWindow.__SSID]) {
- return 0; // not a browser window, or not otherwise tracked by SS.
- }
-
- return this._windows[aWindow.__SSID].closedTabs.length;
- },
-
- getClosedTabs: function ss_getClosedTabs(aWindow) {
- if (!aWindow.__SSID) {
- throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
- }
-
- return this._windows[aWindow.__SSID].closedTabs;
- },
-
- undoCloseTab: function ss_undoCloseTab(aWindow, aCloseTabData) {
- if (!aWindow.__SSID) {
- throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
- }
-
- let closedTabs = this._windows[aWindow.__SSID].closedTabs;
- if (!closedTabs) {
- return null;
- }
-
- // If the tab data is in the closedTabs array, remove it.
- closedTabs.find(function (tabData, i) {
- if (tabData == aCloseTabData) {
- closedTabs.splice(i, 1);
- return true;
- }
- });
-
- // create a new tab and bring to front
- let params = {
- selected: true,
- isPrivate: aCloseTabData.isPrivate,
- desktopMode: aCloseTabData.desktopMode,
- tabIndex: this._lastClosedTabIndex
- };
- let tab = aWindow.BrowserApp.addTab(aCloseTabData.entries[aCloseTabData.index - 1].url, params);
- tab.browser.__SS_data = aCloseTabData;
- tab.browser.__SS_extdata = aCloseTabData.extData;
- this._restoreTab(aCloseTabData, tab.browser);
-
- this._lastClosedTabIndex = -1;
-
- if (this._notifyClosedTabs) {
- this._sendClosedTabsToJava(aWindow);
- }
-
- return tab.browser;
- },
-
- forgetClosedTab: function ss_forgetClosedTab(aWindow, aIndex) {
- if (!aWindow.__SSID) {
- throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
- }
-
- let closedTabs = this._windows[aWindow.__SSID].closedTabs;
-
- // default to the most-recently closed tab
- aIndex = aIndex || 0;
- if (!(aIndex in closedTabs)) {
- throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
- }
-
- // remove closed tab from the array
- closedTabs.splice(aIndex, 1);
-
- // Forget the last closed tab index if we're forgetting the last closed tab.
- if (aIndex == 0) {
- this._lastClosedTabIndex = -1;
- }
- if (this._notifyClosedTabs) {
- this._sendClosedTabsToJava(aWindow);
- }
- },
-
- _sendClosedTabsToJava: function ss_sendClosedTabsToJava(aWindow) {
- if (!aWindow.__SSID) {
- throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG);
- }
-
- let closedTabs = this._windows[aWindow.__SSID].closedTabs;
- let isPrivate = PrivateBrowsingUtils.isBrowserPrivate(aWindow.BrowserApp.selectedBrowser);
-
- let tabs = closedTabs
- .filter(tab => tab.isPrivate == isPrivate)
- .map(function (tab) {
- // Get the url and title for the last entry in the session history.
- let lastEntry = tab.entries[tab.entries.length - 1];
- return {
- url: lastEntry.url,
- title: lastEntry.title || "",
- data: tab
- };
- });
-
- log("sending " + tabs.length + " closed tabs to Java");
- Messaging.sendRequest({
- type: "ClosedTabs:Data",
- tabs: tabs
- });
- },
-
- getTabValue: function ss_getTabValue(aTab, aKey) {
- let browser = aTab.browser;
- let data = browser.__SS_extdata || {};
- return data[aKey] || "";
- },
-
- setTabValue: function ss_setTabValue(aTab, aKey, aStringValue) {
- let browser = aTab.browser;
- if (!browser.__SS_extdata) {
- browser.__SS_extdata = {};
- }
- browser.__SS_extdata[aKey] = aStringValue;
- this.saveStateDelayed();
- },
-
- deleteTabValue: function ss_deleteTabValue(aTab, aKey) {
- let browser = aTab.browser;
- if (browser.__SS_extdata && aKey in browser.__SS_extdata) {
- delete browser.__SS_extdata[aKey];
- this.saveStateDelayed();
- }
- },
-
- restoreLastSession: Task.async(function* (aSessionString) {
- let notifyMessage = "";
-
- try {
- this._restoreWindow(aSessionString);
- } catch (e) {
- Cu.reportError("SessionStore: " + e);
- notifyMessage = "fail";
- }
-
- Services.obs.notifyObservers(null, "sessionstore-windows-restored", notifyMessage);
- }),
-
- removeWindow: function ss_removeWindow(aWindow) {
- if (!aWindow || !aWindow.__SSID || !this._windows[aWindow.__SSID]) {
- return;
- }
-
- delete this._windows[aWindow.__SSID];
- delete aWindow.__SSID;
-
- if (this._loadState == STATE_RUNNING) {
- // Save the purged state immediately
- this.saveState();
- } else if (this._loadState <= STATE_QUITTING) {
- this.saveStateDelayed();
- }
- }
-
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SessionStore]);
diff --git a/mobile/android/components/SiteSpecificUserAgent.js b/mobile/android/components/SiteSpecificUserAgent.js
deleted file mode 100644
index f95d7ab16..000000000
--- a/mobile/android/components/SiteSpecificUserAgent.js
+++ /dev/null
@@ -1,33 +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/. */
-
-const Cu = Components.utils;
-const Cc = Components.classes;
-const Ci = Components.interfaces;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/UserAgentOverrides.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-const DEFAULT_UA = Cc["@mozilla.org/network/protocol;1?name=http"]
- .getService(Ci.nsIHttpProtocolHandler)
- .userAgent;
-
-function SiteSpecificUserAgent() {}
-
-SiteSpecificUserAgent.prototype = {
- getUserAgentForURIAndWindow: function ssua_getUserAgentForURIAndWindow(aURI, aWindow) {
- let UA;
- let win = Services.wm.getMostRecentWindow("navigator:browser");
- if (win && win.DesktopUserAgent) {
- UA = win.DesktopUserAgent.getUserAgentForWindow(aWindow);
- }
- return UA || UserAgentOverrides.getOverrideForURI(aURI) || DEFAULT_UA;
- },
-
- classID: Components.ID("{d5234c9d-0ee2-4b3c-9da3-18be9e5cf7e6}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISiteSpecificUserAgent])
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([SiteSpecificUserAgent]);
diff --git a/mobile/android/components/Snippets.js b/mobile/android/components/Snippets.js
deleted file mode 100644
index 92639236f..000000000
--- a/mobile/android/components/Snippets.js
+++ /dev/null
@@ -1,446 +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/. */
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-Cu.import("resource://gre/modules/Accounts.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Home", "resource://gre/modules/Home.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "OS", "resource://gre/modules/osfile.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "UITelemetry", "resource://gre/modules/UITelemetry.jsm");
-
-
-XPCOMUtils.defineLazyGetter(this, "gEncoder", function() { return new gChromeWin.TextEncoder(); });
-XPCOMUtils.defineLazyGetter(this, "gDecoder", function() { return new gChromeWin.TextDecoder(); });
-
-// URL to fetch snippets, in the urlFormatter service format.
-const SNIPPETS_UPDATE_URL_PREF = "browser.snippets.updateUrl";
-
-// URL to send stats data to metrics.
-const SNIPPETS_STATS_URL_PREF = "browser.snippets.statsUrl";
-
-// URL to fetch country code, a value that's cached and refreshed once per month.
-const SNIPPETS_GEO_URL_PREF = "browser.snippets.geoUrl";
-
-// Timestamp when we last updated the user's country code.
-const SNIPPETS_GEO_LAST_UPDATE_PREF = "browser.snippets.geoLastUpdate";
-
-// Pref where we'll cache the user's country.
-const SNIPPETS_COUNTRY_CODE_PREF = "browser.snippets.countryCode";
-
-// Pref where we store an array IDs of snippets that should not be shown again
-const SNIPPETS_REMOVED_IDS_PREF = "browser.snippets.removedIds";
-
-// How frequently we update the user's country code from the server (30 days).
-const SNIPPETS_GEO_UPDATE_INTERVAL_MS = 86400000*30;
-
-// Should be bumped up if the snippets content format changes.
-const SNIPPETS_VERSION = 1;
-
-XPCOMUtils.defineLazyGetter(this, "gSnippetsURL", function() {
- let updateURL = Services.prefs.getCharPref(SNIPPETS_UPDATE_URL_PREF).replace("%SNIPPETS_VERSION%", SNIPPETS_VERSION);
- return Services.urlFormatter.formatURL(updateURL);
-});
-
-// Where we cache snippets data
-XPCOMUtils.defineLazyGetter(this, "gSnippetsPath", function() {
- return OS.Path.join(OS.Constants.Path.profileDir, "snippets.json");
-});
-
-XPCOMUtils.defineLazyGetter(this, "gStatsURL", function() {
- return Services.prefs.getCharPref(SNIPPETS_STATS_URL_PREF);
-});
-
-// Where we store stats about which snippets have been shown
-XPCOMUtils.defineLazyGetter(this, "gStatsPath", function() {
- return OS.Path.join(OS.Constants.Path.profileDir, "snippets-stats.txt");
-});
-
-XPCOMUtils.defineLazyGetter(this, "gGeoURL", function() {
- return Services.prefs.getCharPref(SNIPPETS_GEO_URL_PREF);
-});
-
-XPCOMUtils.defineLazyGetter(this, "gCountryCode", function() {
- try {
- return Services.prefs.getCharPref(SNIPPETS_COUNTRY_CODE_PREF);
- } catch (e) {
- // Return an empty string if the country code pref isn't set yet.
- return "";
- }
-});
-
-XPCOMUtils.defineLazyGetter(this, "gChromeWin", function() {
- return Services.wm.getMostRecentWindow("navigator:browser");
-});
-
-/**
- * Updates snippet data and country code (if necessary).
- */
-function update() {
- // Check to see if we should update the user's country code from the geo server.
- let lastUpdate = 0;
- try {
- lastUpdate = parseFloat(Services.prefs.getCharPref(SNIPPETS_GEO_LAST_UPDATE_PREF));
- } catch (e) {}
-
- if (Date.now() - lastUpdate > SNIPPETS_GEO_UPDATE_INTERVAL_MS) {
- // We should update the snippets after updating the country code,
- // so that we can filter snippets to add to the banner.
- updateCountryCode(updateSnippets);
- } else {
- updateSnippets();
- }
-}
-
-/**
- * Fetches the user's country code from the geo server and stores the value in a pref.
- *
- * @param callback function called once country code is updated
- */
-function updateCountryCode(callback) {
- _httpGetRequest(gGeoURL, function(responseText) {
- // Store the country code in a pref.
- let data = JSON.parse(responseText);
- Services.prefs.setCharPref(SNIPPETS_COUNTRY_CODE_PREF, data.country_code);
-
- // Set last update time.
- Services.prefs.setCharPref(SNIPPETS_GEO_LAST_UPDATE_PREF, Date.now());
-
- callback();
- });
-}
-
-/**
- * Loads snippets from snippets server, caches the response, and
- * updates the home banner with the new set of snippets.
- */
-function updateSnippets() {
- _httpGetRequest(gSnippetsURL, function(responseText) {
- try {
- let messages = JSON.parse(responseText);
- updateBanner(messages);
-
- // Only cache the response if it is valid JSON.
- cacheSnippets(responseText);
- } catch (e) {
- Cu.reportError("Error parsing snippets responseText: " + e);
- }
- });
-}
-
-/**
- * Caches snippets server response text to `snippets.json` in profile directory.
- *
- * @param response responseText returned from snippets server
- */
-function cacheSnippets(response) {
- let data = gEncoder.encode(response);
- let promise = OS.File.writeAtomic(gSnippetsPath, data, { tmpPath: gSnippetsPath + ".tmp" });
- promise.then(null, e => Cu.reportError("Error caching snippets: " + e));
-}
-
-/**
- * Loads snippets from cached `snippets.json`.
- */
-function loadSnippetsFromCache() {
- let promise = OS.File.read(gSnippetsPath);
- promise.then(array => {
- let messages = JSON.parse(gDecoder.decode(array));
- updateBanner(messages);
- }, e => {
- if (e instanceof OS.File.Error && e.becauseNoSuchFile) {
- Services.console.logStringMessage("Couldn't show snippets because cache does not exist yet.");
- } else {
- Cu.reportError("Error loading snippets from cache: " + e);
- }
- });
-}
-
-// Array of the message ids added to the home banner, used to remove
-// older set of snippets when new ones are available.
-var gMessageIds = [];
-
-/**
- * Updates set of snippets in the home banner message rotation.
- *
- * @param messages JSON array of message data JSON objects.
- * Each message object should have the following properties:
- * - id (?): Unique identifier for this snippets message
- * - text (string): Text to show as banner message
- * - url (string): URL to open when banner is clicked
- * - icon (data URI): Icon to appear in banner
- * - countries (list of strings): Country codes for where this message should be shown (e.g. ["US", "GR"])
- */
-function updateBanner(messages) {
- // Remove the current messages, if there are any.
- gMessageIds.forEach(function(id) {
- Home.banner.remove(id);
- })
- gMessageIds = [];
-
- try {
- let removedSnippetIds = JSON.parse(Services.prefs.getCharPref(SNIPPETS_REMOVED_IDS_PREF));
- messages = messages.filter(function(message) {
- // Only include the snippet if it has not been previously removed.
- return removedSnippetIds.indexOf(message.id) === -1;
- });
- } catch (e) {
- // If the pref doesn't exist, there aren't any snippets to filter out.
- }
-
- messages.forEach(function(message) {
- // Don't add this message to the banner if it's not supposed to be shown in this country.
- if ("countries" in message && message.countries.indexOf(gCountryCode) === -1) {
- return;
- }
-
- let id = Home.banner.add({
- text: message.text,
- icon: message.icon,
- weight: message.weight,
- onclick: function() {
- gChromeWin.BrowserApp.loadURI(message.url);
- removeSnippet(id, message.id);
- UITelemetry.addEvent("action.1", "banner", null, message.id);
- },
- ondismiss: function() {
- removeSnippet(id, message.id);
- UITelemetry.addEvent("cancel.1", "banner", null, message.id);
- },
- onshown: function() {
- // 10% of the time, record the snippet id and a timestamp
- if (Math.random() < .1) {
- writeStat(message.id, new Date().toISOString());
- }
- }
- });
- // Keep track of the message we added so that we can remove it later.
- gMessageIds.push(id);
- });
-}
-
-/**
- * Removes a snippet message from the home banner rotation, and stores its
- * snippet id in a pref so we'll never show it again.
- *
- * @param messageId unique id for home banner message, returned from Home.banner API
- * @param snippetId unique id for snippet, sent from snippets server
- */
-function removeSnippet(messageId, snippetId) {
- // Remove the message from the home banner rotation.
- Home.banner.remove(messageId);
-
- // Remove the message from the stored message ids.
- gMessageIds.splice(gMessageIds.indexOf(messageId), 1);
-
- let removedSnippetIds;
- try {
- removedSnippetIds = JSON.parse(Services.prefs.getCharPref(SNIPPETS_REMOVED_IDS_PREF));
- } catch (e) {
- removedSnippetIds = [];
- }
-
- removedSnippetIds.push(snippetId);
- Services.prefs.setCharPref(SNIPPETS_REMOVED_IDS_PREF, JSON.stringify(removedSnippetIds));
-}
-
-/**
- * Appends snippet id and timestamp to the end of `snippets-stats.txt`.
- *
- * @param snippetId unique id for snippet, sent from snippets server
- * @param timestamp in ISO8601
- */
-function writeStat(snippetId, timestamp) {
- let data = gEncoder.encode(snippetId + "," + timestamp + ";");
-
- Task.spawn(function() {
- try {
- let file = yield OS.File.open(gStatsPath, { append: true, write: true });
- try {
- yield file.write(data);
- } finally {
- yield file.close();
- }
- } catch (ex if ex instanceof OS.File.Error && ex.becauseNoSuchFile) {
- // If the file doesn't exist yet, create it.
- yield OS.File.writeAtomic(gStatsPath, data, { tmpPath: gStatsPath + ".tmp" });
- }
- }).then(null, e => Cu.reportError("Error writing snippets stats: " + e));
-}
-
-/**
- * Reads snippets stats data from `snippets-stats.txt` and sends the data to metrics.
- */
-function sendStats() {
- let promise = OS.File.read(gStatsPath);
- promise.then(array => sendStatsRequest(gDecoder.decode(array)), e => {
- if (e instanceof OS.File.Error && e.becauseNoSuchFile) {
- // If the file doesn't exist, there aren't any stats to send.
- } else {
- Cu.reportError("Error eading snippets stats: " + e);
- }
- });
-}
-
-/**
- * Sends stats to metrics about which snippets have been shown.
- * Appends snippet ids and timestamps as parameters to a GET request.
- * e.g. https://snippets-stats.mozilla.org/mobile?s1=3825&t1=2013-11-17T18:27Z&s2=6326&t2=2013-11-18T18:27Z
- *
- * @param data contents of stats data file
- */
-function sendStatsRequest(data) {
- let params = [];
- let stats = data.split(";");
-
- // The last item in the array will be an empty string, so stop before then.
- for (let i = 0; i < stats.length - 1; i++) {
- let stat = stats[i].split(",");
- params.push("s" + i + "=" + encodeURIComponent(stat[0]));
- params.push("t" + i + "=" + encodeURIComponent(stat[1]));
- }
-
- let url = gStatsURL + "?" + params.join("&");
-
- // Remove the file after succesfully sending the data.
- _httpGetRequest(url, removeStats);
-}
-
-/**
- * Removes text file where we store snippets stats.
- */
-function removeStats() {
- let promise = OS.File.remove(gStatsPath);
- promise.then(null, e => Cu.reportError("Error removing snippets stats: " + e));
-}
-
-/**
- * Helper function to make HTTP GET requests.
- *
- * @param url where we send the request
- * @param callback function that is called with the xhr responseText
- */
-function _httpGetRequest(url, callback) {
- let xhr = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
- try {
- xhr.open("GET", url, true);
- } catch (e) {
- Cu.reportError("Error opening request to " + url + ": " + e);
- return;
- }
- xhr.onerror = function onerror(e) {
- Cu.reportError("Error making request to " + url + ": " + e.error);
- }
- xhr.onload = function onload(event) {
- if (xhr.status !== 200) {
- Cu.reportError("Request to " + url + " returned status " + xhr.status);
- return;
- }
- if (callback) {
- callback(xhr.responseText);
- }
- }
- xhr.send(null);
-}
-
-function loadSyncPromoBanner() {
- Accounts.anySyncAccountsExist().then(
- (exist) => {
- // Don't show the banner if sync accounts exist.
- if (exist) {
- return;
- }
-
- let stringBundle = Services.strings.createBundle("chrome://browser/locale/sync.properties");
- let text = stringBundle.GetStringFromName("promoBanner.message.text");
- let link = stringBundle.GetStringFromName("promoBanner.message.link");
-
- let id = Home.banner.add({
- text: text + "<a href=\"#\">" + link + "</a>",
- icon: "drawable://sync_promo",
- onclick: function() {
- // Remove the message, so that it won't show again for the rest of the app lifetime.
- Home.banner.remove(id);
- Accounts.launchSetup();
-
- UITelemetry.addEvent("action.1", "banner", null, "syncpromo");
- },
- ondismiss: function() {
- // Remove the sync promo message from the banner and never try to show it again.
- Home.banner.remove(id);
- Services.prefs.setBoolPref("browser.snippets.syncPromo.enabled", false);
-
- UITelemetry.addEvent("cancel.1", "banner", null, "syncpromo");
- }
- });
- },
- (err) => {
- Cu.reportError("Error checking whether sync account exists: " + err);
- }
- );
-}
-
-function loadHomePanelsBanner() {
- let stringBundle = Services.strings.createBundle("chrome://browser/locale/aboutHome.properties");
- let text = stringBundle.GetStringFromName("banner.firstrunHomepage.text");
-
- let id = Home.banner.add({
- text: text,
- icon: "drawable://homepage_banner_firstrun",
- onclick: function() {
- // Remove the message, so that it won't show again for the rest of the app lifetime.
- Home.banner.remove(id);
- // User has interacted with this snippet so don't show it again.
- Services.prefs.setBoolPref("browser.snippets.firstrunHomepage.enabled", false);
-
- UITelemetry.addEvent("action.1", "banner", null, "firstrun-homepage");
- },
- ondismiss: function() {
- Home.banner.remove(id);
- Services.prefs.setBoolPref("browser.snippets.firstrunHomepage.enabled", false);
-
- UITelemetry.addEvent("cancel.1", "banner", null, "firstrun-homepage");
- }
- });
-}
-
-function Snippets() {}
-
-Snippets.prototype = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsITimerCallback]),
- classID: Components.ID("{a78d7e59-b558-4321-a3d6-dffe2f1e76dd}"),
-
- observe: function(subject, topic, data) {
- switch(topic) {
- case "browser-delayed-startup-finished":
- // Add snippets to be cycled through.
- if (Services.prefs.getBoolPref("browser.snippets.firstrunHomepage.enabled")) {
- loadHomePanelsBanner();
- }
-
- if (Services.prefs.getBoolPref("browser.snippets.syncPromo.enabled")) {
- loadSyncPromoBanner();
- }
-
- if (Services.prefs.getBoolPref("browser.snippets.enabled")) {
- loadSnippetsFromCache();
- }
- break;
- }
- },
-
- // By default, this timer fires once every 24 hours. See the "browser.snippets.updateInterval" pref.
- notify: function(timer) {
- if (!Services.prefs.getBoolPref("browser.snippets.enabled")) {
- return;
- }
- update();
- sendStats();
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([Snippets]);
diff --git a/mobile/android/components/TabSource.js b/mobile/android/components/TabSource.js
deleted file mode 100644
index c35a54438..000000000
--- a/mobile/android/components/TabSource.js
+++ /dev/null
@@ -1,91 +0,0 @@
-/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
- * 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"
-
-const { classes: Cc, interfaces: Ci, manager: Cm, utils: Cu, results: Cr } = Components;
-
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Prompt",
- "resource://gre/modules/Prompt.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Messaging",
- "resource://gre/modules/Messaging.jsm");
-
-function TabSource() {
-}
-
-TabSource.prototype = {
- classID: Components.ID("{5850c76e-b916-4218-b99a-31f004e0a7e7}"),
- classDescription: "Fennec Tab Source",
- contractID: "@mozilla.org/tab-source-service;1",
- QueryInterface: XPCOMUtils.generateQI([Ci.nsITabSource]),
-
- getTabToStream: function() {
- let app = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
- let tabs = app.tabs;
- if (tabs == null || tabs.length == 0) {
- Services.console.logStringMessage("ERROR: No tabs");
- return null;
- }
-
- let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
- let title = bundle.GetStringFromName("tabshare.title")
-
- let prompt = new Prompt({
- title: title,
- window: null
- }).setSingleChoiceItems(tabs.map(function(tab) {
- let label;
- if (tab.browser.contentTitle)
- label = tab.browser.contentTitle;
- else if (tab.browser.contentURI)
- label = tab.browser.contentURI.spec;
- else
- label = tab.originalURI.spec;
- return { label: label,
- icon: "thumbnail:" + tab.id }
- }));
-
- let result = null;
- prompt.show(function(data) {
- result = data.button;
- });
-
- // Spin this thread while we wait for a result.
- let thread = Services.tm.currentThread;
- while (result == null) {
- thread.processNextEvent(true);
- }
-
- if (result == -1) {
- return null;
- }
- return tabs[result].browser.contentWindow;
- },
-
- notifyStreamStart: function(window) {
- let app = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
- let tabs = app.tabs;
- for (var i in tabs) {
- if (tabs[i].browser.contentWindow == window) {
- Messaging.sendRequest({ type: "Tab:StreamStart", tabID: tabs[i].id });
- }
- }
- },
-
- notifyStreamStop: function(window) {
- let app = Services.wm.getMostRecentWindow("navigator:browser").BrowserApp;
- let tabs = app.tabs;
- for (let i in tabs) {
- if (tabs[i].browser.contentWindow == window) {
- Messaging.sendRequest({ type: "Tab:StreamStop", tabID: tabs[i].id });
- }
- }
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([TabSource]);
diff --git a/mobile/android/components/XPIDialogService.js b/mobile/android/components/XPIDialogService.js
deleted file mode 100644
index 2a33d4ddf..000000000
--- a/mobile/android/components/XPIDialogService.js
+++ /dev/null
@@ -1,49 +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/. */
-
-const Ci = Components.interfaces;
-const Cu = Components.utils;
-
-Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm");
-
-XPCOMUtils.defineLazyModuleGetter(this, "AddonManager", "resource://gre/modules/AddonManager.jsm");
-
-// -----------------------------------------------------------------------
-// Web Install Prompt service
-// -----------------------------------------------------------------------
-
-function WebInstallPrompt() { }
-
-WebInstallPrompt.prototype = {
- classID: Components.ID("{c1242012-27d8-477e-a0f1-0b098ffc329b}"),
- QueryInterface: XPCOMUtils.generateQI([Ci.amIWebInstallPrompt]),
-
- confirm: function(aBrowser, aURL, aInstalls) {
- let bundle = Services.strings.createBundle("chrome://browser/locale/browser.properties");
-
- let prompt = Services.prompt;
- let flags = prompt.BUTTON_POS_0 * prompt.BUTTON_TITLE_IS_STRING + prompt.BUTTON_POS_1 * prompt.BUTTON_TITLE_CANCEL;
- let title = bundle.GetStringFromName("addonsConfirmInstall.title");
- let button = bundle.GetStringFromName("addonsConfirmInstall.install");
-
- aInstalls.forEach(function(install) {
- let message;
- if (install.addon.signedState <= AddonManager.SIGNEDSTATE_MISSING) {
- title = bundle.GetStringFromName("addonsConfirmInstallUnsigned.title")
- message = bundle.GetStringFromName("addonsConfirmInstallUnsigned.message") + "\n\n" + install.name;
- } else {
- message = install.name;
- }
-
- let result = (prompt.confirmEx(aBrowser.contentWindow, title, message, flags, button, null, null, null, {value: false}) == 0);
- if (result)
- install.install();
- else
- install.cancel();
- });
- }
-};
-
-this.NSGetFactory = XPCOMUtils.generateNSGetFactory([WebInstallPrompt]);
diff --git a/mobile/android/components/build/moz.build b/mobile/android/components/build/moz.build
deleted file mode 100644
index 7a5c439e7..000000000
--- a/mobile/android/components/build/moz.build
+++ /dev/null
@@ -1,31 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-XPIDL_SOURCES += [
- 'nsIShellService.idl',
-]
-
-XPIDL_MODULE = 'browsercomps'
-
-EXPORTS += [
- 'nsBrowserComponents.h',
-]
-
-SOURCES += [
- 'nsBrowserModule.cpp',
- 'nsShellService.cpp',
-]
-
-if CONFIG['MOZ_ANDROID_HISTORY']:
- SOURCES += [
- 'nsAndroidHistory.cpp',
- ]
- LOCAL_INCLUDES += [
- '/docshell/base',
- '/dom/base',
- ]
-
-FINAL_LIBRARY = 'xul'
diff --git a/mobile/android/components/build/nsAndroidHistory.cpp b/mobile/android/components/build/nsAndroidHistory.cpp
deleted file mode 100644
index 2610781c0..000000000
--- a/mobile/android/components/build/nsAndroidHistory.cpp
+++ /dev/null
@@ -1,395 +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/. */
-
-#include "nsThreadUtils.h"
-#include "nsAndroidHistory.h"
-#include "nsComponentManagerUtils.h"
-#include "nsIURI.h"
-#include "nsIObserverService.h"
-#include "GeneratedJNIWrappers.h"
-#include "Link.h"
-
-#include "mozilla/Services.h"
-#include "mozilla/Preferences.h"
-
-#define NS_LINK_VISITED_EVENT_TOPIC "link-visited"
-
-// We copy Places here.
-// Note that we don't yet observe this pref at runtime.
-#define PREF_HISTORY_ENABLED "places.history.enabled"
-
-// Time we wait to see if a pending visit is really a redirect
-#define PENDING_REDIRECT_TIMEOUT 3000
-
-using namespace mozilla;
-using mozilla::dom::Link;
-
-NS_IMPL_ISUPPORTS(nsAndroidHistory, IHistory, nsIRunnable, nsITimerCallback)
-
-nsAndroidHistory* nsAndroidHistory::sHistory = nullptr;
-
-/*static*/
-nsAndroidHistory*
-nsAndroidHistory::GetSingleton()
-{
- if (!sHistory) {
- sHistory = new nsAndroidHistory();
- NS_ENSURE_TRUE(sHistory, nullptr);
- }
-
- NS_ADDREF(sHistory);
- return sHistory;
-}
-
-nsAndroidHistory::nsAndroidHistory()
- : mHistoryEnabled(true)
-{
- LoadPrefs();
-
- mTimer = do_CreateInstance(NS_TIMER_CONTRACTID);
-}
-
-NS_IMETHODIMP
-nsAndroidHistory::RegisterVisitedCallback(nsIURI *aURI, Link *aContent)
-{
- if (!aContent || !aURI)
- return NS_OK;
-
- // Silently return if URI is something we would never add to DB.
- bool canAdd;
- nsresult rv = CanAddURI(aURI, &canAdd);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!canAdd) {
- return NS_OK;
- }
-
- nsAutoCString uri;
- rv = aURI->GetSpec(uri);
- if (NS_FAILED(rv)) return rv;
- NS_ConvertUTF8toUTF16 uriString(uri);
-
- nsTArray<Link*>* list = mListeners.Get(uriString);
- if (! list) {
- list = new nsTArray<Link*>();
- mListeners.Put(uriString, list);
- }
- list->AppendElement(aContent);
-
- if (jni::IsAvailable()) {
- java::GeckoAppShell::CheckURIVisited(uriString);
- }
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAndroidHistory::UnregisterVisitedCallback(nsIURI *aURI, Link *aContent)
-{
- if (!aContent || !aURI)
- return NS_OK;
-
- nsAutoCString uri;
- nsresult rv = aURI->GetSpec(uri);
- if (NS_FAILED(rv)) return rv;
- NS_ConvertUTF8toUTF16 uriString(uri);
-
- nsTArray<Link*>* list = mListeners.Get(uriString);
- if (! list)
- return NS_OK;
-
- list->RemoveElement(aContent);
- if (list->IsEmpty()) {
- mListeners.Remove(uriString);
- delete list;
- }
- return NS_OK;
-}
-
-void
-nsAndroidHistory::AppendToRecentlyVisitedURIs(nsIURI* aURI) {
- if (mRecentlyVisitedURIs.Length() < RECENTLY_VISITED_URI_SIZE) {
- // Append a new element while the array is not full.
- mRecentlyVisitedURIs.AppendElement(aURI);
- } else {
- // Otherwise, replace the oldest member.
- mRecentlyVisitedURIsNextIndex %= RECENTLY_VISITED_URI_SIZE;
- mRecentlyVisitedURIs.ElementAt(mRecentlyVisitedURIsNextIndex) = aURI;
- mRecentlyVisitedURIsNextIndex++;
- }
-}
-
-bool
-nsAndroidHistory::ShouldRecordHistory() {
- return mHistoryEnabled;
-}
-
-void
-nsAndroidHistory::LoadPrefs() {
- mHistoryEnabled = Preferences::GetBool(PREF_HISTORY_ENABLED, true);
-}
-
-inline bool
-nsAndroidHistory::IsRecentlyVisitedURI(nsIURI* aURI) {
- bool equals = false;
- RecentlyVisitedArray::index_type i;
- RecentlyVisitedArray::size_type length = mRecentlyVisitedURIs.Length();
- for (i = 0; i < length && !equals; ++i) {
- aURI->Equals(mRecentlyVisitedURIs.ElementAt(i), &equals);
- }
- return equals;
-}
-
-void
-nsAndroidHistory::AppendToEmbedURIs(nsIURI* aURI) {
- if (mEmbedURIs.Length() < EMBED_URI_SIZE) {
- // Append a new element while the array is not full.
- mEmbedURIs.AppendElement(aURI);
- } else {
- // Otherwise, replace the oldest member.
- mEmbedURIsNextIndex %= EMBED_URI_SIZE;
- mEmbedURIs.ElementAt(mEmbedURIsNextIndex) = aURI;
- mEmbedURIsNextIndex++;
- }
-}
-
-inline bool
-nsAndroidHistory::IsEmbedURI(nsIURI* aURI) {
- bool equals = false;
- EmbedArray::index_type i;
- EmbedArray::size_type length = mEmbedURIs.Length();
- for (i = 0; i < length && !equals; ++i) {
- aURI->Equals(mEmbedURIs.ElementAt(i), &equals);
- }
- return equals;
-}
-
-inline bool
-nsAndroidHistory::RemovePendingVisitURI(nsIURI* aURI) {
- // Remove the first pending URI that matches. Return a boolean to
- // let the caller know if we removed a URI or not.
- bool equals = false;
- PendingVisitArray::index_type i;
- for (i = 0; i < mPendingVisitURIs.Length(); ++i) {
- aURI->Equals(mPendingVisitURIs.ElementAt(i), &equals);
- if (equals) {
- mPendingVisitURIs.RemoveElementAt(i);
- return true;
- }
- }
- return false;
-}
-
-NS_IMETHODIMP
-nsAndroidHistory::Notify(nsITimer *timer)
-{
- // Any pending visits left in the queue have exceeded our threshold for
- // redirects, so save them
- PendingVisitArray::index_type i;
- for (i = 0; i < mPendingVisitURIs.Length(); ++i) {
- SaveVisitURI(mPendingVisitURIs.ElementAt(i));
- }
- mPendingVisitURIs.Clear();
-
- return NS_OK;
-}
-
-void
-nsAndroidHistory::SaveVisitURI(nsIURI* aURI) {
- // Add the URI to our cache so we can take a fast path later
- AppendToRecentlyVisitedURIs(aURI);
-
- if (jni::IsAvailable()) {
- // Save this URI in our history
- nsAutoCString spec;
- (void)aURI->GetSpec(spec);
- java::GeckoAppShell::MarkURIVisited(NS_ConvertUTF8toUTF16(spec));
- }
-
- // Finally, notify that we've been visited.
- nsCOMPtr<nsIObserverService> obsService = mozilla::services::GetObserverService();
- if (obsService) {
- obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nullptr);
- }
-}
-
-NS_IMETHODIMP
-nsAndroidHistory::VisitURI(nsIURI *aURI, nsIURI *aLastVisitedURI, uint32_t aFlags)
-{
- if (!aURI) {
- return NS_OK;
- }
-
- if (!(aFlags & VisitFlags::TOP_LEVEL)) {
- return NS_OK;
- }
-
- if (aFlags & VisitFlags::UNRECOVERABLE_ERROR) {
- return NS_OK;
- }
-
- // Silently return if URI is something we shouldn't add to DB.
- bool canAdd;
- nsresult rv = CanAddURI(aURI, &canAdd);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!canAdd) {
- return NS_OK;
- }
-
- if (aLastVisitedURI) {
- if (aFlags & VisitFlags::REDIRECT_SOURCE ||
- aFlags & VisitFlags::REDIRECT_PERMANENT ||
- aFlags & VisitFlags::REDIRECT_TEMPORARY) {
- // aLastVisitedURI redirected to aURI. We want to ignore aLastVisitedURI,
- // so remove the pending visit. We want to give aURI a chance to be saved,
- // so don't return early.
- RemovePendingVisitURI(aLastVisitedURI);
- }
-
- bool same;
- rv = aURI->Equals(aLastVisitedURI, &same);
- NS_ENSURE_SUCCESS(rv, rv);
- if (same && IsRecentlyVisitedURI(aURI)) {
- // Do not save refresh visits if we have visited this URI recently.
- return NS_OK;
- }
-
- // Since we have a last visited URI and we were not redirected, it is
- // safe to save the visit if it's still pending.
- if (RemovePendingVisitURI(aLastVisitedURI)) {
- SaveVisitURI(aLastVisitedURI);
- }
- }
-
- // Let's wait and see if this visit is not a redirect.
- mPendingVisitURIs.AppendElement(aURI);
- mTimer->InitWithCallback(this, PENDING_REDIRECT_TIMEOUT, nsITimer::TYPE_ONE_SHOT);
-
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAndroidHistory::SetURITitle(nsIURI *aURI, const nsAString& aTitle)
-{
- // Silently return if URI is something we shouldn't add to DB.
- bool canAdd;
- nsresult rv = CanAddURI(aURI, &canAdd);
- NS_ENSURE_SUCCESS(rv, rv);
- if (!canAdd) {
- return NS_OK;
- }
-
- if (IsEmbedURI(aURI)) {
- return NS_OK;
- }
-
- if (jni::IsAvailable()) {
- nsAutoCString uri;
- nsresult rv = aURI->GetSpec(uri);
- if (NS_FAILED(rv)) return rv;
- if (RemovePendingVisitURI(aURI)) {
- // We have a title, so aURI isn't a redirect, so save the visit now before setting the title.
- SaveVisitURI(aURI);
- }
- NS_ConvertUTF8toUTF16 uriString(uri);
- java::GeckoAppShell::SetURITitle(uriString, aTitle);
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAndroidHistory::NotifyVisited(nsIURI *aURI)
-{
- if (aURI && sHistory) {
- nsAutoCString spec;
- (void)aURI->GetSpec(spec);
- sHistory->mPendingLinkURIs.Push(NS_ConvertUTF8toUTF16(spec));
- NS_DispatchToMainThread(sHistory);
- }
- return NS_OK;
-}
-
-NS_IMETHODIMP
-nsAndroidHistory::Run()
-{
- while (! mPendingLinkURIs.IsEmpty()) {
- nsString uriString = mPendingLinkURIs.Pop();
- nsTArray<Link*>* list = sHistory->mListeners.Get(uriString);
- if (list) {
- for (unsigned int i = 0; i < list->Length(); i++) {
- list->ElementAt(i)->SetLinkState(eLinkState_Visited);
- }
- // as per the IHistory interface contract, remove the
- // Link pointers once they have been notified
- mListeners.Remove(uriString);
- delete list;
- }
- }
- return NS_OK;
-}
-
-// Filter out unwanted URIs such as "chrome:", "mailbox:", etc.
-//
-// The model is if we don't know differently then add which basically means
-// we are suppose to try all the things we know not to allow in and then if
-// we don't bail go on and allow it in.
-//
-// Logic ported from nsNavHistory::CanAddURI.
-
-NS_IMETHODIMP
-nsAndroidHistory::CanAddURI(nsIURI* aURI, bool* canAdd)
-{
- NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
- NS_ENSURE_ARG(aURI);
- NS_ENSURE_ARG_POINTER(canAdd);
-
- // See if we're disabled.
- if (!ShouldRecordHistory()) {
- *canAdd = false;
- return NS_OK;
- }
-
- nsAutoCString scheme;
- nsresult rv = aURI->GetScheme(scheme);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // first check the most common cases (HTTP, HTTPS) to allow in to avoid most
- // of the work
- if (scheme.EqualsLiteral("http")) {
- *canAdd = true;
- return NS_OK;
- }
- if (scheme.EqualsLiteral("https")) {
- *canAdd = true;
- return NS_OK;
- }
- if (scheme.EqualsLiteral("about")) {
- nsAutoCString path;
- rv = aURI->GetPath(path);
- NS_ENSURE_SUCCESS(rv, rv);
-
- if (StringBeginsWith(path, NS_LITERAL_CSTRING("reader"))) {
- *canAdd = true;
- return NS_OK;
- }
- }
-
- // now check for all bad things
- if (scheme.EqualsLiteral("about") ||
- scheme.EqualsLiteral("imap") ||
- scheme.EqualsLiteral("news") ||
- scheme.EqualsLiteral("mailbox") ||
- scheme.EqualsLiteral("moz-anno") ||
- scheme.EqualsLiteral("view-source") ||
- scheme.EqualsLiteral("chrome") ||
- scheme.EqualsLiteral("resource") ||
- scheme.EqualsLiteral("data") ||
- scheme.EqualsLiteral("wyciwyg") ||
- scheme.EqualsLiteral("javascript") ||
- scheme.EqualsLiteral("blob")) {
- *canAdd = false;
- return NS_OK;
- }
- *canAdd = true;
- return NS_OK;
-}
diff --git a/mobile/android/components/build/nsAndroidHistory.h b/mobile/android/components/build/nsAndroidHistory.h
deleted file mode 100644
index 382fbcd2e..000000000
--- a/mobile/android/components/build/nsAndroidHistory.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/* -*- Mode: c++; c-basic-offset: 4; tab-width: 20; 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/. */
-
-#ifndef NS_ANDROIDHISTORY_H
-#define NS_ANDROIDHISTORY_H
-
-#include "IHistory.h"
-#include "nsDataHashtable.h"
-#include "nsTPriorityQueue.h"
-#include "nsIRunnable.h"
-#include "nsIURI.h"
-#include "nsITimer.h"
-
-
-#define NS_ANDROIDHISTORY_CID \
- {0xCCAA4880, 0x44DD, 0x40A7, {0xA1, 0x3F, 0x61, 0x56, 0xFC, 0x88, 0x2C, 0x0B}}
-
-// Max size of History::mRecentlyVisitedURIs
-#define RECENTLY_VISITED_URI_SIZE 8
-
-// Max size of History::mEmbedURIs
-#define EMBED_URI_SIZE 128
-
-class nsAndroidHistory final : public mozilla::IHistory,
- public nsIRunnable,
- public nsITimerCallback
-{
-public:
- NS_DECL_ISUPPORTS
- NS_DECL_IHISTORY
- NS_DECL_NSIRUNNABLE
- NS_DECL_NSITIMERCALLBACK
-
- /**
- * Obtains a pointer that has had AddRef called on it. Used by the service
- * manager only.
- */
- static nsAndroidHistory* GetSingleton();
-
- nsAndroidHistory();
-
-private:
- ~nsAndroidHistory() {}
-
- static nsAndroidHistory* sHistory;
-
- // Will mimic the value of the places.history.enabled preference.
- bool mHistoryEnabled;
-
- void LoadPrefs();
- bool ShouldRecordHistory();
- nsresult CanAddURI(nsIURI* aURI, bool* canAdd);
-
- /**
- * We need to manage data used to determine a:visited status.
- */
- nsDataHashtable<nsStringHashKey, nsTArray<mozilla::dom::Link *> *> mListeners;
- nsTPriorityQueue<nsString> mPendingLinkURIs;
-
- /**
- * Redirection (temporary and permanent) flags are sent with the redirected
- * URI, not the original URI. Since we want to ignore the original URI, we
- * need to cache the pending visit and make sure it doesn't redirect.
- */
- RefPtr<nsITimer> mTimer;
- typedef AutoTArray<nsCOMPtr<nsIURI>, RECENTLY_VISITED_URI_SIZE> PendingVisitArray;
- PendingVisitArray mPendingVisitURIs;
-
- bool RemovePendingVisitURI(nsIURI* aURI);
- void SaveVisitURI(nsIURI* aURI);
-
- /**
- * mRecentlyVisitedURIs remembers URIs which are recently added to the DB,
- * to avoid saving these locations repeatedly in a short period.
- */
- typedef AutoTArray<nsCOMPtr<nsIURI>, RECENTLY_VISITED_URI_SIZE> RecentlyVisitedArray;
- RecentlyVisitedArray mRecentlyVisitedURIs;
- RecentlyVisitedArray::index_type mRecentlyVisitedURIsNextIndex;
-
- void AppendToRecentlyVisitedURIs(nsIURI* aURI);
- bool IsRecentlyVisitedURI(nsIURI* aURI);
-
- /**
- * mEmbedURIs remembers URIs which are explicitly not added to the DB,
- * to avoid wasting time on these locations.
- */
- typedef AutoTArray<nsCOMPtr<nsIURI>, EMBED_URI_SIZE> EmbedArray;
- EmbedArray::index_type mEmbedURIsNextIndex;
- EmbedArray mEmbedURIs;
-
- void AppendToEmbedURIs(nsIURI* aURI);
- bool IsEmbedURI(nsIURI* aURI);
-};
-
-#endif
diff --git a/mobile/android/components/build/nsBrowserComponents.h b/mobile/android/components/build/nsBrowserComponents.h
deleted file mode 100644
index c9830d9c5..000000000
--- a/mobile/android/components/build/nsBrowserComponents.h
+++ /dev/null
@@ -1,7 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-// Needed for building our components as part of libxul
-#define APP_COMPONENT_MODULES MODULE(nsBrowserCompsModule)
diff --git a/mobile/android/components/build/nsBrowserModule.cpp b/mobile/android/components/build/nsBrowserModule.cpp
deleted file mode 100644
index 6f9fe67bf..000000000
--- a/mobile/android/components/build/nsBrowserModule.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-#include "mozilla/ModuleUtils.h"
-
-#include "nsShellService.h"
-
-#ifdef MOZ_ANDROID_HISTORY
-#include "nsDocShellCID.h"
-#include "nsAndroidHistory.h"
-#define NS_ANDROIDHISTORY_CID \
- {0xCCAA4880, 0x44DD, 0x40A7, {0xA1, 0x3F, 0x61, 0x56, 0xFC, 0x88, 0x2C, 0x0B}}
-#endif
-
-NS_GENERIC_FACTORY_CONSTRUCTOR(nsShellService)
-NS_DEFINE_NAMED_CID(nsShellService_CID);
-
-#ifdef MOZ_ANDROID_HISTORY
-NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsAndroidHistory, nsAndroidHistory::GetSingleton)
-NS_DEFINE_NAMED_CID(NS_ANDROIDHISTORY_CID);
-#endif
-
-static const mozilla::Module::CIDEntry kBrowserCIDs[] = {
- { &knsShellService_CID, false, nullptr, nsShellServiceConstructor },
-#ifdef MOZ_ANDROID_HISTORY
- { &kNS_ANDROIDHISTORY_CID, false, nullptr, nsAndroidHistoryConstructor },
-#endif
- { nullptr }
-};
-
-static const mozilla::Module::ContractIDEntry kBrowserContracts[] = {
- { nsShellService_ContractID, &knsShellService_CID },
-#ifdef MOZ_ANDROID_HISTORY
- { NS_IHISTORY_CONTRACTID, &kNS_ANDROIDHISTORY_CID },
-#endif
- { nullptr }
-};
-
-static const mozilla::Module kBrowserModule = {
- mozilla::Module::kVersion,
- kBrowserCIDs,
- kBrowserContracts
-};
-
-NSMODULE_DEFN(nsBrowserCompsModule) = &kBrowserModule;
diff --git a/mobile/android/components/build/nsIShellService.idl b/mobile/android/components/build/nsIShellService.idl
deleted file mode 100644
index e7f8d9277..000000000
--- a/mobile/android/components/build/nsIShellService.idl
+++ /dev/null
@@ -1,26 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-#include "nsISupports.idl"
-
-[scriptable, uuid(fd2450a3-966b-44a9-a8eb-316256bb80b4)]
-interface nsIShellService : nsISupports
-{
- /**
- * This method displays a UI to switch to (or launch) a different task
- */
- void switchTask();
-
- /**
- * This method creates a shortcut on a desktop or homescreen that opens in
- * the our application.
- *
- * @param aTitle the user-friendly name of the shortcut.
- * @param aURI the URI to open.
- * @param aIconData obsolete and ignored, but remains for backward compatibility; pass an empty string
- * @param aIntent obsolete and ignored, but remains for backward compatibility; pass an empty string
- */
- void createShortcut(in AString aTitle, in AString aURI, in AString aIconData, in AString aIntent);
-};
diff --git a/mobile/android/components/build/nsShellService.cpp b/mobile/android/components/build/nsShellService.cpp
deleted file mode 100644
index 86cac86b4..000000000
--- a/mobile/android/components/build/nsShellService.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-#include "nsShellService.h"
-#include "nsString.h"
-
-#include "GeneratedJNIWrappers.h"
-
-using namespace mozilla;
-
-NS_IMPL_ISUPPORTS(nsShellService, nsIShellService)
-
-NS_IMETHODIMP
-nsShellService::SwitchTask()
-{
- return NS_ERROR_NOT_IMPLEMENTED;
-}
-
-NS_IMETHODIMP
-nsShellService::CreateShortcut(const nsAString& aTitle, const nsAString& aURI,
- const nsAString& aIcondata, const nsAString& aIntent)
-{
- if (!aTitle.Length() || !aURI.Length())
- return NS_ERROR_FAILURE;
-
- java::GeckoAppShell::CreateShortcut(aTitle, aURI);
- return NS_OK;
-}
diff --git a/mobile/android/components/build/nsShellService.h b/mobile/android/components/build/nsShellService.h
deleted file mode 100644
index ba56cbcae..000000000
--- a/mobile/android/components/build/nsShellService.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* 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/. */
-
-#ifndef __NS_SHELLSERVICE_H__
-#define __NS_SHELLSERVICE_H__
-
-#include "nsIShellService.h"
-
-class nsShellService final : public nsIShellService
-{
-public:
-
- NS_DECL_ISUPPORTS
- NS_DECL_NSISHELLSERVICE
-
- nsShellService() {}
-
-private:
- ~nsShellService() {}
-};
-
-#define nsShellService_CID \
-{0xae9ebe1c, 0x61e9, 0x45fa, {0x8f, 0x34, 0xc1, 0x07, 0x80, 0x3a, 0x5b, 0x44}}
-
-#define nsShellService_ContractID "@mozilla.org/browser/shell-service;1"
-
-#endif
diff --git a/mobile/android/components/extensions/.eslintrc.js b/mobile/android/components/extensions/.eslintrc.js
deleted file mode 100644
index 4b67e27b8..000000000
--- a/mobile/android/components/extensions/.eslintrc.js
+++ /dev/null
@@ -1,5 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": "../../../../toolkit/components/extensions/.eslintrc.js",
-};
diff --git a/mobile/android/components/extensions/ext-pageAction.js b/mobile/android/components/extensions/ext-pageAction.js
deleted file mode 100644
index fb1c3a3f3..000000000
--- a/mobile/android/components/extensions/ext-pageAction.js
+++ /dev/null
@@ -1,169 +0,0 @@
-/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set sts=2 sw=2 et tw=80: */
-"use strict";
-
-XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
- "resource://devtools/shared/event-emitter.js");
-
-XPCOMUtils.defineLazyModuleGetter(this, "Services",
- "resource://gre/modules/Services.jsm");
-
-// Import the android PageActions module.
-XPCOMUtils.defineLazyModuleGetter(this, "PageActions",
- "resource://gre/modules/PageActions.jsm");
-
-Cu.import("resource://gre/modules/ExtensionUtils.jsm");
-
-var {
- IconDetails,
- SingletonEventManager,
-} = ExtensionUtils;
-
-// WeakMap[Extension -> PageAction]
-var pageActionMap = new WeakMap();
-
-function PageAction(options, extension) {
- this.id = null;
-
- this.extension = extension;
- this.icons = IconDetails.normalize({path: options.default_icon}, extension);
-
- this.popupUrl = options.default_popup;
-
- this.options = {
- title: options.default_title || extension.name,
- id: `{${extension.uuid}}`,
- clickCallback: () => {
- if (this.popupUrl) {
- let win = Services.wm.getMostRecentWindow("navigator:browser");
- win.BrowserApp.addTab(this.popupUrl, {
- selected: true,
- parentId: win.BrowserApp.selectedTab.id,
- });
- } else {
- this.emit("click");
- }
- },
- };
-
- this.shouldShow = false;
-
- EventEmitter.decorate(this);
-}
-
-PageAction.prototype = {
- show(tabId, context) {
- if (this.id) {
- return Promise.resolve();
- }
-
- if (this.options.icon) {
- this.id = PageActions.add(this.options);
- return Promise.resolve();
- }
-
- this.shouldShow = true;
-
- // TODO(robwu): Remove dependency on contentWindow from this file. It should
- // be put in a separate file called ext-c-pageAction.js.
- // Note: Fennec is not going to be multi-process for the foreseaable future,
- // so this layering violation has no immediate impact. However, it is should
- // be done at some point.
- let {contentWindow} = context.xulBrowser;
-
- // TODO(robwu): Why is this contentWindow.devicePixelRatio, while
- // convertImageURLToDataURL uses browserWindow.devicePixelRatio?
- let {icon} = IconDetails.getPreferredIcon(this.icons, this.extension,
- 18 * contentWindow.devicePixelRatio);
-
- let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
- return IconDetails.convertImageURLToDataURL(icon, contentWindow, browserWindow).then(dataURI => {
- if (this.shouldShow) {
- this.options.icon = dataURI;
- this.id = PageActions.add(this.options);
- }
- }).catch(() => {
- return Promise.reject({
- message: "Failed to load PageAction icon",
- });
- });
- },
-
- hide(tabId) {
- this.shouldShow = false;
- if (this.id) {
- PageActions.remove(this.id);
- this.id = null;
- }
- },
-
- setPopup(tab, url) {
- // TODO: Only set the popup for the specified tab once we have Tabs API support.
- this.popupUrl = url;
- },
-
- getPopup(tab) {
- // TODO: Only return the popup for the specified tab once we have Tabs API support.
- return this.popupUrl;
- },
-
- shutdown() {
- this.hide();
- },
-};
-
-/* eslint-disable mozilla/balanced-listeners */
-extensions.on("manifest_page_action", (type, directive, extension, manifest) => {
- let pageAction = new PageAction(manifest.page_action, extension);
- pageActionMap.set(extension, pageAction);
-});
-
-extensions.on("shutdown", (type, extension) => {
- if (pageActionMap.has(extension)) {
- pageActionMap.get(extension).shutdown();
- pageActionMap.delete(extension);
- }
-});
-/* eslint-enable mozilla/balanced-listeners */
-
-extensions.registerSchemaAPI("pageAction", "addon_parent", context => {
- let {extension} = context;
- return {
- pageAction: {
- onClicked: new SingletonEventManager(context, "pageAction.onClicked", fire => {
- let listener = (event) => {
- fire();
- };
- pageActionMap.get(extension).on("click", listener);
- return () => {
- pageActionMap.get(extension).off("click", listener);
- };
- }).api(),
-
- show(tabId) {
- return pageActionMap.get(extension)
- .show(tabId, context)
- .then(() => {});
- },
-
- hide(tabId) {
- pageActionMap.get(extension).hide(tabId);
- return Promise.resolve();
- },
-
- setPopup(details) {
- // TODO: Use the Tabs API to get the tab from details.tabId.
- let tab = null;
- let url = details.popup && context.uri.resolve(details.popup);
- pageActionMap.get(extension).setPopup(tab, url);
- },
-
- getPopup(details) {
- // TODO: Use the Tabs API to get the tab from details.tabId.
- let tab = null;
- let popup = pageActionMap.get(extension).getPopup(tab);
- return Promise.resolve(popup);
- },
- },
- };
-});
diff --git a/mobile/android/components/extensions/extensions-mobile.manifest b/mobile/android/components/extensions/extensions-mobile.manifest
deleted file mode 100644
index f15540d62..000000000
--- a/mobile/android/components/extensions/extensions-mobile.manifest
+++ /dev/null
@@ -1,5 +0,0 @@
-# scripts
-category webextension-scripts pageAction chrome://browser/content/ext-pageAction.js
-
-# schemas
-category webextension-schemas page_action chrome://browser/content/schemas/page_action.json \ No newline at end of file
diff --git a/mobile/android/components/extensions/jar.mn b/mobile/android/components/extensions/jar.mn
deleted file mode 100644
index a3d2b8de8..000000000
--- a/mobile/android/components/extensions/jar.mn
+++ /dev/null
@@ -1,6 +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/.
-
-chrome.jar:
- content/ext-pageAction.js \ No newline at end of file
diff --git a/mobile/android/components/extensions/moz.build b/mobile/android/components/extensions/moz.build
deleted file mode 100644
index 0953fcefc..000000000
--- a/mobile/android/components/extensions/moz.build
+++ /dev/null
@@ -1,16 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-JAR_MANIFESTS += ['jar.mn']
-
-EXTRA_COMPONENTS += [
- 'extensions-mobile.manifest',
-]
-
-DIRS += ['schemas']
-
-MOCHITEST_MANIFESTS += ['test/mochitest/mochitest.ini']
-MOCHITEST_CHROME_MANIFESTS += ['test/mochitest/chrome.ini']
diff --git a/mobile/android/components/extensions/schemas/jar.mn b/mobile/android/components/extensions/schemas/jar.mn
deleted file mode 100644
index 1a587ce20..000000000
--- a/mobile/android/components/extensions/schemas/jar.mn
+++ /dev/null
@@ -1,6 +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/.
-
-chrome.jar:
- content/schemas/page_action.json \ No newline at end of file
diff --git a/mobile/android/components/extensions/schemas/moz.build b/mobile/android/components/extensions/schemas/moz.build
deleted file mode 100644
index eb4454d28..000000000
--- a/mobile/android/components/extensions/schemas/moz.build
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-JAR_MANIFESTS += ['jar.mn'] \ No newline at end of file
diff --git a/mobile/android/components/extensions/schemas/page_action.json b/mobile/android/components/extensions/schemas/page_action.json
deleted file mode 100644
index 5e9280922..000000000
--- a/mobile/android/components/extensions/schemas/page_action.json
+++ /dev/null
@@ -1,239 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-[
- {
- "namespace": "manifest",
- "types": [
- {
- "$extend": "WebExtensionManifest",
- "properties": {
- "page_action": {
- "type": "object",
- "additionalProperties": { "$ref": "UnrecognizedProperty" },
- "properties": {
- "default_title": {
- "type": "string",
- "optional": true,
- "preprocess": "localize"
- },
- "default_icon": {
- "$ref": "IconPath",
- "optional": true
- },
- "default_popup": {
- "type": "string",
- "format": "relativeUrl",
- "optional": true,
- "preprocess": "localize"
- },
- "browser_style": {
- "type": "boolean",
- "optional": true
- }
- },
- "optional": true
- }
- }
- }
- ]
- },
- {
- "namespace": "pageAction",
- "description": "Use the <code>browser.pageAction</code> API to put icons inside the address bar. Page actions represent actions that can be taken on the current page, but that aren't applicable to all pages.",
- "permissions": ["manifest:page_action"],
- "types": [
- {
- "id": "ImageDataType",
- "type": "object",
- "isInstanceOf": "ImageData",
- "additionalProperties": { "type": "any" },
- "description": "Pixel data for an image. Must be an ImageData object (for example, from a <code>canvas</code> element)."
- }
- ],
- "functions": [
- {
- "name": "show",
- "type": "function",
- "description": "Shows the page action. The page action is shown whenever the tab is selected.",
- "async": "callback",
- "parameters": [
- {"type": "integer", "name": "tabId", "minimum": 0, "description": "The id of the tab for which you want to modify the page action."},
- {
- "type": "function",
- "name": "callback",
- "optional": true,
- "parameters": []
- }
- ]
- },
- {
- "name": "hide",
- "type": "function",
- "description": "Hides the page action.",
- "async": "callback",
- "parameters": [
- {"type": "integer", "name": "tabId", "minimum": 0, "description": "The id of the tab for which you want to modify the page action."},
- {
- "type": "function",
- "name": "callback",
- "optional": true,
- "parameters": []
- }
- ]
- },
- {
- "name": "setTitle",
- "unsupported": true,
- "type": "function",
- "description": "Sets the title of the page action. This is displayed in a tooltip over the page action.",
- "parameters": [
- {
- "name": "details",
- "type": "object",
- "properties": {
- "tabId": {"type": "integer", "minimum": 0, "description": "The id of the tab for which you want to modify the page action."},
- "title": {"type": "string", "description": "The tooltip string."}
- }
- }
- ]
- },
- {
- "name": "getTitle",
- "unsupported": true,
- "type": "function",
- "description": "Gets the title of the page action.",
- "async": "callback",
- "parameters": [
- {
- "name": "details",
- "type": "object",
- "properties": {
- "tabId": {
- "type": "integer",
- "description": "Specify the tab to get the title from."
- }
- }
- },
- {
- "type": "function",
- "name": "callback",
- "parameters": [
- {
- "name": "result",
- "type": "string"
- }
- ]
- }
- ]
- },
- {
- "name": "setIcon",
- "unsupported": true,
- "type": "function",
- "description": "Sets the icon for the page action. The icon can be specified either as the path to an image file or as the pixel data from a canvas element, or as dictionary of either one of those. Either the <b>path</b> or the <b>imageData</b> property must be specified.",
- "async": "callback",
- "parameters": [
- {
- "name": "details",
- "type": "object",
- "properties": {
- "tabId": {"type": "integer", "minimum": 0, "description": "The id of the tab for which you want to modify the page action."},
- "imageData": {
- "choices": [
- { "$ref": "ImageDataType" },
- {
- "type": "object",
- "additionalProperties": {"$ref": "ImageDataType"}
- }
- ],
- "optional": true,
- "description": "Either an ImageData object or a dictionary {size -> ImageData} representing icon to be set. If the icon is specified as a dictionary, the actual image to be used is chosen depending on screen's pixel density. If the number of image pixels that fit into one screen space unit equals <code>scale</code>, then image with size <code>scale</code> * 19 will be selected. Initially only scales 1 and 2 will be supported. At least one image must be specified. Note that 'details.imageData = foo' is equivalent to 'details.imageData = {'19': foo}'"
- },
- "path": {
- "choices": [
- { "type": "string" },
- {
- "type": "object",
- "additionalProperties": {"type": "string"}
- }
- ],
- "optional": true,
- "description": "Either a relative image path or a dictionary {size -> relative image path} pointing to icon to be set. If the icon is specified as a dictionary, the actual image to be used is chosen depending on screen's pixel density. If the number of image pixels that fit into one screen space unit equals <code>scale</code>, then image with size <code>scale</code> * 19 will be selected. Initially only scales 1 and 2 will be supported. At least one image must be specified. Note that 'details.path = foo' is equivalent to 'details.imageData = {'19': foo}'"
- }
- }
- },
- {
- "type": "function",
- "name": "callback",
- "optional": true,
- "parameters": []
- }
- ]
- },
- {
- "name": "setPopup",
- "type": "function",
- "async": "callback",
- "description": "Sets the html document to be opened as a popup when the user clicks on the page action's icon.",
- "parameters": [
- {
- "name": "details",
- "type": "object",
- "properties": {
- "tabId": {"type": "integer", "minimum": 0, "description": "The id of the tab for which you want to modify the page action."},
- "popup": {
- "type": "string",
- "description": "The html file to show in a popup. If set to the empty string (''), no popup is shown."
- }
- }
- },
- {
- "type": "function",
- "name": "callback",
- "optional": true,
- "parameters": []
- }
- ]
- },
- {
- "name": "getPopup",
- "type": "function",
- "description": "Gets the html document set as the popup for this page action.",
- "async": "callback",
- "parameters": [
- {
- "name": "details",
- "type": "object",
- "properties": {
- "tabId": {
- "type": "integer",
- "description": "Specify the tab to get the popup from."
- }
- }
- },
- {
- "type": "function",
- "name": "callback",
- "optional": true,
- "parameters": []
- }
- ]
- }
- ],
- "events": [
- {
- "name": "onClicked",
- "type": "function",
- "description": "Fired when a page action icon is clicked. This event will not fire if the page action has a popup.",
- "parameters": [
- {
- "name": "tab",
- "$ref": "tabs.Tab"
- }
- ]
- }
- ]
- }
-]
diff --git a/mobile/android/components/extensions/test/mochitest/.eslintrc.js b/mobile/android/components/extensions/test/mochitest/.eslintrc.js
deleted file mode 100644
index 5f9059e18..000000000
--- a/mobile/android/components/extensions/test/mochitest/.eslintrc.js
+++ /dev/null
@@ -1,10 +0,0 @@
-"use strict";
-
-module.exports = {
- "extends": "../../../../../../toolkit/components/extensions/test/mochitest/.eslintrc.js",
-
- "globals": {
- "isPageActionShown": true,
- "clickPageAction": true,
- },
-};
diff --git a/mobile/android/components/extensions/test/mochitest/chrome.ini b/mobile/android/components/extensions/test/mochitest/chrome.ini
deleted file mode 100644
index e19ddf393..000000000
--- a/mobile/android/components/extensions/test/mochitest/chrome.ini
+++ /dev/null
@@ -1,7 +0,0 @@
-[DEFAULT]
-support-files =
- head.js
-tags = webextensions
-
-[test_ext_pageAction.html]
-[test_ext_pageAction_popup.html]
diff --git a/mobile/android/components/extensions/test/mochitest/head.js b/mobile/android/components/extensions/test/mochitest/head.js
deleted file mode 100644
index be9683682..000000000
--- a/mobile/android/components/extensions/test/mochitest/head.js
+++ /dev/null
@@ -1,15 +0,0 @@
-"use strict";
-
-/* exported isPageActionShown clickPageAction */
-
-const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
-
-Cu.import("resource://gre/modules/PageActions.jsm");
-
-function isPageActionShown(uuid) {
- return PageActions.isShown(uuid);
-}
-
-function clickPageAction(uuid) {
- PageActions.synthesizeClick(uuid);
-}
diff --git a/mobile/android/components/extensions/test/mochitest/mochitest.ini b/mobile/android/components/extensions/test/mochitest/mochitest.ini
deleted file mode 100644
index 59ef4bd20..000000000
--- a/mobile/android/components/extensions/test/mochitest/mochitest.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[DEFAULT]
-support-files =
- ../../../../../../toolkit/components/extensions/test/mochitest/test_ext_all_apis.js
-tags = webextensions
-
-[test_ext_all_apis.html]
diff --git a/mobile/android/components/extensions/test/mochitest/test_ext_all_apis.html b/mobile/android/components/extensions/test/mochitest/test_ext_all_apis.html
deleted file mode 100644
index aec3eb7c1..000000000
--- a/mobile/android/components/extensions/test/mochitest/test_ext_all_apis.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <title>WebExtension test</title>
- <meta charset="utf-8">
- <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
- <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
- <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
- <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
-</head>
-<body>
-<script>
-"use strict";
-/* exported expectedContentApisTargetSpecific, expectedBackgroundApisTargetSpecific */
-let expectedContentApisTargetSpecific = [
-];
-
-let expectedBackgroundApisTargetSpecific = [
-];
-</script>
-<script src="test_ext_all_apis.js"></script>
-</body>
-</html>
diff --git a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html
deleted file mode 100644
index b13c551bd..000000000
--- a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction.html
+++ /dev/null
@@ -1,99 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <title>PageAction Test</title>
- <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
- <script type="text/javascript" src="head.js"></script>
- <link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
-</head>
-<body>
-
-<script type="text/javascript">
-"use strict";
-
-let dataURI = "iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC";
-
-let image = atob(dataURI);
-const IMAGE_ARRAYBUFFER = Uint8Array.from(image, byte => byte.charCodeAt(0)).buffer;
-
-function background() {
- browser.test.assertTrue("pageAction" in browser, "Namespace 'pageAction' exists in browser");
- browser.test.assertTrue("show" in browser.pageAction, "API method 'show' exists in browser.pageAction");
-
- // TODO: Use the Tabs API to obtain the tab ids for showing pageActions.
- let tabId = 1;
- browser.test.onMessage.addListener(msg => {
- if (msg === "pageAction-show") {
- browser.pageAction.show(tabId).then(() => {
- browser.test.sendMessage("page-action-shown");
- });
- } else if (msg === "pageAction-hide") {
- browser.pageAction.hide(tabId).then(() => {
- browser.test.sendMessage("page-action-hidden");
- });
- }
- });
-
- browser.pageAction.onClicked.addListener(tab => {
- // TODO: Make sure we get the correct tab once basic tabs support is added.
- browser.test.sendMessage("page-action-clicked");
- });
-
- let extensionInfo = {
- // Extract the assigned uuid from the background page url.
- uuid: `{${window.location.hostname}}`,
- };
-
- browser.test.sendMessage("ready", extensionInfo);
-}
-
-add_task(function* test_pageAction() {
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- "name": "PageAction Extension",
- "page_action": {
- "default_title": "Page Action",
- "default_icon": {
- "18": "extension.png",
- },
- },
- "applications": {
- "gecko": {
- "id": "foo@bar.com",
- },
- },
- },
- files: {
- "extension.png": IMAGE_ARRAYBUFFER,
- },
- });
-
- yield extension.startup();
- let {uuid} = yield extension.awaitMessage("ready");
-
- extension.sendMessage("pageAction-show");
- yield extension.awaitMessage("page-action-shown");
- ok(isPageActionShown(uuid), "The PageAction should be shown");
-
- extension.sendMessage("pageAction-hide");
- yield extension.awaitMessage("page-action-hidden");
- ok(!isPageActionShown(uuid), "The PageAction should be hidden");
-
- extension.sendMessage("pageAction-show");
- yield extension.awaitMessage("page-action-shown");
- ok(isPageActionShown(uuid), "The PageAction should be shown");
-
- clickPageAction(uuid);
- yield extension.awaitMessage("page-action-clicked");
- ok(isPageActionShown(uuid), "The PageAction should still be shown after being clicked");
-
- yield extension.unload();
- ok(!isPageActionShown(uuid), "The PageAction should be removed after unload");
-});
-</script>
-
-</body>
-</html>
diff --git a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html b/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html
deleted file mode 100644
index 89edc7c29..000000000
--- a/mobile/android/components/extensions/test/mochitest/test_ext_pageAction_popup.html
+++ /dev/null
@@ -1,169 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
- <title>PageAction Test</title>
- <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
- <script src="chrome://mochikit/content/tests/SimpleTest/SpawnTask.js"></script>
- <script src="chrome://mochikit/content/tests/SimpleTest/ExtensionTestUtils.js"></script>
- <script type="text/javascript" src="head.js"></script>
- <link rel="stylesheet" href="chrome://mochikit/contents/tests/SimpleTest/test.css"/>
-</head>
-<body>
-
-<script type="text/javascript">
-"use strict";
-
-Cu.import("resource://gre/modules/Services.jsm");
-
-let dataURI = "iVBORw0KGgoAAAANSUhEUgAAACQAAAAkCAYAAADhAJiYAAAC4klEQVRYhdWXLWzbQBSADQtDAwsHC1tUhUxqfL67lk2tdn+OJg0ODU0rLByqgqINBY6tmlbn7LMTJ5FaFVVBk1G0oUGjG2jT2Y7jxmmcbU/6iJ+f36fz+e5sGP9riCGm9hB37RG+scd4Yo/wsDXCZyIE2xuXsce4bY+wXkAsQtzYmExrfFgvkJkRbkzo1ehoxx5iXcgI/9iYUGt8WH9MqDXEcmNChmEYrRCf2SHWeYgQx3x0tLNRIeKQLTtEFyJEep4NTuhk8BC+yMrwEE3+iozo42d8gK7FAOkMsRiiN8QhW2ttSK5QTfRRV4QoymVeJMvPvDp7gCZigD613MN6yRFA3SWarow9QB9LCfG+NeF9qCtjAKOSQjCqVKhfVsiHEQ+grgx/lRGqUihAc1uL8EFD+KCRO+GrF4J61phcoRoPoEzkYhZYpykh5sMb7kOdIeY+jHKur4QI4Feh4AFX1nVeLxrAvQchGsBz5ls6wa2QdwcvIcE2863bTH79KOvsz/uUYJsp+J0pSzNlDckVqqVGUAF+n6uS7txcOl6wot4JVy70ufDLy4pWLUQVPE81pRI0mGe9oxLMHSeohHvMs/STUNaUK6vDPCvOyxMFDx4achehRDJmHnydnkPww5OFfLxrGIZBFDyYl4LpMzlTQFIP6AQx86w2UeYBccFpJrcKv5L9eGDtUAU6RIELqsB74uynjy/UBRF1gS5BTFxwQT1wTiXoUg9MH7m/3NZRRoi5IJytUbMgzv4Wc832+oQkiKgEehmyMkkpKsFkQV11QsRJL5rJYBLItQgRaUZEmnoZXsomz3vGiWw+I9KMF9SVFOqZEemZekli1jN3U/UOqhHHvC6oWWGElhfSpGdOk6+O9prdwvtLj5BjRsQxdRnot+Zeifpy/2/0stktKTRNLmbk0mwXyl8253fyojj+8rxOHNAhjjm5n0/5OOCGOKBzkrMO0Z75lvSAzKlrF32Z/3z8BqLAn+yMV7VhAAAAAElFTkSuQmCC";
-
-let image = atob(dataURI);
-const IMAGE_ARRAYBUFFER = Uint8Array.from(image, byte => byte.charCodeAt(0)).buffer;
-
-add_task(function* test_contentscript() {
- function background() {
- // TODO: Use the Tabs API to obtain the tab ids for showing pageActions.
- let tabId = 1;
- let onClickedListenerEnabled = false;
-
- browser.test.onMessage.addListener((msg, details) => {
- if (msg === "page-action-show") {
- // TODO: switch to using .show(tabId).then(...) once bug 1270742 lands.
- browser.pageAction.show(tabId).then(() => {
- browser.test.sendMessage("page-action-shown");
- });
- } else if (msg == "page-action-set-popup") {
- browser.pageAction.setPopup({popup: details.name, tabId: tabId}).then(() => {
- browser.test.sendMessage("page-action-popup-set");
- });
- } else if (msg == "page-action-get-popup") {
- browser.pageAction.getPopup({tabId: tabId}).then(url => {
- browser.test.sendMessage("page-action-got-popup", url);
- });
- } else if (msg == "page-action-enable-onClicked-listener") {
- onClickedListenerEnabled = true;
- browser.test.sendMessage("page-action-onClicked-listener-enabled");
- } else if (msg == "page-action-disable-onClicked-listener") {
- onClickedListenerEnabled = false;
- browser.test.sendMessage("page-action-onClicked-listener-disabled");
- }
- });
-
- browser.pageAction.onClicked.addListener(tab => {
- browser.test.assertTrue(onClickedListenerEnabled, "The onClicked listener should only fire when it is enabled.");
- browser.test.sendMessage("page-action-onClicked-fired");
- });
-
- let extensionInfo = {
- // Extract the assigned uuid from the background page url.
- uuid: `{${window.location.hostname}}`,
- };
-
- browser.test.sendMessage("ready", extensionInfo);
- }
-
- function popupScript() {
- window.onload = () => {
- browser.test.sendMessage("page-action-from-popup", location.href);
- };
- browser.test.onMessage.addListener((msg, details) => {
- if (msg == "page-action-close-popup") {
- if (details.location == location.href) {
- window.close();
- }
- }
- });
- }
-
- let extension = ExtensionTestUtils.loadExtension({
- background,
- manifest: {
- "name": "PageAction Extension",
- "page_action": {
- "default_title": "Page Action",
- "default_popup": "default.html",
- "default_icon": {
- "18": "extension.png",
- },
- },
- },
- files: {
- "default.html": `<html><head><meta charset="utf-8"><script src="popup.js"><\/script></head></html>`,
- "extension.png": IMAGE_ARRAYBUFFER,
- "a.html": `<html><head><meta charset="utf-8"><script src="popup.js"><\/script></head></html>`,
- "b.html": `<html><head><meta charset="utf-8"><script src="popup.js"><\/script></head></html>`,
- "popup.js": popupScript,
- },
- });
-
- let tabClosedPromise = () => {
- return new Promise(resolve => {
- let chromeWin = Services.wm.getMostRecentWindow("navigator:browser");
- let BrowserApp = chromeWin.BrowserApp;
-
- let tabCloseListener = (event) => {
- BrowserApp.deck.removeEventListener("TabClose", tabCloseListener, false);
- let browser = event.target;
- let url = browser.currentURI.spec;
- resolve(url);
- };
-
- BrowserApp.deck.addEventListener("TabClose", tabCloseListener, false);
- });
- };
-
- function* testPopup(name, uuid) {
- // We don't need to set the popup when testing default_popup.
- if (name != "default.html") {
- extension.sendMessage("page-action-set-popup", {name});
- yield extension.awaitMessage("page-action-popup-set");
- }
-
- extension.sendMessage("page-action-get-popup");
- let url = yield extension.awaitMessage("page-action-got-popup");
-
- if (name == "") {
- ok(url == name, "Calling pageAction.getPopup should return an empty string when the popup is not set.");
-
- // The onClicked listener should get called when the popup is set to an empty string.
- extension.sendMessage("page-action-enable-onClicked-listener");
- yield extension.awaitMessage("page-action-onClicked-listener-enabled");
-
- clickPageAction(uuid);
- yield extension.awaitMessage("page-action-onClicked-fired");
-
- extension.sendMessage("page-action-disable-onClicked-listener");
- yield extension.awaitMessage("page-action-onClicked-listener-disabled");
- } else {
- ok(url.includes(name), "Calling pageAction.getPopup should return the correct popup URL when the popup is set.");
-
- clickPageAction(uuid);
- let location = yield extension.awaitMessage("page-action-from-popup");
- ok(location.includes(name), "The popup with the correct URL should be shown.");
-
- extension.sendMessage("page-action-close-popup", {location});
-
- url = yield tabClosedPromise();
- ok(url.includes(name), "The tab for the popup should be closed.");
- }
- }
-
- yield extension.startup();
- let {uuid} = yield extension.awaitMessage("ready");
-
- extension.sendMessage("page-action-show");
- yield extension.awaitMessage("page-action-shown");
- ok(isPageActionShown(uuid), "The PageAction should be shown.");
-
- yield testPopup("default.html", uuid);
- yield testPopup("a.html", uuid);
- yield testPopup("", uuid);
- yield testPopup("b.html", uuid);
-
- yield extension.unload();
- ok(!isPageActionShown(uuid), "The PageAction should be removed after unload.");
-});
-</script>
-
-</body>
-</html>
diff --git a/mobile/android/components/moz.build b/mobile/android/components/moz.build
deleted file mode 100644
index 9e6683662..000000000
--- a/mobile/android/components/moz.build
+++ /dev/null
@@ -1,47 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-XPIDL_SOURCES += [
- 'SessionStore.idl',
-]
-
-XPIDL_MODULE = 'MobileComponents'
-
-EXTRA_COMPONENTS += [
- 'AboutRedirector.js',
- 'AddonUpdateService.js',
- 'BlocklistPrompt.js',
- 'BrowserCLH.js',
- 'ColorPicker.js',
- 'ContentDispatchChooser.js',
- 'ContentPermissionPrompt.js',
- 'DirectoryProvider.js',
- 'FilePicker.js',
- 'HelperAppDialog.js',
- 'ImageBlockingPolicy.js',
- 'LoginManagerPrompter.js',
- 'NSSDialogService.js',
- 'PersistentNotificationHandler.js',
- 'PresentationDevicePrompt.js',
- 'PresentationRequestUIGlue.js',
- 'PromptService.js',
- 'SessionStore.js',
- 'SiteSpecificUserAgent.js',
- 'Snippets.js',
- 'TabSource.js',
- 'XPIDialogService.js',
-]
-
-# Keep it this way if at all possible. If you need preprocessing,
-# consider adding fields to AppConstants.jsm.
-EXTRA_PP_COMPONENTS += [
- 'MobileComponents.manifest',
-]
-
-DIRS += [
- 'extensions',
- 'build',
-]