/* 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 PermissionsInstaller */ var Cc = Components.classes; var Ci = Components.interfaces; var Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/FileUtils.jsm"); Cu.import("resource://gre/modules/NetUtil.jsm"); Cu.import("resource://gre/modules/PermissionsInstaller.jsm"); Cu.import("resource://gre/modules/ContactService.jsm"); Cu.import("resource://gre/modules/AppsUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm"); function pref(name, value) { return { name: name, value: value } } var WebappRT = { prefs: [ // Disable all add-on locations other than the profile (which can't be disabled this way) pref("extensions.enabledScopes", 1), // Auto-disable any add-ons that are "dropped in" to the profile pref("extensions.autoDisableScopes", 1), // Disable add-on installation via the web-exposed APIs pref("xpinstall.enabled", false), // Set a future policy version to avoid the telemetry prompt. pref("toolkit.telemetry.prompted", 999), pref("toolkit.telemetry.notifiedOptOut", 999), pref("media.useAudioChannelAPI", true), pref("dom.mozTCPSocket.enabled", true), // Enabled system messages for web activity support pref("dom.sysmsg.enabled", true), ], init: function(aStatus, aUrl, aCallback) { this.deck = document.getElementById("browsers"); this.deck.addEventListener("click", this, false, true); // on first run, update any prefs if (aStatus == "new") { this.prefs.forEach(this.addPref); // update the blocklist url to use a different app id let blocklist = Services.prefs.getCharPref("extensions.blocklist.url"); blocklist = blocklist.replace(/%APP_ID%/g, "webapprt-mobile@mozilla.org"); Services.prefs.setCharPref("extensions.blocklist.url", blocklist); } // On firstrun, set permissions to their default values. // When the webapp runtime is updated, update the permissions. if (aStatus == "new" || aStatus == "upgrade") { this.getManifestFor(aUrl, function (aManifest, aApp) { if (aManifest) { PermissionsInstaller.installPermissions(aApp, true); } }); } // If the app is in debug mode, configure and enable the remote debugger. Messaging.sendRequestForResult({ type: "NativeApp:IsDebuggable" }).then((response) => { let that = this; let name = this._getAppName(aUrl); if (response.isDebuggable) { Notifications.create({ title: Strings.browser.formatStringFromName("remoteStartNotificationTitle", [name], 1), message: Strings.browser.GetStringFromName("remoteStartNotificationMessage"), icon: "drawable://warning_doorhanger", onClick: function(aId, aCookie) { that._enableRemoteDebugger(aUrl); }, }); } }); this.findManifestUrlFor(aUrl, (function(aLaunchUrl) { if (aStatus == "new") { if (BrowserApp.manifest && BrowserApp.manifest.orientation) { let orientation = BrowserApp.manifest.orientation; if (Array.isArray(orientation)) { orientation = orientation.join(","); } this.addPref(pref("app.orientation.default", orientation)); } } aCallback(aLaunchUrl); }).bind(this)); }, getManifestFor: function (aUrl, aCallback) { let request = navigator.mozApps.mgmt.getAll(); request.onsuccess = function() { let apps = request.result; for (let i = 0; i < apps.length; i++) { let app = apps[i]; let manifest = new ManifestHelper(app.manifest, app.origin, app.manifestURL); // if this is a path to the manifest, or the launch path, then we have a hit. if (app.manifestURL == aUrl || manifest.fullLaunchPath() == aUrl) { aCallback(manifest, app); return; } } // Otherwise, once we loop through all of them, we have a miss. aCallback(undefined); }; request.onerror = function() { // Treat an error like a miss. We can't find the manifest. aCallback(undefined); }; }, findManifestUrlFor: function(aUrl, aCallback) { this.getManifestFor(aUrl, function(aManifest, aApp) { if (!aManifest) { // we can't find the manifest, so open it like a web page aCallback(aUrl); return; } BrowserApp.manifest = aManifest; BrowserApp.manifestUrl = aApp.manifestURL; aCallback(aManifest.fullLaunchPath()); }); }, addPref: function(aPref) { switch (typeof aPref.value) { case "string": Services.prefs.setCharPref(aPref.name, aPref.value); break; case "boolean": Services.prefs.setBoolPref(aPref.name, aPref.value); break; case "number": Services.prefs.setIntPref(aPref.name, aPref.value); break; } }, _getAppName: function(aUrl) { let name = Strings.browser.GetStringFromName("remoteNotificationGenericName"); let app = DOMApplicationRegistry.getAppByManifestURL(aUrl); if (app) { name = app.name; } return name; }, _enableRemoteDebugger: function(aUrl) { // Skip the connection prompt in favor of notifying the user below. Services.prefs.setBoolPref("devtools.debugger.prompt-connection", false); // Automagically find a free port and configure the debugger to use it. let serv = Cc['@mozilla.org/network/server-socket;1'].createInstance(Ci.nsIServerSocket); serv.init(-1, true, -1); let port = serv.port; serv.close(); Services.prefs.setIntPref("devtools.debugger.remote-port", port); // Clear the UNIX domain socket path to ensure a TCP socket will be used // instead. Services.prefs.setCharPref("devtools.debugger.unix-domain-socket", ""); Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true); // Notify the user that we enabled the debugger and which port it's using // so they can use the DevTools Connect… dialog to connect the client to it. DOMApplicationRegistry.registryReady.then(() => { let name = this._getAppName(aUrl); Notifications.create({ title: Strings.browser.formatStringFromName("remoteNotificationTitle", [name], 1), message: Strings.browser.formatStringFromName("remoteNotificationMessage", [port], 1), icon: "drawable://warning_doorhanger", }); }); }, handleEvent: function(event) { let target = event.target; // walk up the tree to find the nearest link tag while (target && !(target instanceof HTMLAnchorElement)) { target = target.parentNode; } if (!target || target.getAttribute("target") != "_blank") { return; } let uri = Services.io.newURI(target.href, target.ownerDocument.characterSet, null); // Direct the URL to the browser. Cc["@mozilla.org/uriloader/external-protocol-service;1"]. getService(Ci.nsIExternalProtocolService). getProtocolHandlerInfo(uri.scheme). launchWithURI(uri); // Prevent the runtime from loading the URL. We do this after directing it // to the browser to give the runtime a shot at handling the URL if we fail // to direct it to the browser for some reason. event.preventDefault(); } }