1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/mobile/android/chrome/content/WebappRT.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,222 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +let Cc = Components.classes; 1.8 +let Ci = Components.interfaces; 1.9 +let Cu = Components.utils; 1.10 + 1.11 +Cu.import("resource://gre/modules/Services.jsm"); 1.12 +Cu.import("resource://gre/modules/FileUtils.jsm"); 1.13 +Cu.import("resource://gre/modules/NetUtil.jsm"); 1.14 +Cu.import("resource://gre/modules/PermissionsInstaller.jsm"); 1.15 +Cu.import("resource://gre/modules/PermissionPromptHelper.jsm"); 1.16 +Cu.import("resource://gre/modules/ContactService.jsm"); 1.17 +#ifdef MOZ_ANDROID_SYNTHAPKS 1.18 +Cu.import("resource://gre/modules/AppsUtils.jsm"); 1.19 + 1.20 +XPCOMUtils.defineLazyModuleGetter(this, "Notifications", "resource://gre/modules/Notifications.jsm"); 1.21 +#endif 1.22 + 1.23 +function pref(name, value) { 1.24 + return { 1.25 + name: name, 1.26 + value: value 1.27 + } 1.28 +} 1.29 + 1.30 +let WebappRT = { 1.31 + DEFAULT_PREFS_FILENAME: "default-prefs.js", 1.32 + 1.33 + prefs: [ 1.34 + // Disable all add-on locations other than the profile (which can't be disabled this way) 1.35 + pref("extensions.enabledScopes", 1), 1.36 + // Auto-disable any add-ons that are "dropped in" to the profile 1.37 + pref("extensions.autoDisableScopes", 1), 1.38 + // Disable add-on installation via the web-exposed APIs 1.39 + pref("xpinstall.enabled", false), 1.40 + // Set a future policy version to avoid the telemetry prompt. 1.41 + pref("toolkit.telemetry.prompted", 999), 1.42 + pref("toolkit.telemetry.notifiedOptOut", 999), 1.43 + pref("media.useAudioChannelService", true), 1.44 + pref("dom.mozTCPSocket.enabled", true), 1.45 + // Don't check for updates in webapp processes to avoid duplicate notifications. 1.46 + pref("browser.webapps.checkForUpdates", 0), 1.47 + ], 1.48 + 1.49 + init: function(aStatus, aUrl, aCallback) { 1.50 + this.deck = document.getElementById("browsers"); 1.51 + this.deck.addEventListener("click", this, false, true); 1.52 + 1.53 + // on first run, update any prefs 1.54 + if (aStatus == "new") { 1.55 + this.getDefaultPrefs().forEach(this.addPref); 1.56 + 1.57 + // update the blocklist url to use a different app id 1.58 + let blocklist = Services.prefs.getCharPref("extensions.blocklist.url"); 1.59 + blocklist = blocklist.replace(/%APP_ID%/g, "webapprt-mobile@mozilla.org"); 1.60 + Services.prefs.setCharPref("extensions.blocklist.url", blocklist); 1.61 + } 1.62 + 1.63 + // On firstrun, set permissions to their default values. 1.64 + // When the webapp runtime is updated, update the permissions. 1.65 + if (aStatus == "new" || aStatus == "upgrade") { 1.66 + this.getManifestFor(aUrl, function (aManifest, aApp) { 1.67 + if (aManifest) { 1.68 + PermissionsInstaller.installPermissions(aApp, true); 1.69 + } 1.70 + }); 1.71 + } 1.72 + 1.73 +#ifdef MOZ_ANDROID_SYNTHAPKS 1.74 + // If the app is in debug mode, configure and enable the remote debugger. 1.75 + sendMessageToJava({ type: "NativeApp:IsDebuggable" }, (response) => { 1.76 + if (response.isDebuggable) { 1.77 + this._enableRemoteDebugger(aUrl); 1.78 + } 1.79 + }); 1.80 +#endif 1.81 + 1.82 + this.findManifestUrlFor(aUrl, aCallback); 1.83 + }, 1.84 + 1.85 + getManifestFor: function (aUrl, aCallback) { 1.86 + DOMApplicationRegistry.registryReady.then(() => { 1.87 + let request = navigator.mozApps.mgmt.getAll(); 1.88 + request.onsuccess = function() { 1.89 + let apps = request.result; 1.90 + for (let i = 0; i < apps.length; i++) { 1.91 + let app = apps[i]; 1.92 + let manifest = new ManifestHelper(app.manifest, app.origin); 1.93 + 1.94 + // if this is a path to the manifest, or the launch path, then we have a hit. 1.95 + if (app.manifestURL == aUrl || manifest.fullLaunchPath() == aUrl) { 1.96 + aCallback(manifest, app); 1.97 + return; 1.98 + } 1.99 + } 1.100 + 1.101 + // Otherwise, once we loop through all of them, we have a miss. 1.102 + aCallback(undefined); 1.103 + }; 1.104 + 1.105 + request.onerror = function() { 1.106 + // Treat an error like a miss. We can't find the manifest. 1.107 + aCallback(undefined); 1.108 + }; 1.109 + }); 1.110 + }, 1.111 + 1.112 + findManifestUrlFor: function(aUrl, aCallback) { 1.113 + this.getManifestFor(aUrl, function(aManifest, aApp) { 1.114 + if (!aManifest) { 1.115 + // we can't find the manifest, so open it like a web page 1.116 + aCallback(aUrl); 1.117 + return; 1.118 + } 1.119 + 1.120 + BrowserApp.manifest = aManifest; 1.121 + BrowserApp.manifestUrl = aApp.manifestURL; 1.122 + 1.123 + aCallback(aManifest.fullLaunchPath()); 1.124 + }); 1.125 + }, 1.126 + 1.127 + getDefaultPrefs: function() { 1.128 + // read default prefs from the disk 1.129 + try { 1.130 + let defaultPrefs = []; 1.131 + try { 1.132 + defaultPrefs = this.readDefaultPrefs(FileUtils.getFile("ProfD", [this.DEFAULT_PREFS_FILENAME])); 1.133 + } catch(ex) { 1.134 + // this can throw if the defaultprefs.js file doesn't exist 1.135 + } 1.136 + for (let i = 0; i < defaultPrefs.length; i++) { 1.137 + this.prefs.push(defaultPrefs[i]); 1.138 + } 1.139 + } catch(ex) { 1.140 + console.log("Error reading defaultPrefs file: " + ex); 1.141 + } 1.142 + return this.prefs; 1.143 + }, 1.144 + 1.145 + readDefaultPrefs: function webapps_readDefaultPrefs(aFile) { 1.146 + let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream); 1.147 + fstream.init(aFile, -1, 0, 0); 1.148 + let prefsString = NetUtil.readInputStreamToString(fstream, fstream.available(), {}); 1.149 + return JSON.parse(prefsString); 1.150 + }, 1.151 + 1.152 + addPref: function(aPref) { 1.153 + switch (typeof aPref.value) { 1.154 + case "string": 1.155 + Services.prefs.setCharPref(aPref.name, aPref.value); 1.156 + break; 1.157 + case "boolean": 1.158 + Services.prefs.setBoolPref(aPref.name, aPref.value); 1.159 + break; 1.160 + case "number": 1.161 + Services.prefs.setIntPref(aPref.name, aPref.value); 1.162 + break; 1.163 + } 1.164 + }, 1.165 + 1.166 +#ifdef MOZ_ANDROID_SYNTHAPKS 1.167 + _enableRemoteDebugger: function(aUrl) { 1.168 + // Skip the connection prompt in favor of notifying the user below. 1.169 + Services.prefs.setBoolPref("devtools.debugger.prompt-connection", false); 1.170 + 1.171 + // Automagically find a free port and configure the debugger to use it. 1.172 + let serv = Cc['@mozilla.org/network/server-socket;1'].createInstance(Ci.nsIServerSocket); 1.173 + serv.init(-1, true, -1); 1.174 + let port = serv.port; 1.175 + serv.close(); 1.176 + Services.prefs.setIntPref("devtools.debugger.remote-port", port); 1.177 + 1.178 + Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true); 1.179 + 1.180 + // Notify the user that we enabled the debugger and which port it's using 1.181 + // so they can use the DevTools Connect… dialog to connect the client to it. 1.182 + DOMApplicationRegistry.registryReady.then(() => { 1.183 + let name; 1.184 + let app = DOMApplicationRegistry.getAppByManifestURL(aUrl); 1.185 + if (app) { 1.186 + name = app.name; 1.187 + } else { 1.188 + name = Strings.browser.GetStringFromName("remoteNotificationGenericName"); 1.189 + } 1.190 + 1.191 + Notifications.create({ 1.192 + title: Strings.browser.formatStringFromName("remoteNotificationTitle", [name], 1), 1.193 + message: Strings.browser.formatStringFromName("remoteNotificationMessage", [port], 1), 1.194 + icon: "drawable://warning_doorhanger", 1.195 + }); 1.196 + }); 1.197 + }, 1.198 +#endif 1.199 + 1.200 + handleEvent: function(event) { 1.201 + let target = event.target; 1.202 + 1.203 + // walk up the tree to find the nearest link tag 1.204 + while (target && !(target instanceof HTMLAnchorElement)) { 1.205 + target = target.parentNode; 1.206 + } 1.207 + 1.208 + if (!target || target.getAttribute("target") != "_blank") { 1.209 + return; 1.210 + } 1.211 + 1.212 + let uri = Services.io.newURI(target.href, target.ownerDocument.characterSet, null); 1.213 + 1.214 + // Direct the URL to the browser. 1.215 + Cc["@mozilla.org/uriloader/external-protocol-service;1"]. 1.216 + getService(Ci.nsIExternalProtocolService). 1.217 + getProtocolHandlerInfo(uri.scheme). 1.218 + launchWithURI(uri); 1.219 + 1.220 + // Prevent the runtime from loading the URL. We do this after directing it 1.221 + // to the browser to give the runtime a shot at handling the URL if we fail 1.222 + // to direct it to the browser for some reason. 1.223 + event.preventDefault(); 1.224 + } 1.225 +}